Add Socket Libraries.
Add Posix functions for porting compatibility. Fix compliance issues with ISO/IEC 9899:199409 New Functions: setenv(), fparseln(), GetFileNameFromPath(), rename(), realpath(), setprogname(), getprogname(), strlcat(), strlcpy(), strsep(), setitimer(), getitimer(), timegm(), getopt(), basename(), mkstemp(), ffs(), vsnprintf(), snprintf(), getpass(), usleep(), select(), writev(), strcasecmp(), getcwd(), chdir(), tcgetpgrp(), getpgrp(), gettimeofday(), bcopy(), git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12061 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -45,6 +45,12 @@ static const int stdioFlags[NUM_SPECIAL] = {
|
||||
static DeviceNode *ConNode[NUM_SPECIAL];
|
||||
static ConInstance *ConInstanceList;
|
||||
|
||||
static wchar_t *ConReadBuf;
|
||||
|
||||
/* Flags settable by Ioctl */
|
||||
static BOOLEAN TtyCooked;
|
||||
static BOOLEAN TtyEcho;
|
||||
|
||||
ssize_t
|
||||
WideTtyCvt( CHAR16 *dest, const char *buf, size_t n)
|
||||
{
|
||||
@@ -127,74 +133,6 @@ da_ConSeek(
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
ssize_t
|
||||
EFIAPI
|
||||
da_ConRead(
|
||||
IN OUT struct __filedes *filp,
|
||||
IN OUT off_t *offset, // Console ignores this
|
||||
IN size_t BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;
|
||||
ConInstance *Stream;
|
||||
CHAR16 *OutPtr;
|
||||
EFI_INPUT_KEY Key;
|
||||
UINTN NumChar;
|
||||
UINTN Edex;
|
||||
EFI_STATUS Status = RETURN_SUCCESS;
|
||||
UINTN i;
|
||||
|
||||
Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
|
||||
// Quick check to see if Stream looks reasonable
|
||||
if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'
|
||||
EFIerrno = RETURN_INVALID_PARAMETER;
|
||||
return -1; // Looks like a bad This pointer
|
||||
}
|
||||
if(Stream->InstanceNum != STDIN_FILENO) {
|
||||
// Read only valid for stdin
|
||||
EFIerrno = RETURN_UNSUPPORTED;
|
||||
return -1;
|
||||
}
|
||||
// It looks like things are OK for trying to read
|
||||
// We will accumulate *BufferSize characters or until we encounter
|
||||
// an "activation" character. Currently any control character.
|
||||
Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
|
||||
OutPtr = Buffer;
|
||||
NumChar = (BufferSize - 1) / sizeof(CHAR16);
|
||||
i = 0;
|
||||
do {
|
||||
if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {
|
||||
Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);
|
||||
if(Status != RETURN_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
Status = Proto->ReadKeyStroke(Proto, &Key);
|
||||
if(Status != RETURN_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Key.ScanCode = Stream->UnGetKey.ScanCode;
|
||||
Key.UnicodeChar = Stream->UnGetKey.UnicodeChar;
|
||||
Stream->UnGetKey.ScanCode = SCAN_NULL;
|
||||
Stream->UnGetKey.UnicodeChar = CHAR_NULL;
|
||||
}
|
||||
if(Key.ScanCode == SCAN_NULL) {
|
||||
*OutPtr++ = Key.UnicodeChar;
|
||||
++i;
|
||||
}
|
||||
if(iswcntrl(Key.UnicodeChar)) { // If a control character, or a scan code
|
||||
break;
|
||||
}
|
||||
} while(i < NumChar);
|
||||
|
||||
*OutPtr = L'\0'; // Terminate the input buffer
|
||||
EFIerrno = Status;
|
||||
return (ssize_t)(i * sizeof(CHAR16)); // Will be 0 if we didn't get a key
|
||||
}
|
||||
|
||||
/* Write a NULL terminated WCS to the EFI console.
|
||||
|
||||
@param[in,out] BufferSize Number of bytes in Buffer. Set to zero if
|
||||
@@ -265,6 +203,109 @@ da_ConWrite(
|
||||
return BufferSize;
|
||||
}
|
||||
|
||||
/** Read characters from the console input device.
|
||||
|
||||
@param[in,out] filp Pointer to file descriptor for this file.
|
||||
@param[in,out] offset Ignored.
|
||||
@param[in] BufferSize Buffer size, in bytes.
|
||||
@param[out] Buffer Buffer in which to place the read characters.
|
||||
|
||||
@return Number of bytes actually placed into Buffer.
|
||||
|
||||
@todo Handle encodings other than ASCII-7 and UEFI.
|
||||
**/
|
||||
static
|
||||
ssize_t
|
||||
EFIAPI
|
||||
da_ConRead(
|
||||
IN OUT struct __filedes *filp,
|
||||
IN OUT off_t *offset, // Console ignores this
|
||||
IN size_t BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;
|
||||
ConInstance *Stream;
|
||||
wchar_t *OutPtr;
|
||||
EFI_INPUT_KEY Key;
|
||||
UINTN NumChar;
|
||||
UINTN Edex;
|
||||
EFI_STATUS Status = RETURN_SUCCESS;
|
||||
UINTN i;
|
||||
char EchoBuff[MB_CUR_MAX + 1];
|
||||
int NumEcho;
|
||||
|
||||
Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction);
|
||||
// Quick check to see if Stream looks reasonable
|
||||
if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'
|
||||
EFIerrno = RETURN_INVALID_PARAMETER;
|
||||
return -1; // Looks like a bad This pointer
|
||||
}
|
||||
if(Stream->InstanceNum != STDIN_FILENO) {
|
||||
// Read only valid for stdin
|
||||
EFIerrno = RETURN_UNSUPPORTED;
|
||||
return -1;
|
||||
}
|
||||
// It looks like things are OK for trying to read
|
||||
// We will accumulate *BufferSize characters or until we encounter
|
||||
// an "activation" character. Currently any control character.
|
||||
Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
|
||||
OutPtr = ConReadBuf;
|
||||
NumChar = (BufferSize > MAX_INPUT)? MAX_INPUT : BufferSize;
|
||||
i = 0;
|
||||
do {
|
||||
if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) {
|
||||
Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);
|
||||
if(Status != RETURN_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
Status = Proto->ReadKeyStroke(Proto, &Key);
|
||||
if(Status != RETURN_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Key.ScanCode = Stream->UnGetKey.ScanCode;
|
||||
Key.UnicodeChar = Stream->UnGetKey.UnicodeChar;
|
||||
Stream->UnGetKey.ScanCode = SCAN_NULL;
|
||||
Stream->UnGetKey.UnicodeChar = CHAR_NULL;
|
||||
}
|
||||
if(Key.ScanCode == SCAN_NULL) {
|
||||
NumEcho = 0;
|
||||
if(TtyCooked && (Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {
|
||||
*OutPtr++ = CHAR_LINEFEED;
|
||||
NumEcho = wctomb(EchoBuff, CHAR_LINEFEED);
|
||||
}
|
||||
else {
|
||||
*OutPtr++ = Key.UnicodeChar;
|
||||
NumEcho = wctomb(EchoBuff, Key.UnicodeChar);
|
||||
}
|
||||
++i;
|
||||
EchoBuff[NumEcho] = 0; /* Terminate the Echo buffer */
|
||||
if(TtyEcho) {
|
||||
/* Echo the character just input */
|
||||
da_ConWrite(&gMD->fdarray[STDOUT_FILENO], NULL, 2, EchoBuff);
|
||||
}
|
||||
}
|
||||
if(iswcntrl(Key.UnicodeChar)) { // If a control character, or a scan code
|
||||
break;
|
||||
}
|
||||
} while(i < NumChar);
|
||||
|
||||
*OutPtr = L'\0'; // Terminate the input buffer
|
||||
|
||||
/* Convert the input buffer and place in Buffer.
|
||||
If the fully converted input buffer won't fit, write what will and
|
||||
leave the rest in ConReadBuf with ConReadLeft indicating how many
|
||||
unconverted characters remain in ConReadBuf.
|
||||
*/
|
||||
NumEcho = (int)wcstombs(Buffer, ConReadBuf, BufferSize); /* Re-use NumEcho to hold number of bytes in Buffer */
|
||||
/* More work needs to be done before locales other than C can be supported. */
|
||||
|
||||
EFIerrno = Status;
|
||||
return (ssize_t)NumEcho; // Will be 0 if we didn't get a key
|
||||
}
|
||||
|
||||
/** Console-specific helper function for the fstat() function.
|
||||
|
||||
st_size Set to number of characters read for stdin and number written for stdout and stderr.
|
||||
@@ -347,27 +388,28 @@ da_ConIoctl(
|
||||
int
|
||||
EFIAPI
|
||||
da_ConOpen(
|
||||
DeviceNode *DevNode,
|
||||
struct __filedes *filp,
|
||||
void *DevInstance,
|
||||
int DevInstance, // Not used for console devices
|
||||
wchar_t *Path, // Not used for console devices
|
||||
wchar_t *Flags // Not used for console devices
|
||||
wchar_t *MPath // Not used for console devices
|
||||
)
|
||||
{
|
||||
ConInstance *Stream;
|
||||
|
||||
if((filp == NULL) ||
|
||||
(DevInstance == NULL))
|
||||
(DevNode == NULL))
|
||||
{
|
||||
EFIerrno = RETURN_INVALID_PARAMETER;
|
||||
return -1;
|
||||
}
|
||||
Stream = (ConInstance *)DevInstance;
|
||||
Stream = (ConInstance *)DevNode->InstanceList;
|
||||
// Quick check to see if Stream looks reasonable
|
||||
if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb'
|
||||
EFIerrno = RETURN_INVALID_PARAMETER;
|
||||
return -1; // Looks like a bad This pointer
|
||||
}
|
||||
gMD->StdIo[Stream->InstanceNum] = (ConInstance *)DevInstance;
|
||||
gMD->StdIo[Stream->InstanceNum] = Stream;
|
||||
filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE);
|
||||
filp->f_offset = 0;
|
||||
filp->f_ops = &Stream->Abstraction;
|
||||
@@ -448,7 +490,8 @@ __Cons_construct(
|
||||
int i;
|
||||
|
||||
ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance));
|
||||
if(ConInstanceList == NULL) {
|
||||
ConReadBuf = (wchar_t *)AllocateZeroPool((MAX_INPUT + 1) * sizeof(wchar_t));
|
||||
if((ConInstanceList == NULL) || (ConReadBuf == NULL)) {
|
||||
return RETURN_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
@@ -507,6 +550,10 @@ __Cons_construct(
|
||||
}
|
||||
Stream->Parent = ConNode[i];
|
||||
}
|
||||
/* Initialize Ioctl flags until Ioctl is really implemented. */
|
||||
TtyCooked = TRUE;
|
||||
TtyEcho = TRUE;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
@@ -527,6 +574,9 @@ __Cons_deconstruct(
|
||||
if(ConInstanceList != NULL) {
|
||||
FreePool(ConInstanceList);
|
||||
}
|
||||
if(ConReadBuf != NULL) {
|
||||
FreePool(ConReadBuf);
|
||||
}
|
||||
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <wctype.h>
|
||||
#include <wchar.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/syslimits.h>
|
||||
#include <kfile.h>
|
||||
#include <Device/Device.h>
|
||||
#include <MainData.h>
|
||||
@@ -321,7 +322,7 @@ da_ShellIoctl(
|
||||
void *argp ///< May be a pointer or a value
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/** Open an abstract Shell File.
|
||||
@@ -329,10 +330,11 @@ da_ShellIoctl(
|
||||
int
|
||||
EFIAPI
|
||||
da_ShellOpen(
|
||||
DeviceNode *DevNode,
|
||||
struct __filedes *filp,
|
||||
void *DevInstance,
|
||||
int DevInstance, /* Not used by Shell */
|
||||
wchar_t *Path,
|
||||
wchar_t *Flags
|
||||
wchar_t *MPath
|
||||
)
|
||||
{
|
||||
UINT64 OpenMode;
|
||||
@@ -340,8 +342,10 @@ da_ShellOpen(
|
||||
SHELL_FILE_HANDLE FileHandle;
|
||||
GenericInstance *Gip;
|
||||
char *NPath;
|
||||
wchar_t *WPath;
|
||||
RETURN_STATUS Status;
|
||||
int oflags;
|
||||
int retval;
|
||||
|
||||
EFIerrno = RETURN_SUCCESS;
|
||||
|
||||
@@ -356,6 +360,23 @@ da_ShellOpen(
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Re-create the full mapped path for the shell. */
|
||||
if(MPath != NULL) {
|
||||
WPath = AllocateZeroPool(PATH_MAX * sizeof(wchar_t) + 1);
|
||||
if(WPath == NULL) {
|
||||
errno = ENOMEM;
|
||||
EFIerrno = RETURN_OUT_OF_RESOURCES;
|
||||
return -1;
|
||||
}
|
||||
wcsncpy(WPath, MPath, NAME_MAX); /* Get the Map Name */
|
||||
wcsncat(WPath, Path, (PATH_MAX - NAME_MAX)); /* Append the path */
|
||||
}
|
||||
else {
|
||||
WPath = Path;
|
||||
}
|
||||
|
||||
retval = -1; /* Initially assume failure. */
|
||||
|
||||
/* Do we care if the file already exists?
|
||||
If O_TRUNC, then delete the file. It will be created anew subsequently.
|
||||
If O_EXCL, then error if the file exists and O_CREAT is set.
|
||||
@@ -363,23 +384,24 @@ da_ShellOpen(
|
||||
!!!!!!!!! Change this to use ShellSetFileInfo() to actually truncate the file
|
||||
!!!!!!!!! instead of deleting and re-creating it.
|
||||
*/
|
||||
do { /* Do fake exception handling */
|
||||
if((oflags & O_TRUNC) || ((oflags & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) {
|
||||
Status = ShellIsFile( Path );
|
||||
Status = ShellIsFile( WPath );
|
||||
if(Status == RETURN_SUCCESS) {
|
||||
// The file exists
|
||||
if(oflags & O_TRUNC) {
|
||||
NPath = AllocateZeroPool(1024);
|
||||
NPath = AllocateZeroPool(PATH_MAX);
|
||||
if(NPath == NULL) {
|
||||
errno = ENOMEM;
|
||||
EFIerrno = RETURN_OUT_OF_RESOURCES;
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
wcstombs(NPath, Path, 1024);
|
||||
wcstombs(NPath, WPath, PATH_MAX);
|
||||
// We do a truncate by deleting the existing file and creating a new one.
|
||||
if(unlink(NPath) != 0) {
|
||||
filp->f_iflags = 0; // Release our reservation on this FD
|
||||
FreePool(NPath);
|
||||
return -1; // errno and EFIerrno are already set.
|
||||
break;
|
||||
}
|
||||
FreePool(NPath);
|
||||
}
|
||||
@@ -387,32 +409,40 @@ da_ShellOpen(
|
||||
errno = EEXIST;
|
||||
EFIerrno = RETURN_ACCESS_DENIED;
|
||||
filp->f_iflags = 0; // Release our reservation on this FD
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call the EFI Shell's Open function
|
||||
Status = ShellOpenFileByName( Path, &FileHandle, OpenMode, Attributes);
|
||||
Status = ShellOpenFileByName( WPath, &FileHandle, OpenMode, Attributes);
|
||||
if(RETURN_ERROR(Status)) {
|
||||
filp->f_iflags = 0; // Release our reservation on this FD
|
||||
// Set errno based upon Status
|
||||
errno = EFI2errno(Status);
|
||||
EFIerrno = Status;
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
retval = 0;
|
||||
// Successfully got a regular File
|
||||
filp->f_iflags |= S_IFREG;
|
||||
|
||||
// Update the info in the fd
|
||||
filp->devdata = (void *)FileHandle;
|
||||
|
||||
Gip = (GenericInstance *)DevInstance;
|
||||
Gip = (GenericInstance *)DevNode->InstanceList;
|
||||
filp->f_offset = 0;
|
||||
filp->f_ops = &Gip->Abstraction;
|
||||
// filp->devdata = FileHandle;
|
||||
// filp->devdata = FileHandle;
|
||||
} while(FALSE);
|
||||
|
||||
return 0;
|
||||
/* If we get this far, WPath is not NULL.
|
||||
If MPath is not NULL, then WPath was allocated so we need to free it.
|
||||
*/
|
||||
if(MPath != NULL) {
|
||||
FreePool(WPath);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#include <sys/poll.h>
|
||||
@@ -468,9 +498,10 @@ da_ShellRename(
|
||||
RETURN_STATUS Status;
|
||||
EFI_FILE_INFO *NewFileInfo;
|
||||
EFI_FILE_INFO *OldFileInfo;
|
||||
char *NewFn;
|
||||
wchar_t *NewFn;
|
||||
int OldFd;
|
||||
SHELL_FILE_HANDLE FileHandle;
|
||||
wchar_t *NormalizedPath;
|
||||
|
||||
// Open old file
|
||||
OldFd = open(from, O_RDWR, 0);
|
||||
@@ -482,22 +513,20 @@ da_ShellRename(
|
||||
OldFileInfo = ShellGetFileInfo( FileHandle);
|
||||
if(OldFileInfo != NULL) {
|
||||
// Copy the Old file info into our new buffer, and free the old.
|
||||
memcpy(OldFileInfo, NewFileInfo, sizeof(EFI_FILE_INFO));
|
||||
memcpy(NewFileInfo, OldFileInfo, sizeof(EFI_FILE_INFO));
|
||||
FreePool(OldFileInfo);
|
||||
// Normalize path and convert to WCS.
|
||||
NormalizedPath = NormalizePath(to);
|
||||
if (NormalizedPath != NULL) {
|
||||
// Strip off all but the file name portion of new
|
||||
NewFn = strrchr(to, '/');
|
||||
if(NewFn == NULL) {
|
||||
NewFn = strrchr(to, '\\');
|
||||
if(NewFn == NULL) {
|
||||
NewFn = (char *)to;
|
||||
}
|
||||
}
|
||||
// Convert new name from MBCS to WCS
|
||||
(void)AsciiStrToUnicodeStr( NewFn, gMD->UString);
|
||||
NewFn = GetFileNameFromPath(NormalizedPath);
|
||||
// Copy the new file name into our new file info buffer
|
||||
wcsncpy(NewFileInfo->FileName, gMD->UString, wcslen(gMD->UString)+1);
|
||||
wcsncpy(NewFileInfo->FileName, NewFn, wcslen(NewFn) + 1);
|
||||
// Update the size of the structure.
|
||||
NewFileInfo->Size = sizeof(EFI_FILE_INFO) + StrSize(NewFn);
|
||||
// Apply the new file name
|
||||
Status = ShellSetFileInfo(FileHandle, NewFileInfo);
|
||||
free(NormalizedPath);
|
||||
free(NewFileInfo);
|
||||
if(Status == EFI_SUCCESS) {
|
||||
// File has been successfully renamed. We are DONE!
|
||||
@@ -507,6 +536,12 @@ da_ShellRename(
|
||||
EFIerrno = Status;
|
||||
}
|
||||
else {
|
||||
free(NewFileInfo);
|
||||
errno = ENOMEM;
|
||||
}
|
||||
}
|
||||
else {
|
||||
free(NewFileInfo);
|
||||
errno = EIO;
|
||||
}
|
||||
}
|
||||
@@ -619,7 +654,7 @@ __ctor_DevShell(
|
||||
Stream->Abstraction.fo_poll = &da_ShellPoll;
|
||||
Stream->Abstraction.fo_flush = &fnullop_flush;
|
||||
Stream->Abstraction.fo_stat = &da_ShellStat;
|
||||
Stream->Abstraction.fo_ioctl = &fbadop_ioctl;
|
||||
Stream->Abstraction.fo_ioctl = &da_ShellIoctl;
|
||||
Stream->Abstraction.fo_delete = &da_ShellDelete;
|
||||
Stream->Abstraction.fo_rmdir = &da_ShellRmdir;
|
||||
Stream->Abstraction.fo_mkdir = &da_ShellMkdir;
|
||||
|
@@ -31,33 +31,33 @@ DeviceNode *daCurrentDevice = NULL; ///< Device currently being accessed
|
||||
fnullop_* Does nothing and returns success.
|
||||
fbadop_* Does nothing and returns EPERM
|
||||
*/
|
||||
int fnullop_fcntl (struct __filedes *filp, UINT32 Cmd, void *p3, void *p4)
|
||||
int EFIAPI fnullop_fcntl (struct __filedes *filp, UINT32 Cmd, void *p3, void *p4)
|
||||
{ return 0; }
|
||||
|
||||
short fnullop_poll (struct __filedes *filp, short Events)
|
||||
short EFIAPI fnullop_poll (struct __filedes *filp, short Events)
|
||||
{
|
||||
return ((POLLIN | POLLRDNORM | POLLOUT) & Events);
|
||||
}
|
||||
|
||||
int fnullop_flush (struct __filedes *filp)
|
||||
int EFIAPI fnullop_flush (struct __filedes *filp)
|
||||
{ return 0; }
|
||||
|
||||
int fbadop_stat (struct __filedes *filp, struct stat *StatBuf, void *Buf)
|
||||
int EFIAPI fbadop_stat (struct __filedes *filp, struct stat *StatBuf, void *Buf)
|
||||
{ return -EPERM; }
|
||||
|
||||
int fbadop_ioctl (struct __filedes *filp, ULONGN Cmd, void *argp)
|
||||
int EFIAPI fbadop_ioctl (struct __filedes *filp, ULONGN Cmd, void *argp)
|
||||
{ return -EPERM; }
|
||||
|
||||
int fbadop_delete (struct __filedes *filp)
|
||||
int EFIAPI fbadop_delete (struct __filedes *filp)
|
||||
{ return -EPERM; }
|
||||
|
||||
int fbadop_mkdir (const char *path, __mode_t perms)
|
||||
int EFIAPI fbadop_mkdir (const char *path, __mode_t perms)
|
||||
{ return -EPERM; }
|
||||
|
||||
int fbadop_rename (const char *from, const char *to)
|
||||
int EFIAPI fbadop_rename (const char *from, const char *to)
|
||||
{ return -EPERM; }
|
||||
|
||||
int fbadop_rmdir (struct __filedes *filp)
|
||||
int EFIAPI fbadop_rmdir (struct __filedes *filp)
|
||||
{ return -EPERM; }
|
||||
|
||||
/** Add a new device to the device list.
|
||||
|
@@ -248,10 +248,16 @@ PathAlias(
|
||||
|
||||
/** Parse a path producing the target device, device instance, and file path.
|
||||
|
||||
It is the caller's responsibility to free() FullPath and MapPath when they
|
||||
are no longer needed.
|
||||
|
||||
@param[in] path
|
||||
@param[out] FullPath
|
||||
@param[out] DevNode
|
||||
@param[out] Which
|
||||
@param[out] MapPath OPTIONAL. If not NULL, it points to the place to save a pointer
|
||||
to the extracted map name. If the path didn't have a map name,
|
||||
then *MapPath is set to NULL.
|
||||
|
||||
@retval RETURN_SUCCESS The path was parsed successfully.
|
||||
@retval RETURN_NOT_FOUND The path does not map to a valid device.
|
||||
@@ -266,7 +272,8 @@ ParsePath(
|
||||
IN const char *path,
|
||||
OUT wchar_t **FullPath,
|
||||
OUT DeviceNode **DevNode,
|
||||
OUT int *Which
|
||||
OUT int *Which,
|
||||
OUT wchar_t **MapPath
|
||||
)
|
||||
{
|
||||
int MapLen;
|
||||
@@ -301,7 +308,7 @@ reclassify:
|
||||
// Get the Map Name, including the trailing ':'. */
|
||||
MPath = calloc(MapLen+2, sizeof(wchar_t));
|
||||
if(MPath != NULL) {
|
||||
wmemcpy(MPath, WPath, MapLen+2);
|
||||
wmemcpy(MPath, WPath, MapLen+1);
|
||||
}
|
||||
else {
|
||||
errno = ENOMEM;
|
||||
@@ -346,6 +353,12 @@ reclassify:
|
||||
if(!RETURN_ERROR(Status)) {
|
||||
*FullPath = WPath;
|
||||
*Which = Instance;
|
||||
if(MapPath != NULL) {
|
||||
*MapPath = MPath;
|
||||
}
|
||||
else if(MPath != NULL) {
|
||||
free(MPath); /* Caller doesn't want it so let MPath go free */
|
||||
}
|
||||
|
||||
/* At this point, WPath is an absolute path,
|
||||
MPath is either NULL or points to the Map Name,
|
||||
@@ -359,6 +372,9 @@ reclassify:
|
||||
if(Node != NULL) {
|
||||
Status = RETURN_SUCCESS;
|
||||
}
|
||||
else {
|
||||
Status = RETURN_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* This is a mapped path. */
|
||||
@@ -375,8 +391,41 @@ reclassify:
|
||||
*DevNode = Node;
|
||||
}
|
||||
}
|
||||
if(MPath != NULL) {
|
||||
free(MPath); // We don't need this any more.
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Parses a normalized wide character path and returns a pointer to the entry
|
||||
following the last \. If a \ is not found in the path the return value will
|
||||
be the same as the input value. All error conditions return NULL.
|
||||
|
||||
The behavior when passing in a path that has not been normalized is undefined.
|
||||
|
||||
@param Path - A pointer to a wide character string containing a path to a
|
||||
directory or a file.
|
||||
|
||||
@return Pointer to the file name or terminal directory. NULL if an error is
|
||||
detected.
|
||||
**/
|
||||
wchar_t *
|
||||
EFIAPI
|
||||
GetFileNameFromPath (
|
||||
const wchar_t *Path
|
||||
)
|
||||
{
|
||||
wchar_t *Tail;
|
||||
|
||||
if (Path == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Tail = wcsrchr(Path, L'\\');
|
||||
if(Tail == NULL) {
|
||||
Tail = (wchar_t *) Path;
|
||||
} else {
|
||||
// Move to the next character after the '\\' to get the file name.
|
||||
Tail++;
|
||||
}
|
||||
|
||||
return Tail;
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = DevConsole
|
||||
FILE_GUID = 42c078ef-14a8-4e30-9329-6f12d796e54a
|
||||
FILE_GUID = f6937495-1f44-4a8a-8a1b-5a669f9396f6
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = DevConsole
|
||||
@@ -49,15 +49,3 @@
|
||||
[Protocols]
|
||||
gEfiSimpleTextInProtocolGuid
|
||||
gEfiSimpleTextOutProtocolGuid
|
||||
|
||||
################################################################
|
||||
#
|
||||
# The Build Options, below, are only used when building the C library.
|
||||
# DO NOT use them when building your application!
|
||||
# Nasty things could happen if you do.
|
||||
#
|
||||
# /Oi is required for Microsoft VC++ to allow "intrinsic" functions to be
|
||||
# defined in this library.
|
||||
#
|
||||
#[BuildOptions]
|
||||
# MSFT:*_*_*_CC_FLAGS = /Oi-
|
||||
|
@@ -19,7 +19,7 @@
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = DevShell
|
||||
FILE_GUID = 42c078ef-14a8-4e30-9329-6f12d796e54a
|
||||
FILE_GUID = 0a1d4fd8-4704-4501-85eb-93399492cbed
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = DevShell
|
||||
@@ -49,15 +49,3 @@
|
||||
LibWchar
|
||||
LibUefi
|
||||
DevUtility
|
||||
|
||||
################################################################
|
||||
#
|
||||
# The Build Options, below, are only used when building the C library.
|
||||
# DO NOT use them when building your application!
|
||||
# Nasty things could happen if you do.
|
||||
#
|
||||
# /Oi is required for Microsoft VC++ to allow "intrinsic" functions to be
|
||||
# defined in this library.
|
||||
#
|
||||
#[BuildOptions]
|
||||
# MSFT:*_*_*_CC_FLAGS = /Oi-
|
||||
|
@@ -15,7 +15,7 @@
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = DevUtility
|
||||
FILE_GUID = 42c078ef-14a8-4e30-9329-6f12d796e54a
|
||||
FILE_GUID = d6a9928c-3397-4dd1-818f-c664ba6dcaaf
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = DevUtility
|
||||
@@ -42,15 +42,3 @@
|
||||
LibC
|
||||
LibWchar
|
||||
LibUefi
|
||||
|
||||
################################################################
|
||||
#
|
||||
# The Build Options, below, are only used when building the C library.
|
||||
# DO NOT use them when building your application!
|
||||
# Nasty things could happen if you do.
|
||||
#
|
||||
# /Oi- is required for Microsoft VC++ to allow "intrinsic" functions to be
|
||||
# defined in this library.
|
||||
#
|
||||
#[BuildOptions]
|
||||
# MSFT:*_*_*_CC_FLAGS = /Oi-
|
||||
|
57
StdLib/LibC/Uefi/GetPass.c
Normal file
57
StdLib/LibC/Uefi/GetPass.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/** @file Implement the getpass function.
|
||||
|
||||
Copyright (c) 2011, Intel Corporation <BR>
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <Library/ShellLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
|
||||
static CHAR8 *ReturnStringAscii = NULL;
|
||||
|
||||
char *getpass(const char *Prompt)
|
||||
{
|
||||
BOOLEAN Ascii;
|
||||
CHAR16 *ReturnString;
|
||||
|
||||
Ascii = FALSE;
|
||||
|
||||
Print(L"%a", Prompt);
|
||||
|
||||
ReturnString = ShellFileHandleReturnLine (gEfiShellParametersProtocol->StdIn, &Ascii);
|
||||
if (ReturnString == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ReturnStringAscii = AllocateZeroPool((StrLen(ReturnString)+1)*sizeof(CHAR8));
|
||||
if (ReturnStringAscii == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
UnicodeStrToAsciiStr(ReturnString, ReturnStringAscii);
|
||||
|
||||
FreePool(ReturnString);
|
||||
|
||||
return (ReturnStringAscii);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DestructMePlease (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
SHELL_FREE_NON_NULL(ReturnStringAscii);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
79
StdLib/LibC/Uefi/StubFunctions.c
Normal file
79
StdLib/LibC/Uefi/StubFunctions.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/** @file
|
||||
Implement the invalid functions to return failures.
|
||||
|
||||
Copyright (c) 2011, Intel Corporation
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
#include <sys/EfiCdefs.h>
|
||||
#include <sys/featuretest.h>
|
||||
#include <namespace.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct passwd *
|
||||
getpwuid (uid_t uid)
|
||||
{
|
||||
uid;
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *getlogin (void)
|
||||
{
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct passwd *
|
||||
getpwnam (const char *name)
|
||||
{
|
||||
name;
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uid_t getuid (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pid_t fork (void)
|
||||
{
|
||||
errno = EPERM;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int chmod (const char *c, mode_t m)
|
||||
{
|
||||
errno = EPERM;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pid_t wait(int *stat_loc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *popen (const char *cmd, const char *type)
|
||||
{
|
||||
errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int pclose (FILE *stream)
|
||||
{
|
||||
errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int access (const char *path, int amode)
|
||||
{
|
||||
return 0;
|
||||
}
|
@@ -524,7 +524,7 @@ mkdir (const char *path, __mode_t perms)
|
||||
int Instance = 0;
|
||||
int retval = 0;
|
||||
|
||||
Status = ParsePath(path, &NewPath, &Node, &Instance);
|
||||
Status = ParsePath(path, &NewPath, &Node, &Instance, NULL);
|
||||
if(Status == RETURN_SUCCESS) {
|
||||
GenI = Node->InstanceList;
|
||||
if(GenI == NULL) {
|
||||
@@ -532,7 +532,7 @@ mkdir (const char *path, __mode_t perms)
|
||||
retval = -1;
|
||||
}
|
||||
else {
|
||||
GenI += (Instance * Node->InstanceSize);
|
||||
//GenI += (Instance * Node->InstanceSize);
|
||||
retval = ((GenericInstance *)GenI)->Abstraction.fo_mkdir( path, perms);
|
||||
}
|
||||
free(NewPath);
|
||||
@@ -567,11 +567,15 @@ mkdir (const char *path, __mode_t perms)
|
||||
O_EXCL -- if O_CREAT is also set, open will fail if the file already exists.
|
||||
**/
|
||||
int
|
||||
open (const char *path, int oflags, int mode)
|
||||
open(
|
||||
const char *path,
|
||||
int oflags,
|
||||
int mode
|
||||
)
|
||||
{
|
||||
wchar_t *NewPath;
|
||||
wchar_t *MPath;
|
||||
DeviceNode *Node;
|
||||
char *GenI = NULL;
|
||||
struct __filedes *filp;
|
||||
int Instance = 0;
|
||||
RETURN_STATUS Status;
|
||||
@@ -579,10 +583,10 @@ open (const char *path, int oflags, int mode)
|
||||
int fd = -1;
|
||||
int doresult;
|
||||
|
||||
Status = ParsePath(path, &NewPath, &Node, &Instance);
|
||||
Status = ParsePath(path, &NewPath, &Node, &Instance, &MPath);
|
||||
if(Status == RETURN_SUCCESS) {
|
||||
if((Node != NULL) &&
|
||||
((GenI = Node->InstanceList) == NULL)) {
|
||||
if((Node == NULL) ||
|
||||
(Node->InstanceList == NULL)) {
|
||||
errno = EPERM;
|
||||
}
|
||||
else {
|
||||
@@ -595,15 +599,14 @@ open (const char *path, int oflags, int mode)
|
||||
if( fd < 0 ) {
|
||||
// All available FDs are in use
|
||||
errno = EMFILE;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
filp = &gMD->fdarray[fd];
|
||||
// Save the flags and mode in the File Descriptor
|
||||
filp->Oflags = oflags;
|
||||
filp->Omode = mode;
|
||||
|
||||
GenI += (Instance * Node->InstanceSize);
|
||||
doresult = Node->OpenFunc(filp, GenI, NewPath, NULL);
|
||||
doresult = Node->OpenFunc(Node, filp, Instance, NewPath, MPath);
|
||||
if(doresult < 0) {
|
||||
filp->f_iflags = 0; // Release this FD
|
||||
fd = -1; // Indicate an error
|
||||
@@ -618,8 +621,14 @@ open (const char *path, int oflags, int mode)
|
||||
FILE_SET_MATURE(filp);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(NewPath != NULL) {
|
||||
free(NewPath);
|
||||
}
|
||||
}
|
||||
if(MPath != NULL) {
|
||||
free(MPath); // We don't need this any more.
|
||||
}
|
||||
// return the fd of our now open file
|
||||
return fd;
|
||||
}
|
||||
@@ -748,6 +757,7 @@ poll (
|
||||
}
|
||||
} while (( 0 == SelectedFDs )
|
||||
&& ( EFI_SUCCESS == Status ));
|
||||
|
||||
//
|
||||
// Stop the timer
|
||||
//
|
||||
@@ -776,7 +786,6 @@ poll (
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** The rename() function changes the name of a file.
|
||||
The old argument points to the pathname of the file to be renamed. The new
|
||||
argument points to the new pathname of the file.
|
||||
@@ -807,7 +816,6 @@ poll (
|
||||
shall be changed or created.
|
||||
**/
|
||||
int
|
||||
EFIAPI
|
||||
rename(
|
||||
const char *from,
|
||||
const char *to
|
||||
@@ -820,7 +828,7 @@ rename(
|
||||
RETURN_STATUS Status;
|
||||
int retval = -1;
|
||||
|
||||
Status = ParsePath(from, &FromPath, &FromNode, &Instance);
|
||||
Status = ParsePath(from, &FromPath, &FromNode, &Instance, NULL);
|
||||
if(Status == RETURN_SUCCESS) {
|
||||
GenI = FromNode->InstanceList;
|
||||
if(GenI == NULL) {
|
||||
@@ -828,7 +836,7 @@ rename(
|
||||
retval = -1;
|
||||
}
|
||||
else {
|
||||
GenI += (Instance * FromNode->InstanceSize);
|
||||
//GenI += (Instance * FromNode->InstanceSize);
|
||||
retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( from, to);
|
||||
}
|
||||
free(FromPath);
|
||||
@@ -839,7 +847,6 @@ rename(
|
||||
/**
|
||||
**/
|
||||
int
|
||||
EFIAPI
|
||||
rmdir(
|
||||
const char *path
|
||||
)
|
||||
@@ -1006,13 +1013,13 @@ ioctl(
|
||||
from a file associated with a terminal may return one typed line of data.
|
||||
|
||||
If fildes does not refer to a directory, the function reads the requested
|
||||
number of bytes from the file at the file<EFBFBD>s current position and returns
|
||||
number of bytes from the file at the file's current position and returns
|
||||
them in buf. If the read goes beyond the end of the file, the read
|
||||
length is truncated to the end of the file. The file<EFBFBD>s current position is
|
||||
length is truncated to the end of the file. The file's current position is
|
||||
increased by the number of bytes returned.
|
||||
|
||||
If fildes refers to a directory, the function reads the directory entry at
|
||||
the file<EFBFBD>s current position and returns the entry in buf. If buf
|
||||
the file's current position and returns the entry in buf. If buf
|
||||
is not large enough to hold the current directory entry, then
|
||||
errno is set to EBUFSIZE, EFIerrno is set to EFI_BUFFER_TOO_SMALL, and the
|
||||
current file position is not updated. The size of the buffer needed to read
|
||||
@@ -1129,3 +1136,56 @@ char
|
||||
|
||||
return (UnicodeStrToAsciiStr(Cwd, buf));
|
||||
}
|
||||
|
||||
/** Change the current working directory.
|
||||
|
||||
The chdir() function shall cause the directory named by the pathname
|
||||
pointed to by the path argument to become the current working directory;
|
||||
that is, the starting point for path searches for pathnames not beginning
|
||||
with '/'.
|
||||
|
||||
@param[in] path The new path to set.
|
||||
|
||||
@todo Add non-shell CWD changing.
|
||||
**/
|
||||
int
|
||||
chdir (const char *path)
|
||||
{
|
||||
CONST CHAR16 *Cwd;
|
||||
EFI_STATUS Status;
|
||||
CHAR16 *UnicodePath;
|
||||
|
||||
Cwd = ShellGetCurrentDir(NULL);
|
||||
if (Cwd != NULL) {
|
||||
/* We have shell support */
|
||||
UnicodePath = AllocatePool(((AsciiStrLen (path) + 1) * sizeof (CHAR16)));
|
||||
if (UnicodePath == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
AsciiStrToUnicodeStr(path, UnicodePath);
|
||||
Status = gEfiShellProtocol->SetCurDir(NULL, UnicodePath);
|
||||
FreePool(UnicodePath);
|
||||
if (EFI_ERROR(Status)) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add here for non-shell */
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid_t tcgetpgrp (int x)
|
||||
{
|
||||
return ((pid_t)(UINTN)(gImageHandle));
|
||||
}
|
||||
|
||||
pid_t getpgrp(void)
|
||||
{
|
||||
return ((pid_t)(UINTN)(gImageHandle));
|
||||
}
|
||||
|
||||
|
@@ -16,18 +16,24 @@
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = LibUefi
|
||||
FILE_GUID = 39356e02-26bf-4cfb-9564-378ce25e702f
|
||||
FILE_GUID = 1dcff17c-aa53-4b78-b234-864027555035
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = LibUefi
|
||||
LIBRARY_CONSTRUCTOR = DestructMePlease
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 IPF
|
||||
#
|
||||
|
||||
[Sources]
|
||||
select.c
|
||||
SysCalls.c
|
||||
writev.c
|
||||
Xform.c
|
||||
compat.c
|
||||
GetPass.c
|
||||
StubFunctions.c
|
||||
|
||||
[Packages]
|
||||
StdLib/StdLib.dec
|
||||
|
847
StdLib/LibC/Uefi/compat.c
Normal file
847
StdLib/LibC/Uefi/compat.c
Normal file
@@ -0,0 +1,847 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: compat.c,v 1.1.1.1 2008/08/24 05:33:08 gmcgarry Exp $
|
||||
|
||||
* Copyright (c) 1997, 2002 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Klaus Klein and Jason R. Thorpe.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $NetBSD: compat.c,v 1.1.1.1 2008/08/24 05:33:08 gmcgarry Exp $
|
||||
|
||||
* Copyright (c) 1987, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $NetBSD: compat.c,v 1.1.1.1 2008/08/24 05:33:08 gmcgarry Exp $
|
||||
*/
|
||||
#include <LibConfig.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
char *optarg;
|
||||
int optind = 1;
|
||||
int
|
||||
getopt(int argc, char **argv, char *args)
|
||||
{
|
||||
size_t n;
|
||||
size_t nlen = strlen(args);
|
||||
char cmd;
|
||||
char rv;
|
||||
|
||||
if (argv[optind] && *argv[optind] == '-') {
|
||||
cmd = *(argv[optind] + 1);
|
||||
|
||||
for (n = 0; n < nlen; n++) {
|
||||
if (args[n] == ':')
|
||||
continue;
|
||||
if (args[n] == cmd) {
|
||||
rv = *(argv[optind] + 1);
|
||||
if (args[n+1] == ':') {
|
||||
if (*(argv[optind] + 2) != '\0') {
|
||||
optarg = argv[optind] + 2;
|
||||
optind += 1;
|
||||
} else {
|
||||
optarg = argv[optind + 1];
|
||||
optind += 2;
|
||||
}
|
||||
if (!optarg)
|
||||
optarg="";
|
||||
return rv;
|
||||
} else {
|
||||
optarg = NULL;
|
||||
optind += 1;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define ISPATHSEPARATOR(x) ((x == '/') || (x == '\\'))
|
||||
#else
|
||||
#define ISPATHSEPARATOR(x) (x == '/')
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_BASENAME
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 5000
|
||||
#endif
|
||||
|
||||
char *
|
||||
basename(char *path)
|
||||
{
|
||||
static char singledot[] = ".";
|
||||
static char result[PATH_MAX];
|
||||
char *p, *lastp;
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* If `path' is a null pointer or points to an empty string,
|
||||
* return a pointer to the string ".".
|
||||
*/
|
||||
if ((path == NULL) || (*path == '\0'))
|
||||
return (singledot);
|
||||
|
||||
/* Strip trailing slashes, if any. */
|
||||
lastp = path + strlen(path) - 1;
|
||||
while (lastp != path && ISPATHSEPARATOR(*lastp))
|
||||
lastp--;
|
||||
|
||||
/* Now find the beginning of this (final) component. */
|
||||
p = lastp;
|
||||
while (p != path && !ISPATHSEPARATOR(*(p - 1)))
|
||||
p--;
|
||||
|
||||
/* ...and copy the result into the result buffer. */
|
||||
len = (lastp - p) + 1 /* last char */;
|
||||
if (len > (PATH_MAX - 1))
|
||||
len = PATH_MAX - 1;
|
||||
|
||||
memcpy(result, p, len);
|
||||
result[len] = '\0';
|
||||
|
||||
return (result);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_MKSTEMP) && !defined(WIN32)
|
||||
int
|
||||
mkstemp(char *path)
|
||||
{
|
||||
char *start, *trv;
|
||||
unsigned int pid;
|
||||
|
||||
/* To guarantee multiple calls generate unique names even if
|
||||
the file is not created. 676 different possibilities with 7
|
||||
or more X's, 26 with 6 or less. */
|
||||
static char xtra[2] = "aa";
|
||||
int xcnt = 0;
|
||||
|
||||
pid = getpid();
|
||||
|
||||
/* Move to end of path and count trailing X's. */
|
||||
for (trv = path; *trv; ++trv)
|
||||
if (*trv == 'X')
|
||||
xcnt++;
|
||||
else
|
||||
xcnt = 0;
|
||||
|
||||
/* Use at least one from xtra. Use 2 if more than 6 X's. */
|
||||
if (*(trv - 1) == 'X')
|
||||
*--trv = xtra[0];
|
||||
if (xcnt > 6 && *(trv - 1) == 'X')
|
||||
*--trv = xtra[1];
|
||||
|
||||
/* Set remaining X's to pid digits with 0's to the left. */
|
||||
while (*--trv == 'X') {
|
||||
*trv = (pid % 10) + '0';
|
||||
pid /= 10;
|
||||
}
|
||||
|
||||
/* update xtra for next call. */
|
||||
if (xtra[0] != 'z')
|
||||
xtra[0]++;
|
||||
else {
|
||||
xtra[0] = 'a';
|
||||
if (xtra[1] != 'z')
|
||||
xtra[1]++;
|
||||
else
|
||||
xtra[1] = 'a';
|
||||
}
|
||||
|
||||
return open(path, O_CREAT | O_EXCL | O_RDWR, 0600);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FFS
|
||||
int
|
||||
ffs(int x)
|
||||
{
|
||||
int r = 1;
|
||||
if (!x) return 0;
|
||||
if (!(x & 0xffff)) { x >>= 16; r += 16; }
|
||||
if (!(x & 0xff)) { x >>= 8; r += 8; }
|
||||
if (!(x & 0xf)) { x >>= 4; r += 4; }
|
||||
if (!(x & 3)) { x >>= 2; r += 2; }
|
||||
if (!(x & 1)) { x >>= 1; r += 1; }
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Copyright Patrick Powell 1995
|
||||
* This code is based on code written by Patrick Powell (papowell@astart.com)
|
||||
* It may be used for any purpose as long as this notice remains intact
|
||||
* on all source code distributions
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
|
||||
|
||||
static void
|
||||
dopr(char *buffer, size_t maxlen, const char *format, va_list args);
|
||||
|
||||
static void
|
||||
fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags,
|
||||
int min, int max);
|
||||
|
||||
static void
|
||||
fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base,
|
||||
int min, int max, int flags);
|
||||
|
||||
static void
|
||||
fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
|
||||
int min, int max, int flags);
|
||||
|
||||
static void
|
||||
dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
|
||||
|
||||
/*
|
||||
* dopr(): poor man's version of doprintf
|
||||
*/
|
||||
|
||||
/* format read states */
|
||||
#define DP_S_DEFAULT 0
|
||||
#define DP_S_FLAGS 1
|
||||
#define DP_S_MIN 2
|
||||
#define DP_S_DOT 3
|
||||
#define DP_S_MAX 4
|
||||
#define DP_S_MOD 5
|
||||
#define DP_S_CONV 6
|
||||
#define DP_S_DONE 7
|
||||
|
||||
/* format flags - Bits */
|
||||
#define DP_F_MINUS (1 << 0)
|
||||
#define DP_F_PLUS (1 << 1)
|
||||
#define DP_F_SPACE (1 << 2)
|
||||
#define DP_F_NUM (1 << 3)
|
||||
#define DP_F_ZERO (1 << 4)
|
||||
#define DP_F_UP (1 << 5)
|
||||
#define DP_F_UNSIGNED (1 << 6)
|
||||
|
||||
/* Conversion Flags */
|
||||
#define DP_C_SHORT 1
|
||||
#define DP_C_LONG 2
|
||||
#define DP_C_LDOUBLE 3
|
||||
#define DP_C_LONG_LONG 4
|
||||
|
||||
#define char_to_int(p) (p - '0')
|
||||
#define abs_val(p) (p < 0 ? -p : p)
|
||||
|
||||
|
||||
static void
|
||||
dopr(char *buffer, size_t maxlen, const char *format, va_list args)
|
||||
{
|
||||
char *strvalue, ch;
|
||||
long value;
|
||||
long double fvalue;
|
||||
int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;
|
||||
size_t currlen = 0;
|
||||
|
||||
ch = *format++;
|
||||
|
||||
while (state != DP_S_DONE) {
|
||||
if ((ch == '\0') || (currlen >= maxlen))
|
||||
state = DP_S_DONE;
|
||||
|
||||
switch(state) {
|
||||
case DP_S_DEFAULT:
|
||||
if (ch == '%')
|
||||
state = DP_S_FLAGS;
|
||||
else
|
||||
dopr_outch(buffer, &currlen, maxlen, ch);
|
||||
ch = *format++;
|
||||
break;
|
||||
case DP_S_FLAGS:
|
||||
switch (ch) {
|
||||
case '-':
|
||||
flags |= DP_F_MINUS;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '+':
|
||||
flags |= DP_F_PLUS;
|
||||
ch = *format++;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= DP_F_SPACE;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '#':
|
||||
flags |= DP_F_NUM;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '0':
|
||||
flags |= DP_F_ZERO;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
state = DP_S_MIN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DP_S_MIN:
|
||||
if (isdigit((unsigned char)ch)) {
|
||||
min = 10 * min + char_to_int (ch);
|
||||
ch = *format++;
|
||||
} else if (ch == '*') {
|
||||
min = va_arg (args, int);
|
||||
ch = *format++;
|
||||
state = DP_S_DOT;
|
||||
} else
|
||||
state = DP_S_DOT;
|
||||
break;
|
||||
case DP_S_DOT:
|
||||
if (ch == '.') {
|
||||
state = DP_S_MAX;
|
||||
ch = *format++;
|
||||
} else
|
||||
state = DP_S_MOD;
|
||||
break;
|
||||
case DP_S_MAX:
|
||||
if (isdigit((unsigned char)ch)) {
|
||||
if (max < 0)
|
||||
max = 0;
|
||||
max = 10 * max + char_to_int(ch);
|
||||
ch = *format++;
|
||||
} else if (ch == '*') {
|
||||
max = va_arg (args, int);
|
||||
ch = *format++;
|
||||
state = DP_S_MOD;
|
||||
} else
|
||||
state = DP_S_MOD;
|
||||
break;
|
||||
case DP_S_MOD:
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
cflags = DP_C_SHORT;
|
||||
ch = *format++;
|
||||
break;
|
||||
case 'l':
|
||||
cflags = DP_C_LONG;
|
||||
ch = *format++;
|
||||
if (ch == 'l') {
|
||||
cflags = DP_C_LONG_LONG;
|
||||
ch = *format++;
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
cflags = DP_C_LONG_LONG;
|
||||
ch = *format++;
|
||||
break;
|
||||
case 'L':
|
||||
cflags = DP_C_LDOUBLE;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = DP_S_CONV;
|
||||
break;
|
||||
case DP_S_CONV:
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = va_arg(args, int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg(args, long int);
|
||||
else if (cflags == DP_C_LONG_LONG)
|
||||
value = va_arg (args, long long);
|
||||
else
|
||||
value = va_arg (args, int);
|
||||
fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
|
||||
break;
|
||||
case 'o':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = va_arg(args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg(args, unsigned long int);
|
||||
else if (cflags == DP_C_LONG_LONG)
|
||||
value = va_arg(args, unsigned long long);
|
||||
else
|
||||
value = va_arg(args, unsigned int);
|
||||
fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
|
||||
break;
|
||||
case 'u':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = va_arg(args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg(args, unsigned long int);
|
||||
else if (cflags == DP_C_LONG_LONG)
|
||||
value = va_arg(args, unsigned long long);
|
||||
else
|
||||
value = va_arg(args, unsigned int);
|
||||
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
|
||||
break;
|
||||
case 'X':
|
||||
flags |= DP_F_UP;
|
||||
case 'x':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = va_arg(args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg(args, unsigned long int);
|
||||
else if (cflags == DP_C_LONG_LONG)
|
||||
value = va_arg(args, unsigned long long);
|
||||
else
|
||||
value = va_arg(args, unsigned int);
|
||||
fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
|
||||
break;
|
||||
case 'f':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg(args, long double);
|
||||
else
|
||||
fvalue = va_arg(args, double);
|
||||
/* um, floating point? */
|
||||
fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
|
||||
break;
|
||||
case 'E':
|
||||
flags |= DP_F_UP;
|
||||
case 'e':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg(args, long double);
|
||||
else
|
||||
fvalue = va_arg(args, double);
|
||||
break;
|
||||
case 'G':
|
||||
flags |= DP_F_UP;
|
||||
case 'g':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg(args, long double);
|
||||
else
|
||||
fvalue = va_arg(args, double);
|
||||
break;
|
||||
case 'c':
|
||||
dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
|
||||
break;
|
||||
case 's':
|
||||
strvalue = va_arg(args, char *);
|
||||
if (max < 0)
|
||||
max = maxlen; /* ie, no max */
|
||||
fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
|
||||
break;
|
||||
case 'p':
|
||||
strvalue = va_arg(args, void *);
|
||||
fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
|
||||
break;
|
||||
case 'n':
|
||||
if (cflags == DP_C_SHORT) {
|
||||
short int *num;
|
||||
num = va_arg(args, short int *);
|
||||
*num = currlen;
|
||||
} else if (cflags == DP_C_LONG) {
|
||||
long int *num;
|
||||
num = va_arg(args, long int *);
|
||||
*num = currlen;
|
||||
} else if (cflags == DP_C_LONG_LONG) {
|
||||
long long *num;
|
||||
num = va_arg(args, long long *);
|
||||
*num = currlen;
|
||||
} else {
|
||||
int *num;
|
||||
num = va_arg(args, int *);
|
||||
*num = currlen;
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
dopr_outch(buffer, &currlen, maxlen, ch);
|
||||
break;
|
||||
case 'w': /* not supported yet, treat as next char */
|
||||
ch = *format++;
|
||||
break;
|
||||
default: /* Unknown, skip */
|
||||
break;
|
||||
}
|
||||
ch = *format++;
|
||||
state = DP_S_DEFAULT;
|
||||
flags = cflags = min = 0;
|
||||
max = -1;
|
||||
break;
|
||||
case DP_S_DONE:
|
||||
break;
|
||||
default: /* hmm? */
|
||||
break; /* some picky compilers need this */
|
||||
}
|
||||
}
|
||||
if (currlen < maxlen - 1)
|
||||
buffer[currlen] = '\0';
|
||||
else
|
||||
buffer[maxlen - 1] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
fmtstr(char *buffer, size_t *currlen, size_t maxlen,
|
||||
char *value, int flags, int min, int max)
|
||||
{
|
||||
int cnt = 0, padlen, strln; /* amount to pad */
|
||||
|
||||
if (value == 0)
|
||||
value = "<NULL>";
|
||||
|
||||
for (strln = 0; value[strln]; ++strln); /* strlen */
|
||||
padlen = min - strln;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen; /* Left Justify */
|
||||
|
||||
while ((padlen > 0) && (cnt < max)) {
|
||||
dopr_outch(buffer, currlen, maxlen, ' ');
|
||||
--padlen;
|
||||
++cnt;
|
||||
}
|
||||
while (*value && (cnt < max)) {
|
||||
dopr_outch(buffer, currlen, maxlen, *value++);
|
||||
++cnt;
|
||||
}
|
||||
while ((padlen < 0) && (cnt < max)) {
|
||||
dopr_outch(buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
|
||||
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
|
||||
|
||||
static void
|
||||
fmtint(char *buffer, size_t *currlen, size_t maxlen,
|
||||
long value, int base, int min, int max, int flags)
|
||||
{
|
||||
unsigned long uvalue;
|
||||
char convert[20];
|
||||
int signvalue = 0, place = 0, caps = 0;
|
||||
int spadlen = 0; /* amount to space pad */
|
||||
int zpadlen = 0; /* amount to zero pad */
|
||||
|
||||
#define PADMAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
if (max < 0)
|
||||
max = 0;
|
||||
|
||||
uvalue = value;
|
||||
|
||||
if (!(flags & DP_F_UNSIGNED)) {
|
||||
if (value < 0) {
|
||||
signvalue = '-';
|
||||
uvalue = -value;
|
||||
} else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
||||
signvalue = '+';
|
||||
else if (flags & DP_F_SPACE)
|
||||
signvalue = ' ';
|
||||
}
|
||||
|
||||
if (flags & DP_F_UP)
|
||||
caps = 1; /* Should characters be upper case? */
|
||||
do {
|
||||
convert[place++] =
|
||||
(caps ? "0123456789ABCDEF" : "0123456789abcdef")
|
||||
[uvalue % (unsigned)base];
|
||||
uvalue = (uvalue / (unsigned)base );
|
||||
} while (uvalue && (place < 20));
|
||||
if (place == 20)
|
||||
place--;
|
||||
convert[place] = 0;
|
||||
|
||||
zpadlen = max - place;
|
||||
spadlen = min - PADMAX(max, place) - (signvalue ? 1 : 0);
|
||||
if (zpadlen < 0)
|
||||
zpadlen = 0;
|
||||
if (spadlen < 0)
|
||||
spadlen = 0;
|
||||
if (flags & DP_F_ZERO) {
|
||||
zpadlen = PADMAX(zpadlen, spadlen);
|
||||
spadlen = 0;
|
||||
}
|
||||
if (flags & DP_F_MINUS)
|
||||
spadlen = -spadlen; /* Left Justifty */
|
||||
|
||||
/* Spaces */
|
||||
while (spadlen > 0) {
|
||||
dopr_outch(buffer, currlen, maxlen, ' ');
|
||||
--spadlen;
|
||||
}
|
||||
|
||||
/* Sign */
|
||||
if (signvalue)
|
||||
dopr_outch(buffer, currlen, maxlen, signvalue);
|
||||
|
||||
/* Zeros */
|
||||
if (zpadlen > 0) {
|
||||
while (zpadlen > 0) {
|
||||
dopr_outch(buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
}
|
||||
|
||||
/* Digits */
|
||||
while (place > 0)
|
||||
dopr_outch(buffer, currlen, maxlen, convert[--place]);
|
||||
|
||||
/* Left Justified spaces */
|
||||
while (spadlen < 0) {
|
||||
dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
++spadlen;
|
||||
}
|
||||
}
|
||||
|
||||
static long double
|
||||
pow10(int exp)
|
||||
{
|
||||
long double result = 1;
|
||||
|
||||
while (exp) {
|
||||
result *= 10;
|
||||
exp--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static long
|
||||
round(long double value)
|
||||
{
|
||||
long intpart = value;
|
||||
|
||||
value -= intpart;
|
||||
if (value >= 0.5)
|
||||
intpart++;
|
||||
|
||||
return intpart;
|
||||
}
|
||||
|
||||
static void
|
||||
fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
|
||||
int min, int max, int flags)
|
||||
{
|
||||
char iconvert[20], fconvert[20];
|
||||
int signvalue = 0, iplace = 0, fplace = 0;
|
||||
int padlen = 0; /* amount to pad */
|
||||
int zpadlen = 0, caps = 0;
|
||||
long intpart, fracpart;
|
||||
long double ufvalue;
|
||||
|
||||
/*
|
||||
* AIX manpage says the default is 0, but Solaris says the default
|
||||
* is 6, and sprintf on AIX defaults to 6
|
||||
*/
|
||||
if (max < 0)
|
||||
max = 6;
|
||||
|
||||
ufvalue = abs_val(fvalue);
|
||||
|
||||
if (fvalue < 0)
|
||||
signvalue = '-';
|
||||
else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
||||
signvalue = '+';
|
||||
else if (flags & DP_F_SPACE)
|
||||
signvalue = ' ';
|
||||
|
||||
intpart = ufvalue;
|
||||
|
||||
/*
|
||||
* Sorry, we only support 9 digits past the decimal because of our
|
||||
* conversion method
|
||||
*/
|
||||
if (max > 9)
|
||||
max = 9;
|
||||
|
||||
/* We "cheat" by converting the fractional part to integer by
|
||||
* multiplying by a factor of 10
|
||||
*/
|
||||
fracpart = round((pow10 (max)) * (ufvalue - intpart));
|
||||
|
||||
if (fracpart >= pow10 (max)) {
|
||||
intpart++;
|
||||
fracpart -= pow10 (max);
|
||||
}
|
||||
|
||||
/* Convert integer part */
|
||||
do {
|
||||
iconvert[iplace++] =
|
||||
(caps ? "0123456789ABCDEF" : "0123456789abcdef")
|
||||
[intpart % 10];
|
||||
intpart = (intpart / 10);
|
||||
} while(intpart && (iplace < 20));
|
||||
if (iplace == 20)
|
||||
iplace--;
|
||||
iconvert[iplace] = 0;
|
||||
|
||||
/* Convert fractional part */
|
||||
do {
|
||||
fconvert[fplace++] =
|
||||
(caps ? "0123456789ABCDEF" : "0123456789abcdef")
|
||||
[fracpart % 10];
|
||||
fracpart = (fracpart / 10);
|
||||
} while(fracpart && (fplace < 20));
|
||||
if (fplace == 20)
|
||||
fplace--;
|
||||
fconvert[fplace] = 0;
|
||||
|
||||
/* -1 for decimal point, another -1 if we are printing a sign */
|
||||
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
|
||||
zpadlen = max - fplace;
|
||||
if (zpadlen < 0)
|
||||
zpadlen = 0;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen; /* Left Justifty */
|
||||
|
||||
if ((flags & DP_F_ZERO) && (padlen > 0)) {
|
||||
if (signvalue) {
|
||||
dopr_outch(buffer, currlen, maxlen, signvalue);
|
||||
--padlen;
|
||||
signvalue = 0;
|
||||
}
|
||||
while (padlen > 0) {
|
||||
dopr_outch(buffer, currlen, maxlen, '0');
|
||||
--padlen;
|
||||
}
|
||||
}
|
||||
while (padlen > 0) {
|
||||
dopr_outch(buffer, currlen, maxlen, ' ');
|
||||
--padlen;
|
||||
}
|
||||
if (signvalue)
|
||||
dopr_outch(buffer, currlen, maxlen, signvalue);
|
||||
|
||||
while (iplace > 0)
|
||||
dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
|
||||
|
||||
/*
|
||||
* Decimal point. This should probably use locale to find the
|
||||
* correct char to print out.
|
||||
*/
|
||||
dopr_outch(buffer, currlen, maxlen, '.');
|
||||
|
||||
while (fplace > 0)
|
||||
dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
|
||||
|
||||
while (zpadlen > 0) {
|
||||
dopr_outch(buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
|
||||
while (padlen < 0) {
|
||||
dopr_outch(buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
{
|
||||
if (*currlen < maxlen)
|
||||
buffer[(*currlen)++] = c;
|
||||
}
|
||||
#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
|
||||
|
||||
#ifndef HAVE_VSNPRINTF
|
||||
int
|
||||
vsnprintf(char *str, size_t count, const char *fmt, va_list args)
|
||||
{
|
||||
str[0] = 0;
|
||||
dopr(str, count, fmt, args);
|
||||
|
||||
return(strlen(str));
|
||||
}
|
||||
#endif /* !HAVE_VSNPRINTF */
|
||||
|
||||
#ifndef HAVE_SNPRINTF
|
||||
int
|
||||
snprintf(char *str,size_t count,const char *fmt,...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
(void) vsnprintf(str, count, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return(strlen(str));
|
||||
}
|
||||
|
||||
#endif /* !HAVE_SNPRINTF */
|
256
StdLib/LibC/Uefi/select.c
Normal file
256
StdLib/LibC/Uefi/select.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Portions copyright (c) 1999, 2000
|
||||
* Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
*
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley, Intel Corporation, and its contributors.
|
||||
*
|
||||
* 4. Neither the name of University, Intel Corporation, or their respective
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS, INTEL CORPORATION AND
|
||||
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS,
|
||||
* INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @(#)sys_generic.c 8.5 (Berkeley) 1/21/94
|
||||
* $Id: select.c,v 1.1.1.1 2003/11/19 01:50:30 kyu3 Exp $
|
||||
*/
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
|
||||
#include <LibConfig.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <extern.h> /* For ffs() */
|
||||
#ifndef KERNEL
|
||||
#define KERNEL
|
||||
#include <errno.h>
|
||||
#undef KERNEL
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef EFI_NT_EMULATOR
|
||||
#define _SELECT_DELAY_ 10000
|
||||
#else
|
||||
#define _SELECT_DELAY_ 1000
|
||||
#endif
|
||||
|
||||
#define MAX_SLEEP_DELAY 0xfffffffe
|
||||
|
||||
//
|
||||
// Name:
|
||||
// usleep
|
||||
//
|
||||
// Description:
|
||||
// Implement usleep(3) function.
|
||||
//
|
||||
// Arguments:
|
||||
// Microseconds to sleep.
|
||||
//
|
||||
// Returns:
|
||||
// 0
|
||||
//
|
||||
int
|
||||
usleep( useconds_t Microseconds )
|
||||
{
|
||||
while ( MAX_SLEEP_DELAY < Microseconds ) {
|
||||
gBS->Stall ( MAX_SLEEP_DELAY );
|
||||
Microseconds -= MAX_SLEEP_DELAY;
|
||||
}
|
||||
gBS->Stall((UINTN)Microseconds );
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
selscan(
|
||||
fd_mask **ibits,
|
||||
fd_mask **obits,
|
||||
int nfd,
|
||||
int *nselected
|
||||
)
|
||||
{
|
||||
int msk;
|
||||
int i;
|
||||
int j;
|
||||
int fd;
|
||||
int n;
|
||||
struct pollfd pfd;
|
||||
int FdCount;
|
||||
fd_mask bits;
|
||||
/* Note: backend also returns POLLHUP/POLLERR if appropriate. */
|
||||
static int16_t flag[3] = { POLLRDNORM, POLLWRNORM, POLLRDBAND };
|
||||
|
||||
for (msk = 0, n = 0; msk < 3; msk++) {
|
||||
if (ibits[msk] == NULL)
|
||||
continue;
|
||||
for (i = 0; i < nfd; i += NFDBITS) {
|
||||
bits = ibits[ msk ][ i / NFDBITS ];
|
||||
while (( 0 != (j = ffs(bits))) && ((fd = i + --j) < nfd)) {
|
||||
bits &= ~(1 << j);
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = flag[msk];
|
||||
pfd.revents = 0;
|
||||
FdCount = poll ( &pfd, 1, 0 );
|
||||
if ( -1 == FdCount ) {
|
||||
return errno;
|
||||
}
|
||||
if ( 0 != FdCount ) {
|
||||
obits[msk][(fd)/NFDBITS] |=
|
||||
(1 << ((fd) % NFDBITS));
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*nselected = n;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
select(
|
||||
int nd,
|
||||
fd_set *in,
|
||||
fd_set *ou,
|
||||
fd_set *ex,
|
||||
struct timeval *tv
|
||||
)
|
||||
{
|
||||
fd_mask *ibits[3], *obits[3], *selbits, *sbp;
|
||||
int error, forever, nselected;
|
||||
u_int nbufbytes, ncpbytes, nfdbits;
|
||||
int64_t timo;
|
||||
|
||||
if (nd < 0)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Allocate just enough bits for the non-null fd_sets. Use the
|
||||
* preallocated auto buffer if possible.
|
||||
*/
|
||||
nfdbits = roundup(nd, NFDBITS);
|
||||
ncpbytes = nfdbits / NBBY;
|
||||
nbufbytes = 0;
|
||||
if (in != NULL)
|
||||
nbufbytes += 2 * ncpbytes;
|
||||
if (ou != NULL)
|
||||
nbufbytes += 2 * ncpbytes;
|
||||
if (ex != NULL)
|
||||
nbufbytes += 2 * ncpbytes;
|
||||
selbits = malloc(nbufbytes);
|
||||
|
||||
/*
|
||||
* Assign pointers into the bit buffers and fetch the input bits.
|
||||
* Put the output buffers together so that they can be bzeroed
|
||||
* together.
|
||||
*/
|
||||
sbp = selbits;
|
||||
#define getbits(name, x) \
|
||||
do { \
|
||||
if (name == NULL) \
|
||||
ibits[x] = NULL; \
|
||||
else { \
|
||||
ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp; \
|
||||
obits[x] = sbp; \
|
||||
sbp += ncpbytes / sizeof *sbp; \
|
||||
bcopy(name, ibits[x], ncpbytes); \
|
||||
} \
|
||||
} while (0)
|
||||
getbits(in, 0);
|
||||
getbits(ou, 1);
|
||||
getbits(ex, 2);
|
||||
#undef getbits
|
||||
if (nbufbytes != 0)
|
||||
memset(selbits, 0, nbufbytes / 2);
|
||||
|
||||
if (tv) {
|
||||
timo = tv->tv_usec + (tv->tv_sec * 1000000);
|
||||
forever = 0;
|
||||
} else {
|
||||
timo = 0;
|
||||
forever = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll for I/O events
|
||||
*/
|
||||
nselected = 0;
|
||||
do {
|
||||
/*
|
||||
* Scan for pending I/O
|
||||
*/
|
||||
error = selscan(ibits, obits, nd, &nselected);
|
||||
if (error || nselected)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Adjust timeout is needed
|
||||
*/
|
||||
if (timo) {
|
||||
/*
|
||||
* Give it a rest
|
||||
*/
|
||||
usleep( _SELECT_DELAY_ );
|
||||
timo -= _SELECT_DELAY_;
|
||||
}
|
||||
|
||||
} while (timo > 0 || forever);
|
||||
|
||||
/* select is not restarted after signals... */
|
||||
if (error == ERESTART)
|
||||
error = EINTR;
|
||||
else if (error == EWOULDBLOCK)
|
||||
error = 0;
|
||||
|
||||
#define putbits(name, x) if (name) bcopy(obits[x], name, ncpbytes)
|
||||
if (error == 0) {
|
||||
putbits(in, 0);
|
||||
putbits(ou, 1);
|
||||
putbits(ex, 2);
|
||||
#undef putbits
|
||||
} else {
|
||||
errno = error;
|
||||
nselected = -1;
|
||||
}
|
||||
|
||||
free( selbits );
|
||||
return ( nselected );
|
||||
}
|
143
StdLib/LibC/Uefi/writev.c
Normal file
143
StdLib/LibC/Uefi/writev.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2000
|
||||
* Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software must
|
||||
* display the following acknowledgement:
|
||||
*
|
||||
* This product includes software developed by Intel Corporation and its
|
||||
* contributors.
|
||||
*
|
||||
* 4. Neither the name of Intel Corporation or its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*++
|
||||
|
||||
Module Name:
|
||||
|
||||
writev.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Functions implementing the standard "writev" system call interface
|
||||
|
||||
|
||||
Revision History
|
||||
|
||||
--*/
|
||||
#include <LibConfig.h>
|
||||
|
||||
#ifdef foo
|
||||
#include <efi_interface.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#define KERNEL
|
||||
#include <errno.h>
|
||||
#undef KERNEL
|
||||
#include "./filedesc.h"
|
||||
|
||||
#include <libc_debug.h>
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#include <string.h>
|
||||
#ifndef KERNEL
|
||||
#define KERNEL
|
||||
#include <errno.h>
|
||||
#undef KERNEL
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
//
|
||||
// Name:
|
||||
// writev
|
||||
//
|
||||
// Description:
|
||||
// BSD writev interface for libc
|
||||
//
|
||||
// Arguments:
|
||||
// File Descriptor (index into file descriptor table)
|
||||
// iovec pointer
|
||||
// size of iovec array
|
||||
//
|
||||
// Returns:
|
||||
// number of bytes written
|
||||
//
|
||||
|
||||
ssize_t
|
||||
writev(
|
||||
int fd,
|
||||
const struct iovec *iov,
|
||||
int iovcnt
|
||||
)
|
||||
{
|
||||
const struct iovec *pVecTmp;
|
||||
char *pBuf, *pBufTmp;
|
||||
size_t TotalBytes, i, ret;
|
||||
|
||||
//
|
||||
// See how much memory we'll need
|
||||
//
|
||||
|
||||
for (i = 0, TotalBytes = 0, pVecTmp = iov; i < (size_t)iovcnt; i++, pVecTmp++) {
|
||||
TotalBytes += pVecTmp->iov_len;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate a contiguous buffer
|
||||
//
|
||||
|
||||
pBuf = (char*)malloc (TotalBytes);
|
||||
if (pBuf == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Copy vectors to the buffer
|
||||
//
|
||||
|
||||
for (pBufTmp = pBuf; iovcnt; iovcnt--) {
|
||||
bcopy(iov->iov_base, pBuf, iov->iov_len);
|
||||
pBuf += iov->iov_len;
|
||||
iov++;
|
||||
}
|
||||
|
||||
//
|
||||
// Use standard write(2) then free buffer
|
||||
//
|
||||
|
||||
ret = write (fd, pBuf, TotalBytes);
|
||||
free (pBuf);
|
||||
|
||||
return (ret);
|
||||
}
|
Reference in New Issue
Block a user