Added UTF-8 support

This commit is contained in:
bzt 2021-02-16 13:47:43 +01:00
parent 804d74b0a2
commit acaf9f36ef
12 changed files with 416 additions and 269 deletions

116
README.md
View file

@ -52,14 +52,26 @@ An example **helloworld.c** goes like this:
```c
#include <uefi.h>
int main(int argc, char **argv)
{
printf("Hello World!\n");
return 0;
}
```
By default it uses Clang + lld, and PE is generated without conversion. If `USE_GCC` is set, then the host native's GNU gcc + ld
used to create a shared object and get converted into an .efi file.
If you comment out `USE_UTF8` in uefi.h, then all character representation will use `wchar_t`, and there will be no string
conversion between your application and the UEFI interfaces. This also means you must use `L""` and `L''` literals everywhere:
```c
#include <uefi.h>
int main(int argc, wchar_t **argv)
{
printf(L"Hello World!\n");
return 0;
}
```
By default it uses Clang + lld, and PE is generated without conversion. If `USE_GCC` is set, then the host native's GNU gcc + ld
used to create a shared object and get converted into an .efi file.
### Available Makefile Options
@ -97,10 +109,12 @@ for you, because simplicity was one of its main goals. It is the best to say thi
rather than a POSIX compatible libc.
All strings in the UEFI environment are stored with 16 bits wide characters. The library provides `wchar_t` type for that,
so for example your main() is NOT like `main(int argc, char **argv)`, but `main(int argc, wchar_t **argv)` instead. All
the other string related libc functions (like strlen() for example) use this wide character type too. For this reason, you
must specify your string literals with `L""` and characters with `L''`. Functions that supposed to handle characters in int
type (like `getchar`, `putchar`), do not truncate to unsigned char, rather to wchar_t.
and the `USE_UTF8` define to convert between `char` and `wchar_t` transparently. If you comment out `USE_UTF8`, then for
example your main() will NOT be like `main(int argc, char **argv)`, but `main(int argc, wchar_t **argv)` instead. All
the other string related libc functions (like strlen() for example) will use this wide character type too. For this reason,
you must specify your string literals with `L""` and characters with `L''`. To handle both configurations, `char_t` type is
defined, which is either `char` or `wchar_t`. Functions that supposed to handle characters in int type (like `getchar`,
`putchar`), do not truncate to unsigned char, rather to wchar_t.
File types in dirent are limited to directories and files only (DT_DIR, DT_REG), but for stat in addition to S_IFDIR and
S_IFREG, S_IFIFO also returned (for console streams: stdin, stdout, stderr).
@ -116,7 +130,7 @@ List of Provided POSIX Functions
| Function | Description |
|---------------|----------------------------------------------------------------------------|
| opendir | as usual, but accepts wide char strings |
| opendir | as usual, but might accept wide char strings |
| readdir | as usual |
| rewinddir | as usual |
| closedir | as usual |
@ -127,15 +141,16 @@ Because UEFI has no concept of device files nor of symlinks, dirent fields are l
| Function | Description |
|---------------|----------------------------------------------------------------------------|
| atoi | as usual, but accepts wide char strings and understands "0x" prefix |
| atol | as usual, but accepts wide char strings and understands "0x" prefix |
| strtol | as usual, but accepts wide char strings |
| atoi | as usual, but might accept wide char strings and understands "0x" prefix |
| atol | as usual, but might accept wide char strings and understands "0x" prefix |
| strtol | as usual, but might accept wide char strings |
| malloc | as usual |
| calloc | as usual |
| realloc | as usual (needs testing) |
| free | as usual |
| abort | as usual |
| exit | as usual |
| exit_bs | leave this entire UEFI bullshit behind (exit Boot Services) |
| mbtowc | as usual (UTF-8 char to wchar_t) |
| wctomb | as usual (wchar_t to UTF-8 char) |
| mbstowcs | as usual (UTF-8 string to wchar_t string) |
@ -146,12 +161,17 @@ Because UEFI has no concept of device files nor of symlinks, dirent fields are l
| setenv | pretty UEFI specific |
```c
uint8_t *getenv(wchar_t *name, uintn_t *len);
int exit_bs()
```
Exit Boot Services. Returns 0 on success.
```c
uint8_t *getenv(char_t *name, uintn_t *len);
```
Query the value of environment variable `name`. On success, `len` is set, and a malloc'd buffer returned. It is
the caller's responsibility to free the buffer later. On error returns NULL.
```c
int setenv(wchar_t *name, uintn_t len, uint8_t *data);
int setenv(char_t *name, uintn_t len, uint8_t *data);
```
Sets an environment variable by `name` with `data` of length `len`. On success returns 1, otherwise 0 on error.
@ -159,7 +179,7 @@ Sets an environment variable by `name` with `data` of length `len`. On success r
| Function | Description |
|---------------|----------------------------------------------------------------------------|
| fopen | as usual, but accepts wide char strings, also for mode |
| fopen | as usual, but might accept wide char strings, also for mode |
| fclose | as usual |
| fflush | as usual |
| fread | as usual, only real files accepted (no stdin) |
@ -167,33 +187,27 @@ Sets an environment variable by `name` with `data` of length `len`. On success r
| fseek | as usual, only real files accepted (no stdin, stdout, stderr) |
| ftell | as usual, only real files accepted (no stdin, stdout, stderr) |
| feof | as usual, only real files accepted (no stdin, stdout, stderr) |
| fprintf | as usual, but accepts wide char strings, max BUFSIZ, files, stdout, stderr |
| printf | as usual, but accepts wide char strings, max BUFSIZ, stdout only |
| sprintf | as usual, but accepts wide char strings, max BUFSIZ |
| vfprintf | as usual, but accepts wide char strings, max BUFSIZ, files, stdout, stderr |
| vprintf | as usual, but accepts wide char strings, max BUFSIZ |
| vsprintf | as usual, but accepts wide char strings, max BUFSIZ |
| snprintf | as usual, but accepts wide char strings |
| vsnprintf | as usual, but accepts wide char strings |
| getchar | as usual, waits for a key, blocking, stdin only (no redirects) |
| fprintf | as usual, might be wide char strings, max BUFSIZ, files, stdout, stderr |
| printf | as usual, might be wide char strings, max BUFSIZ, stdout only |
| sprintf | as usual, might be wide char strings, max BUFSIZ |
| vfprintf | as usual, might be wide char strings, max BUFSIZ, files, stdout, stderr |
| vprintf | as usual, might be wide char strings, max BUFSIZ |
| vsprintf | as usual, might be wide char strings, max BUFSIZ |
| snprintf | as usual, might be wide char strings |
| vsnprintf | as usual, might be wide char strings |
| getchar | as usual, blocking, stdin only (no stream redirects), returns UNICODE |
| getchar_ifany | non-blocking, returns 0 if there was no key press, UNICODE otherwise |
| putchar | as usual, stdout only (no redirects) |
| exit_bs | leave this entire UEFI bullshit behind (exit Boot Services) |
| putchar | as usual, stdout only (no stream redirects) |
```c
int exit_bs()
```
Exit Boot Services. Returns 0 on success.
File open modes: `L"r"` read, `L"w"` write, `L"a"` append. Because of UEFI peculiarities, `L"wd"` creates directory.
File open modes: `"r"` read, `"w"` write, `"a"` append. Because of UEFI peculiarities, `"wd"` creates directory.
String formating is limited; only supports padding via number prefixes, `%d`, `%x`, `%X`, `%c`, `%s`, `%q` and
`%p`. Because it operates on wchar_t, it also supports the non-standard `%C` (printing an UTF-8 character, needs
char\*), `%S` (printing an UTF-8 string), `%Q` (printing an escaped UTF-8 string). These functions don't allocate
memory, but in return the total length of the output string cannot be longer than BUFSIZ (8k if you haven't
defined otherwise), except for the variants which have a maxlen argument. For convenience, `%D` requires
`efi_physical_address_t` as argument, and it dumps memory, 16 bytes or one line at once. With the padding
modifier you can dump more lines, for example `%5D` gives you 5 lines (80 dumped bytes).
`%p`. When `USE_UTF8` is not defined, then formating operates on wchar_t, so it also supports the non-standard `%S`
(printing an UTF-8 string), `%Q` (printing an escaped UTF-8 string). These functions don't allocate memory, but in
return the total length of the output string cannot be longer than `BUFSIZ` (8k if you haven't defined otherwise),
except for the variants which have a maxlen argument. For convenience, `%D` requires `efi_physical_address_t` as
argument, and it dumps memory, 16 bytes or one line at once. With the padding modifier you can dump more lines, for
example `%5D` gives you 5 lines (80 dumped bytes).
Special "device files" you can open:
@ -219,27 +233,27 @@ With disk devices, `fread` and `fwrite` arguments look like this: fread(ptr, buf
| memrchr | as usual, works on bytes |
| memmem | as usual, works on bytes |
| memrmem | as usual, works on bytes |
| strcpy | works on wide char strings |
| strncpy | works on wide char strings |
| strcat | works on wide char strings |
| strncat | works on wide char strings |
| strcmp | works on wide char strings |
| strncmp | works on wide char strings |
| strdup | works on wide char strings |
| strchr | works on wide char strings |
| strrchr | works on wide char strings |
| strstr | works on wide char strings |
| strtok | works on wide char strings |
| strtok_r | works on wide char strings |
| strlen | works on wide char strings |
| strcpy | might work on wide char strings |
| strncpy | might work on wide char strings |
| strcat | might work on wide char strings |
| strncat | might work on wide char strings |
| strcmp | might work on wide char strings |
| strncmp | might work on wide char strings |
| strdup | might work on wide char strings |
| strchr | might work on wide char strings |
| strrchr | might work on wide char strings |
| strstr | might work on wide char strings |
| strtok | might work on wide char strings |
| strtok_r | might work on wide char strings |
| strlen | might work on wide char strings |
### sys/stat.h
| Function | Description |
|---------------|----------------------------------------------------------------------------|
| stat | as usual, but accepts wide char strings |
| stat | as usual, but might accept wide char strings |
| fstat | UEFI doesn't have fd, so it uses FILE\* |
| mkdir | as usual, but accepts wide char strings, and mode unused |
| mkdir | as usual, but might accept wide char strings, and mode unused |
Because UEFI has no concept of device major and minor number nor of inodes, struct stat's fields are limited.

View file

@ -3,11 +3,11 @@
/**
* Classic Hello World example
*/
int main(int argc, wchar_t **argv)
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
printf(L"Hello World!\n");
printf("Hello World!\n");
return 0;
}

View file

@ -1,15 +1,15 @@
#include <uefi.h>
/**
* Print out arguments
* Print out arguments. This source can be compiled with and without USE_UTF8
*/
int main(int argc, wchar_t **argv)
int main(int argc, char_t **argv)
{
int i;
printf(L"I got %d argument%s:\n", argc, argc > 1 ? L"s" : L"");
printf(CL("I got %d argument%s:\n"), argc, argc > 1 ? CL("s") : CL(""));
for(i = 0; i < argc; i++)
printf(L" argv[%d] = '%s'\n", i, argv[i]);
printf(CL(" argv[%d] = '%s'\n"), i, argv[i]);
return 0;
}

View file

@ -3,11 +3,11 @@
/**
* Dump memory at given address, should accept 0x prefixes from the command line
*/
int main(int argc, wchar_t **argv)
int main(int argc, char **argv)
{
efi_physical_address_t address =
(argc < 2 ? (efi_physical_address_t)IM : (efi_physical_address_t)atol(argv[1]));
printf(L"%4D", address);
printf("%4D", address);
return 0;
}

View file

@ -31,7 +31,7 @@
#include <uefi.h>
/* this is implemented by the application */
extern int main(int argc, wchar_t **argv);
extern int main(int argc, char_t **argv);
/* definitions for elf relocations */
typedef uint64_t Elf64_Xword;
@ -64,6 +64,9 @@ efi_system_table_t *ST = NULL;
efi_boot_services_t *BS = NULL;
efi_runtime_services_t *RT = NULL;
efi_loaded_image_protocol_t *LIP = NULL;
#if USE_UTF8
char *__argvutf8 = NULL;
#endif
/* we only need one .o file, so use inline Assembly here */
void bootstrap()
@ -153,10 +156,13 @@ int uefi_init (
efi_shell_interface_protocol_t *shi = NULL;
efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
efi_status_t status;
int argc = 0;
int argc = 0, i;
wchar_t **argv = NULL;
#if USE_UTF8
int ret, j;
char *s;
#endif
#ifndef __clang__
int i;
long relsz = 0, relent = 0;
Elf64_Rel *rel = 0;
uintptr_t *addr;
@ -177,6 +183,8 @@ int uefi_init (
relsz -= relent;
}
}
#else
(void)i;
#endif
/* save EFI pointers and loaded image into globals */
IM = image;
@ -193,5 +201,32 @@ int uefi_init (
if(!EFI_ERROR(status) && shi) { argc = shi->Argc; argv = shi->Argv; }
}
/* call main */
#if USE_UTF8
if(argc && argv) {
ret = (argc + 1) * (sizeof(uintptr_t) + 1);
for(i = 0; i < argc; i++)
for(j = 0; argv[i] && argv[i][j]; j++)
ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3);
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, ret, (void **)&__argvutf8);
if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; }
else {
s = __argvutf8 + argc * sizeof(uintptr_t);
*((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t);
for(i = 0; i < argc; i++) {
*((uintptr_t*)(__argvutf8 + i * sizeof(uintptr_t))) = (uintptr_t)s;
for(j = 0; argv[i] && argv[i][j]; j++) {
if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else
if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else
{ *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; }
}
*s++ = 0;
}
}
}
ret = main(argc, (char**)__argvutf8);
if(__argvutf8) BS->FreePool(__argvutf8);
return ret;
#else
return main(argc, argv);
#endif
}

View file

@ -31,7 +31,7 @@
#include <uefi.h>
/* this is implemented by the application */
extern int main(int argc, wchar_t **argv);
extern int main(int argc, char_t **argv);
/* definitions for elf relocations */
typedef uint64_t Elf64_Xword;
@ -64,6 +64,9 @@ efi_system_table_t *ST = NULL;
efi_boot_services_t *BS = NULL;
efi_runtime_services_t *RT = NULL;
efi_loaded_image_protocol_t *LIP = NULL;
#if USE_UTF8
char *__argvutf8 = NULL;
#endif
/* we only need one .o file, so use inline Assembly here */
void bootstrap()
@ -147,10 +150,13 @@ int uefi_init (
efi_shell_interface_protocol_t *shi = NULL;
efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
efi_status_t status;
int argc = 0;
int argc = 0, i;
wchar_t **argv = NULL;
#if USE_UTF8
int ret, j;
char *s;
#endif
#ifndef __clang__
int i;
long relsz = 0, relent = 0;
Elf64_Rel *rel = 0;
uintptr_t *addr;
@ -171,6 +177,8 @@ int uefi_init (
relsz -= relent;
}
}
#else
(void)i;
#endif
/* save EFI pointers and loaded image into globals */
IM = image;
@ -187,5 +195,32 @@ int uefi_init (
if(!EFI_ERROR(status) && shi) { argc = shi->Argc; argv = shi->Argv; }
}
/* call main */
#if USE_UTF8
if(argc && argv) {
ret = (argc + 1) * (sizeof(uintptr_t) + 1);
for(i = 0; i < argc; i++)
for(j = 0; argv[i] && argv[i][j]; j++)
ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3);
status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, ret, (void **)&__argvutf8);
if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; }
else {
s = __argvutf8 + argc * sizeof(uintptr_t);
*((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t);
for(i = 0; i < argc; i++) {
*((uintptr_t*)(__argvutf8 + i * sizeof(uintptr_t))) = (uintptr_t)s;
for(j = 0; argv[i] && argv[i][j]; j++) {
if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else
if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else
{ *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; }
}
*s++ = 0;
}
}
}
ret = main(argc, (char**)__argvutf8);
if(__argvutf8) BS->FreePool(__argvutf8);
return ret;
#else
return main(argc, argv);
#endif
}

View file

@ -33,9 +33,9 @@
extern void __stdio_seterrno(efi_status_t status);
struct dirent __dirent;
DIR *opendir (const wchar_t *__name)
DIR *opendir (const char_t *__name)
{
DIR *dp = (DIR*)fopen(__name, L"rd");
DIR *dp = (DIR*)fopen(__name, CL("rd"));
rewinddir(dp);
return dp;
}
@ -53,8 +53,12 @@ struct dirent *readdir (DIR *__dirp)
return NULL;
}
__dirent.d_type = info.Attribute & EFI_FILE_DIRECTORY ? DT_DIR : DT_REG;
#if USE_UTF8
__dirent.d_reclen = wcstombs(__dirent.d_name, info.FileName, FILENAME_MAX - 1);
#else
__dirent.d_reclen = strlen(info.FileName);
strcpy(__dirent.d_name, info.FileName);
strncpy(__dirent.d_name, info.FileName, FILENAME_MAX - 1);
#endif
return &__dirent;
}

View file

@ -70,7 +70,7 @@ int fstat (FILE *__f, struct stat *__buf)
return 0;
}
int stat (const wchar_t *__file, struct stat *__buf)
int stat (const char_t *__file, struct stat *__buf)
{
int ret;
FILE *f;
@ -79,7 +79,7 @@ int stat (const wchar_t *__file, struct stat *__buf)
errno = EINVAL;
return -1;
}
f = fopen(__file, L"*");
f = fopen(__file, CL("*"));
if(!f) {
memset(__buf, 0, sizeof(struct stat));
return -1;
@ -89,7 +89,7 @@ int stat (const wchar_t *__file, struct stat *__buf)
return ret;
}
extern int mkdir (const wchar_t *__path, mode_t __mode)
extern int mkdir (const char_t *__path, mode_t __mode)
{
FILE *f;
(void)__mode;
@ -97,7 +97,7 @@ extern int mkdir (const wchar_t *__path, mode_t __mode)
errno = EINVAL;
return -1;
}
f = fopen(__path, L"wd");
f = fopen(__path, CL("wd"));
if(!f) {
return -1;
}

View file

@ -35,6 +35,19 @@ static efi_serial_io_protocol_t *__ser = NULL;
static efi_block_io_t **__blk_devs = NULL;
static uintn_t __blk_ndevs = 0;
void __stdio_cleanup()
{
#if USE_UTF8
if(__argvutf8)
free(__argvutf8);
#endif
if(__blk_devs) {
free(__blk_devs);
__blk_devs = NULL;
__blk_ndevs = 0;
}
}
void __stdio_seterrno(efi_status_t status)
{
switch((int)(status & 0xffff)) {
@ -79,13 +92,13 @@ int fflush (FILE *__stream)
return !EFI_ERROR(status);
}
int __remove (const wchar_t *__filename, int isdir)
int __remove (const char_t *__filename, int isdir)
{
efi_status_t status;
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
efi_file_info_t info;
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i;
FILE *f = fopen(__filename, L"r");
FILE *f = fopen(__filename, CL("r"));
if(f == stdin || f == stdout || f == stderr || (__ser && f == (FILE*)__ser)) {
errno = EBADF;
return 1;
@ -118,12 +131,12 @@ err: __stdio_seterrno(status);
return 0;
}
int remove (const wchar_t *__filename)
int remove (const char_t *__filename)
{
return __remove(__filename, -1);
}
FILE *fopen (const wchar_t *__filename, const wchar_t *__modes)
FILE *fopen (const char_t *__filename, const char_t *__modes)
{
FILE *ret;
efi_status_t status;
@ -132,25 +145,27 @@ FILE *fopen (const wchar_t *__filename, const wchar_t *__modes)
efi_guid_t infGuid = EFI_FILE_INFO_GUID;
efi_file_info_t info;
uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), par, i;
#if USE_UTF8
wchar_t wcname[BUFSIZ];
#endif
if(!__filename || !*__filename || !__modes || !*__modes) {
errno = EINVAL;
return NULL;
}
/* fake some device names. UEFI has no concept of device files */
if(!strcmp(__filename, L"/dev/stdin")) {
if(__modes[0] == L'w' || __modes[0] == L'a') { errno = EPERM; return NULL; }
if(!strcmp(__filename, CL("/dev/stdin"))) {
if(__modes[0] == CL('w') || __modes[0] == CL('a')) { errno = EPERM; return NULL; }
return stdin;
}
if(!strcmp(__filename, L"/dev/stdout")) {
if(__modes[0] == L'r') { errno = EPERM; return NULL; }
if(!strcmp(__filename, CL("/dev/stdout"))) {
if(__modes[0] == CL('r')) { errno = EPERM; return NULL; }
return stdout;
}
if(!strcmp(__filename, L"/dev/stderr")) {
if(__modes[0] == L'r') { errno = EPERM; return NULL; }
if(!strcmp(__filename, CL("/dev/stderr"))) {
if(__modes[0] == CL('r')) { errno = EPERM; return NULL; }
return stderr;
}
if(!memcmp(__filename, L"/dev/serial", 22)) {
if(!memcmp(__filename, CL("/dev/serial"), 11 * sizeof(char_t))) {
par = atol(__filename + 11);
if(!__ser) {
efi_guid_t serGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
@ -160,7 +175,7 @@ FILE *fopen (const wchar_t *__filename, const wchar_t *__modes)
__ser->SetAttributes(__ser, par > 9600 ? par : 115200, 0, 1000, NoParity, 8, OneStopBit);
return (FILE*)__ser;
}
if(!memcmp(__filename, L"/dev/disk", 18)) {
if(!memcmp(__filename, CL("/dev/disk"), 9 * sizeof(char_t))) {
par = atol(__filename + 9);
if(!__blk_ndevs) {
efi_guid_t bioGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
@ -202,22 +217,27 @@ FILE *fopen (const wchar_t *__filename, const wchar_t *__modes)
errno = 0;
ret = (FILE*)malloc(sizeof(FILE));
if(!ret) return NULL;
#if USE_UTF8
mbstowcs((wchar_t*)&wcname, __filename, BUFSIZ - 1);
status = __root_dir->Open(__root_dir, &ret, (wchar_t*)&wcname,
#else
status = __root_dir->Open(__root_dir, &ret, (wchar_t*)__filename,
__modes[0] == L'w' ? (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE) : EFI_FILE_MODE_READ,
__modes[1] == L'd' ? EFI_FILE_DIRECTORY : 0);
#endif
__modes[0] == CL('w') ? (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE) : EFI_FILE_MODE_READ,
__modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0);
if(EFI_ERROR(status)) {
err: __stdio_seterrno(status);
free(ret); ret = NULL;
}
status = ret->GetInfo(ret, &infGuid, &fsiz, &info);
if(EFI_ERROR(status)) goto err;
if(__modes[1] == L'd' && !(info.Attribute & EFI_FILE_DIRECTORY)) {
if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) {
free(ret); errno = ENOTDIR; return NULL;
}
if(__modes[1] != L'd' && (info.Attribute & EFI_FILE_DIRECTORY)) {
if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) {
free(ret); errno = EISDIR; return NULL;
}
if(__modes[0] == L'a') fseek(ret, 0, SEEK_END);
if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END);
return ret;
}
@ -377,15 +397,15 @@ err: __stdio_seterrno(status);
return info.FileSize == off;
}
int vsnprintf(wchar_t *dst, size_t maxlen, const wchar_t *fmt, __builtin_va_list args)
int vsnprintf(char_t *dst, size_t maxlen, const char_t *fmt, __builtin_va_list args)
{
#define needsescape(a) (a==L'\"' || a==L'\\' || a==L'\a' || a==L'\b' || a==L'\033' || a=='\f' || \
a==L'\r' || a==L'\n' || a==L'\t' || a=='\v')
#define needsescape(a) (a==CL('\"') || a==CL('\\') || a==CL('\a') || a==CL('\b') || a==CL('\033') || a==CL('\f') || \
a==CL('\r') || a==CL('\n') || a==CL('\t') || a==CL('\v'))
efi_physical_address_t m;
uint8_t *mem;
int64_t arg;
int len, sign, i, j;
wchar_t *p, *orig=dst, *end = dst + maxlen - 1, tmpstr[19], pad=' ', n;
char_t *p, *orig=dst, *end = dst + maxlen - 1, tmpstr[19], pad=CL(' '), n;
char *c;
if(dst==NULL || fmt==NULL)
@ -393,37 +413,30 @@ int vsnprintf(wchar_t *dst, size_t maxlen, const wchar_t *fmt, __builtin_va_list
arg = 0;
while(*fmt && dst < end) {
if(*fmt==L'%') {
if(*fmt==CL('%')) {
fmt++;
if(*fmt==L'%') goto put;
if(*fmt==CL('%')) goto put;
len=0;
if(*fmt==L'0') pad=L'0';
while(*fmt>=L'0' && *fmt<=L'9') {
if(*fmt==CL('0')) pad=CL('0');
while(*fmt>=CL('0') && *fmt<=CL('9')) {
len *= 10;
len += *fmt-L'0';
len += *fmt-CL('0');
fmt++;
}
if(*fmt==L'l') fmt++;
if(*fmt==L'c') {
if(*fmt==CL('l')) fmt++;
if(*fmt==CL('c')) {
arg = __builtin_va_arg(args, int);
#if USE_UTF8
if(arg<0x80) { *dst++ = arg; } else
if(arg<0x800) { *dst++ = ((arg>>6)&0x1F)|0xC0; *dst++ = (arg&0x3F)|0x80; } else
{ *dst++ = ((arg>>12)&0x0F)|0xE0; *dst++ = ((arg>>6)&0x3F)|0x80; *dst++ = (arg&0x3F)|0x80; }
#else
*dst++ = (wchar_t)(arg & 0xffff);
#endif
fmt++;
continue;
} else
if(*fmt==L'C') {
c = __builtin_va_arg(args, char*);
arg = *c;
if((*c & 128) != 0) {
if((*c & 32) == 0 ) { arg = ((*c & 0x1F)<<6)|(*(c+1) & 0x3F); } else
if((*c & 16) == 0 ) { arg = ((*c & 0xF)<<12)|((*(c+1) & 0x3F)<<6)|(*(c+2) & 0x3F); } else
if((*c & 8) == 0 ) { arg = ((*c & 0x7)<<18)|((*(c+1) & 0x3F)<<12)|((*(c+2) & 0x3F)<<6)|(*(c+3) & 0x3F); }
else arg = L'?';
}
*dst++ = (wchar_t)(arg & 0xffff);
fmt++;
continue;
} else
if(*fmt==L'd') {
if(*fmt==CL('d')) {
arg = __builtin_va_arg(args, int);
sign=0;
if((int)arg<0) {
@ -436,11 +449,11 @@ int vsnprintf(wchar_t *dst, size_t maxlen, const wchar_t *fmt, __builtin_va_list
i=18;
tmpstr[i]=0;
do {
tmpstr[--i]=L'0'+(arg%10);
tmpstr[--i]=CL('0')+(arg%10);
arg/=10;
} while(arg!=0 && i>0);
if(sign) {
tmpstr[--i]=L'-';
tmpstr[--i]=CL('-');
}
if(len>0 && len<18) {
while(i>18-len) {
@ -450,53 +463,53 @@ int vsnprintf(wchar_t *dst, size_t maxlen, const wchar_t *fmt, __builtin_va_list
p=&tmpstr[i];
goto copystring;
} else
if(*fmt==L'p' || *fmt==L'P') {
if(*fmt==CL('p')) {
arg = __builtin_va_arg(args, uint64_t);
len = 16; pad = L'0'; goto hex;
len = 16; pad = CL('0'); goto hex;
} else
if(*fmt==L'x' || *fmt==L'X' || *fmt==L'p') {
if(*fmt==CL('x') || *fmt==CL('X')) {
arg = __builtin_va_arg(args, long int);
if(*fmt==L'p') { len = 16; pad = L'0'; }
hex: i=16;
tmpstr[i]=0;
do {
n=arg & 0xf;
/* 0-9 => '0'-'9', 10-15 => 'A'-'F' */
tmpstr[--i]=n+(n>9?(*fmt==L'X'?0x37:0x57):0x30);
tmpstr[--i]=n+(n>9?(*fmt==CL('X')?0x37:0x57):0x30);
arg>>=4;
} while(arg!=0 && i>0);
/* padding, only leading zeros */
if(len>0 && len<=16) {
while(i>16-len) {
tmpstr[--i]=L'0';
tmpstr[--i]=CL('0');
}
}
p=&tmpstr[i];
goto copystring;
} else
if(*fmt==L's' || *fmt==L'q') {
p = __builtin_va_arg(args, wchar_t*);
if(*fmt==CL('s') || *fmt==CL('q')) {
p = __builtin_va_arg(args, char_t*);
copystring: if(p==NULL) {
p=L"(null)";
p=CL("(null)");
}
while(*p && dst + 2 < end) {
if(*fmt==L'q' && needsescape(*p)) {
*dst++ = L'\\';
if(*fmt==CL('q') && needsescape(*p)) {
*dst++ = CL('\\');
switch(*p) {
case L'\a': *dst++ = L'a'; break;
case L'\b': *dst++ = L'b'; break;
case L'\e': *dst++ = L'e'; break;
case L'\f': *dst++ = L'f'; break;
case L'\n': *dst++ = L'n'; break;
case L'\r': *dst++ = L'r'; break;
case L'\t': *dst++ = L't'; break;
case L'\v': *dst++ = L'v'; break;
case CL('\a'): *dst++ = CL('a'); break;
case CL('\b'): *dst++ = CL('b'); break;
case CL('\e'): *dst++ = CL('e'); break;
case CL('\f'): *dst++ = CL('f'); break;
case CL('\n'): *dst++ = CL('n'); break;
case CL('\r'): *dst++ = CL('r'); break;
case CL('\t'): *dst++ = CL('t'); break;
case CL('\v'): *dst++ = CL('v'); break;
default: *dst++ = *p++; break;
}
} else
*dst++ = *p++;
}
} else
#if !defined(USE_UTF8) || !USE_UTF8
if(*fmt==L'S' || *fmt==L'Q') {
c = __builtin_va_arg(args, char*);
if(c==NULL) goto copystring;
@ -537,33 +550,34 @@ copystring: if(p==NULL) {
}
}
} else
if(*fmt==L'D') {
#endif
if(*fmt==CL('D')) {
m = __builtin_va_arg(args, efi_physical_address_t);
for(j = 0; j < (len < 1 ? 1 : (len > 16 ? 16 : len)); j++) {
for(i = 44; i >= 0; i -= 4) {
n = (m >> i) & 15; *dst++ = n + (n>9?0x37:0x30);
if(dst >= end) goto zro;
}
*dst++ = L':'; if(dst >= end) goto zro;
*dst++ = L' '; if(dst >= end) goto zro;
*dst++ = CL(':'); if(dst >= end) goto zro;
*dst++ = CL(' '); if(dst >= end) goto zro;
mem = (uint8_t*)m;
for(i = 0; i < 16; i++) {
n = (mem[i] >> 4) & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro;
n = mem[i] & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro;
*dst++ = L' ';if(dst >= end) goto zro;
*dst++ = CL(' ');if(dst >= end) goto zro;
}
*dst++ = L' '; if(dst >= end) goto zro;
*dst++ = CL(' '); if(dst >= end) goto zro;
for(i = 0; i < 16; i++) {
*dst++ = (mem[i] < 32 || mem[i] >= 127 ? L'.' : mem[i]);
*dst++ = (mem[i] < 32 || mem[i] >= 127 ? CL('.') : mem[i]);
if(dst >= end) goto zro;
}
*dst++ = L'\r'; if(dst >= end) goto zro;
*dst++ = L'\n'; if(dst >= end) goto zro;
*dst++ = CL('\r'); if(dst >= end) goto zro;
*dst++ = CL('\n'); if(dst >= end) goto zro;
m += 16;
}
}
} else {
put: if(*fmt == L'\n') *dst++ = L'\r';
put: if(*fmt == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r');
*dst++ = *fmt;
}
fmt++;
@ -573,48 +587,59 @@ zro:*dst=0;
#undef needsescape
}
int vsprintf(wchar_t *dst, const wchar_t *fmt, __builtin_va_list args)
int vsprintf(char_t *dst, const char_t *fmt, __builtin_va_list args)
{
return vsnprintf(dst, BUFSIZ, fmt, args);
}
int sprintf(wchar_t *dst, const wchar_t* fmt, ...)
int sprintf(char_t *dst, const char_t* fmt, ...)
{
__builtin_va_list args;
__builtin_va_start(args, fmt);
return vsnprintf(dst, BUFSIZ, fmt, args);
}
int snprintf(wchar_t *dst, size_t maxlen, const wchar_t* fmt, ...)
int snprintf(char_t *dst, size_t maxlen, const char_t* fmt, ...)
{
__builtin_va_list args;
__builtin_va_start(args, fmt);
return vsnprintf(dst, maxlen, fmt, args);
}
int vprintf(const wchar_t* fmt, __builtin_va_list args)
int vprintf(const char_t* fmt, __builtin_va_list args)
{
wchar_t dst[BUFSIZ];
int ret;
wchar_t dst[BUFSIZ];
#if USE_UTF8
char_t tmp[BUFSIZ];
ret = vsnprintf(tmp, sizeof(tmp), fmt, args);
mbstowcs(dst, tmp, BUFSIZ - 1);
#else
ret = vsnprintf(dst, sizeof(dst), fmt, args);
#endif
ST->ConOut->OutputString(ST->ConOut, (wchar_t *)&dst);
return ret;
}
int printf(const wchar_t* fmt, ...)
int printf(const char_t* fmt, ...)
{
__builtin_va_list args;
__builtin_va_start(args, fmt);
return vprintf(fmt, args);
}
int vfprintf (FILE *__stream, const wchar_t *__format, __builtin_va_list args)
int vfprintf (FILE *__stream, const char_t *__format, __builtin_va_list args)
{
wchar_t dst[BUFSIZ];
char_t tmp[BUFSIZ];
uintn_t ret, bs, i;
if(__stream == stdin) return 0;
#if USE_UTF8
ret = vsnprintf(tmp, sizeof(tmp), __format, args);
ret = mbstowcs(dst, tmp, BUFSIZ - 1);
#else
ret = vsnprintf(dst, sizeof(dst), __format, args);
if(ret < 1) return 0;
#endif
if(ret < 1 || __stream == stdin) return 0;
for(i = 0; i < __blk_ndevs; i++)
if(__stream == (FILE*)__blk_devs[i]) {
errno = EBADF;
@ -624,14 +649,21 @@ int vfprintf (FILE *__stream, const wchar_t *__format, __builtin_va_list args)
ST->ConOut->OutputString(ST->ConOut, (wchar_t*)&dst);
else if(__stream == stderr)
ST->StdErr->OutputString(ST->StdErr, (wchar_t*)&dst);
else if(__ser && __stream == (FILE*)__ser)
__ser->Write(__ser, &ret, (void*)&dst);
else
else if(__ser && __stream == (FILE*)__ser) {
#if !defined(USE_UTF8) || !USE_UTF8
wcstombs((char*)&tmp, dst, BUFSIZ - 1);
#endif
__ser->Write(__ser, &ret, (void*)&tmp);
} else
#if USE_UTF8
__stream->Write(__stream, &ret, (void*)&tmp);
#else
__stream->Write(__stream, &ret, (void*)&dst);
#endif
return ret;
}
int fprintf (FILE *__stream, const wchar_t *__format, ...)
int fprintf (FILE *__stream, const char_t *__format, ...)
{
__builtin_va_list args;
__builtin_va_start(args, __format);
@ -665,22 +697,3 @@ int putchar (int __c)
ST->ConOut->OutputString(ST->ConOut, (__c == L'\n' ? (wchar_t*)L"\r\n" : (wchar_t*)&tmp));
return (int)tmp[0];
}
int exit_bs()
{
efi_status_t status;
efi_memory_descriptor_t *memory_map = NULL;
uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0, i;
if(__blk_devs) {
free(__blk_devs);
__blk_devs = NULL;
__blk_ndevs = 0;
}
while(cnt--) {
status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL);
if (status!=EFI_BUFFER_TOO_SMALL) break;
status = BS->ExitBootServices(IM, map_key);
if(!EFI_ERROR(status)) return 0;
}
return (int)(status & 0xffff);
}

View file

@ -32,43 +32,44 @@
int errno = 0;
static uint64_t __srand_seed = 6364136223846793005ULL;
extern void __stdio_cleanup();
int atoi(const wchar_t *s)
int atoi(const char_t *s)
{
return (int)atol(s);
}
int64_t atol(const wchar_t *s)
int64_t atol(const char_t *s)
{
int64_t sign = 1;
if(!s || !*s) return 0;
if(*s == L'-') { sign = -1; s++; }
if(s[0] == L'0') {
if(s[1] == L'x')
return strtol(s + 2, NULL, 16);
if(s[1] >= L'0' && s[1] <= L'7')
return strtol(s, NULL, 8);
if(*s == CL('-')) { sign = -1; s++; }
if(s[0] == CL('0')) {
if(s[1] == CL('x'))
return strtol(s + 2, NULL, 16) * sign;
if(s[1] >= CL('0') && s[1] <= CL('7'))
return strtol(s, NULL, 8) * sign;
}
return strtol(s, NULL, 10) * sign;
}
int64_t strtol (const wchar_t *s, wchar_t **__endptr, int __base)
int64_t strtol (const char_t *s, char_t **__endptr, int __base)
{
int64_t v=0, sign = 1;
if(!s || !*s) return 0;
if(*s == L'-') { sign = -1; s++; }
while(!(*s < L'0' || (__base < 10 && *s >= __base + L'0') || (__base >= 10 && ((*s > L'9' && *s < L'A') ||
(*s > L'F' && *s < L'a') || *s > L'f')))) {
if(*s == CL('-')) { sign = -1; s++; }
while(!(*s < CL('0') || (__base < 10 && *s >= __base + CL('0')) || (__base >= 10 && ((*s > CL('9') && *s < CL('A')) ||
(*s > CL('F') && *s < CL('a')) || *s > CL('f'))))) {
v *= __base;
if(*s >= L'0' && *s <= (__base < 10 ? __base + L'0' : L'9'))
v += (*s)-L'0';
else if(__base == 16 && *s >= L'a' && *s <= L'f')
v += (*s)-L'a'+10;
else if(__base == 16 && *s >= L'A' && *s <= L'F')
v += (*s)-L'A'+10;
if(*s >= CL('0') && *s <= (__base < 10 ? __base + CL('0') : CL('9')))
v += (*s)-CL('0');
else if(__base == 16 && *s >= CL('a') && *s <= CL('f'))
v += (*s)-CL('a')+10;
else if(__base == 16 && *s >= CL('A') && *s <= CL('F'))
v += (*s)-CL('A')+10;
s++;
};
if(__endptr) *__endptr = (wchar_t*)s;
if(__endptr) *__endptr = (char_t*)s;
return v * sign;
}
@ -112,14 +113,31 @@ void free (void *__ptr)
void abort ()
{
__stdio_cleanup();
BS->Exit(IM, EFI_ABORTED, 0, NULL);
}
void exit (int __status)
{
__stdio_cleanup();
BS->Exit(IM, !__status ? 0 : (__status < 0 ? EFIERR(-__status) : EFIERR(__status)), 0, NULL);
}
int exit_bs()
{
efi_status_t status;
efi_memory_descriptor_t *memory_map = NULL;
uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0, i;
__stdio_cleanup();
while(cnt--) {
status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL);
if (status!=EFI_BUFFER_TOO_SMALL) break;
status = BS->ExitBootServices(IM, map_key);
if(!EFI_ERROR(status)) return 0;
}
return (int)(status & 0xffff);
}
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, __compar_fn_t cmp)
{
uint64_t s=0, e=nmemb, m;
@ -156,15 +174,17 @@ int mbtowc (wchar_t * __pwc, const char *s, size_t n)
{
wchar_t arg;
const char *orig = s;
int ret = 1;
if(!s || !*s) return 0;
arg = (wchar_t)*s;
if((*s & 128) != 0) {
if((*s & 32) == 0 && n > 0) { arg = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); } else
if((*s & 16) == 0 && n > 1) { arg = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); } else
if((*s & 8) == 0 && n > 2) { arg = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); }
if((*s & 32) == 0 && n > 0) { arg = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); ret = 2; } else
if((*s & 16) == 0 && n > 1) { arg = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); ret = 3; } else
if((*s & 8) == 0 && n > 2) { arg = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); ret = 4; }
else return -1;
}
if(__pwc) *__pwc = arg;
return s - orig;
return ret;
}
int wctomb (char *s, wchar_t u)
@ -190,14 +210,14 @@ size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n)
{
int r;
wchar_t *orig = __pwcs;
size_t ret = 0;
if(!__s || !*__s) return 0;
while(*__s) {
r = mbtowc(__pwcs, __s, __n - ret);
r = mbtowc(__pwcs, __s, __n - (__pwcs - orig));
if(r < 0) return (size_t)-1;
__pwcs++;
__s += r;
};
}
*__pwcs = 0;
return __pwcs - orig;
}
@ -206,12 +226,13 @@ size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n)
int r;
char *orig = __s;
if(!__s || !__pwcs || !*__pwcs) return 0;
while(*__pwcs && (__s - orig + 3 < __n)) {
while(*__pwcs && (__s - orig + 4 < __n)) {
r = wctomb(__s, *__pwcs);
if(r < 0) return (size_t)-1;
__pwcs++;
__s += r;
};
}
*__s = 0;
return __s - orig;
}
@ -235,12 +256,19 @@ int rand()
return ret;
}
uint8_t *getenv(wchar_t *name, uintn_t *len)
uint8_t *getenv(char_t *name, uintn_t *len)
{
efi_guid_t globGuid = EFI_GLOBAL_VARIABLE;
uint8_t tmp[EFI_MAXIMUM_VARIABLE_SIZE], *ret;
uint32_t attr;
efi_status_t status = RT->GetVariable(name, &globGuid, &attr, len, &tmp);
efi_status_t status;
#if USE_UTF8
wchar_t wcname[256];
mbstowcs((wchar_t*)&wcname, name, 256);
status = RT->GetVariable((wchar_t*)&wcname, &globGuid, &attr, len, &tmp);
#else
status = RT->GetVariable(name, &globGuid, &attr, len, &tmp);
#endif
if(EFI_ERROR(status) || *len < 1 || !(ret = malloc((*len) + 1))) {
*len = 0;
return NULL;
@ -250,9 +278,16 @@ uint8_t *getenv(wchar_t *name, uintn_t *len)
return ret;
}
int setenv(wchar_t *name, uintn_t len, uint8_t *data)
int setenv(char_t *name, uintn_t len, uint8_t *data)
{
efi_guid_t globGuid = EFI_GLOBAL_VARIABLE;
efi_status_t status = RT->SetVariable(name, &globGuid, 0, len, data);
efi_status_t status;
#if USE_UTF8
wchar_t wcname[256];
mbstowcs((wchar_t*)&wcname, name, 256);
status = RT->SetVariable(wcname, &globGuid, 0, len, data);
#else
status = RT->SetVariable(name, &globGuid, 0, len, data);
#endif
return !EFI_ERROR(status);
}

View file

@ -119,7 +119,7 @@ void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl)
return NULL;
}
wchar_t *strcpy(wchar_t *dst, const wchar_t *src)
char_t *strcpy(char_t *dst, const char_t *src)
{
if(src && dst) {
while(*src) {*dst++=*src++;} *dst=0;
@ -127,16 +127,16 @@ wchar_t *strcpy(wchar_t *dst, const wchar_t *src)
return dst;
}
wchar_t *strncpy(wchar_t *dst, const wchar_t *src, size_t n)
char_t *strncpy(char_t *dst, const char_t *src, size_t n)
{
const wchar_t *e = src+n;
const char_t *e = src+n;
if(src && dst && n>0) {
while(*src && src<e) {*dst++=*src++;} *dst=0;
}
return dst;
}
wchar_t *strcat(wchar_t *dst, const wchar_t *src)
char_t *strcat(char_t *dst, const char_t *src)
{
if(src && dst) {
dst += strlen(dst);
@ -145,7 +145,7 @@ wchar_t *strcat(wchar_t *dst, const wchar_t *src)
return dst;
}
int strcmp(const wchar_t *s1, const wchar_t *s2)
int strcmp(const char_t *s1, const char_t *s2)
{
if(s1 && s2 && s1!=s2) {
do{if(*s1!=*s2){return *s1-*s2;}s1++;s2++;}while(*s1!=0);
@ -154,9 +154,9 @@ int strcmp(const wchar_t *s1, const wchar_t *s2)
return 0;
}
wchar_t *strncat(wchar_t *dst, const wchar_t *src, size_t n)
char_t *strncat(char_t *dst, const char_t *src, size_t n)
{
const wchar_t *e = src+n;
const char_t *e = src+n;
if(src && dst && n>0) {
dst += strlen(dst);
while(*src && src<e) {*dst++=*src++;} *dst=0;
@ -164,9 +164,9 @@ wchar_t *strncat(wchar_t *dst, const wchar_t *src, size_t n)
return dst;
}
int strncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
int strncmp(const char_t *s1, const char_t *s2, size_t n)
{
const wchar_t *e = s1+n;
const char_t *e = s1+n;
if(s1 && s2 && s1!=s2 && n>0) {
do{if(*s1!=*s2){return *s1-*s2;}s1++;s2++;}while(*s1!=0 && s1<e);
return *s1-*s2;
@ -174,52 +174,52 @@ int strncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
return 0;
}
wchar_t *strdup(const wchar_t *s)
char_t *strdup(const char_t *s)
{
int i = (strlen(s)+1) * sizeof(wchar_t);
wchar_t *s2 = (wchar_t *)malloc(i);
int i = (strlen(s)+1) * sizeof(char_t);
char_t *s2 = (char_t *)malloc(i);
if(s2 != NULL) memcpy(s2, (void*)s, i);
return s2;
}
wchar_t *strchr(const wchar_t *s, int c)
char_t *strchr(const char_t *s, int c)
{
if(s) {
while(*s) {
if(*s == (wchar_t)c) return (wchar_t*)s;
if(*s == (char_t)c) return (char_t*)s;
s++;
}
}
return NULL;
}
wchar_t *strrchr(const wchar_t *s, int c)
char_t *strrchr(const char_t *s, int c)
{
wchar_t *e;
char_t *e;
if(s) {
e = (wchar_t*)s + strlen(s) - 1;
e = (char_t*)s + strlen(s) - 1;
while(s < e) {
if(*e == (wchar_t)c) return e;
if(*e == (char_t)c) return e;
s--;
}
}
return NULL;
}
wchar_t *strstr(const wchar_t *haystack, const wchar_t *needle)
char_t *strstr(const char_t *haystack, const char_t *needle)
{
return memmem(haystack, strlen(haystack) * sizeof(wchar_t), needle, strlen(needle) * sizeof(wchar_t));
return memmem(haystack, strlen(haystack) * sizeof(char_t), needle, strlen(needle) * sizeof(char_t));
}
wchar_t *_strtok_r(wchar_t *s, const wchar_t *d, wchar_t **p)
char_t *_strtok_r(char_t *s, const char_t *d, char_t **p)
{
int c, sc;
wchar_t *tok, *sp;
char_t *tok, *sp;
if(d == NULL || (s == NULL && (s=*p) == NULL)) return NULL;
again:
c = *s++;
for(sp = (wchar_t *)d; (sc=*sp++)!=0;) {
for(sp = (char_t *)d; (sc=*sp++)!=0;) {
if(c == sc) { *p=s; *(s-1)=0; return s-1; }
}
@ -227,7 +227,7 @@ again:
tok = s-1;
while(1) {
c = *s++;
sp = (wchar_t *)d;
sp = (char_t *)d;
do {
if((sc=*sp++) == c) {
if(c == 0) s = NULL;
@ -240,18 +240,18 @@ again:
return NULL;
}
wchar_t *strtok(wchar_t *s, const wchar_t *delim)
char_t *strtok(char_t *s, const char_t *delim)
{
wchar_t *p = s;
char_t *p = s;
return _strtok_r (s, delim, &p);
}
wchar_t *strtok_r(wchar_t *s, const wchar_t *delim, wchar_t **ptr)
char_t *strtok_r(char_t *s, const char_t *delim, char_t **ptr)
{
return _strtok_r (s, delim, ptr);
}
size_t strlen (const wchar_t *__s)
size_t strlen (const char_t *__s)
{
size_t ret;

View file

@ -35,6 +35,9 @@
extern "C" {
#endif
/* comment out this if you want to use wchar_t in your application */
#define USE_UTF8 1
/* get these from the compiler */
typedef char int8_t;
typedef unsigned char uint8_t;
@ -75,6 +78,14 @@ typedef uint64_t efi_physical_address_t;
typedef uint64_t efi_virtual_address_t;
typedef void *efi_handle_t;
typedef void *efi_event_t;
#if USE_UTF8
typedef char char_t;
#define CL(a) a
extern char *__argvutf8;
#else
typedef wchar_t char_t;
#define CL(a) L ## a
#endif
typedef struct {
uint32_t Data1;
@ -1187,10 +1198,10 @@ typedef struct {
struct dirent {
unsigned short int d_reclen;
unsigned char d_type;
wchar_t d_name[FILENAME_MAX];
char_t d_name[FILENAME_MAX];
};
typedef struct efi_file_handle_s DIR;
extern DIR *opendir (const wchar_t *__name);
extern DIR *opendir (const char_t *__name);
extern struct dirent *readdir (DIR *__dirp);
extern void rewinddir (DIR *__dirp);
extern int closedir (DIR *__dirp);
@ -1235,9 +1246,9 @@ extern int errno;
/* stdlib.h */
#define RAND_MAX 2147483647
typedef int (*__compar_fn_t) (const void *, const void *);
extern int atoi (const wchar_t *__nptr);
extern int64_t atol (const wchar_t *__nptr);
extern int64_t strtol (const wchar_t *__nptr, wchar_t **__endptr, int __base);
extern int atoi (const char_t *__nptr);
extern int64_t atol (const char_t *__nptr);
extern int64_t strtol (const char_t *__nptr, char_t **__endptr, int __base);
extern void *malloc (size_t __size);
extern void *calloc (size_t __nmemb, size_t __size);
extern void *realloc (void *__ptr, size_t __size);
@ -1255,6 +1266,8 @@ extern size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n);
extern size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n);
extern void srand(unsigned int __seed);
extern int rand(void);
extern uint8_t *getenv(char_t *name, uintn_t *len);
extern int setenv(char_t *name, uintn_t len, uint8_t *data);
/* stdio.h */
#ifndef BUFSIZ
@ -1269,27 +1282,25 @@ extern int rand(void);
typedef struct efi_file_handle_s FILE;
extern int fclose (FILE *__stream);
extern int fflush (FILE *__stream);
extern int remove (const wchar_t *__filename);
extern FILE *fopen (const wchar_t *__filename, const wchar_t *__modes);
extern int remove (const char_t *__filename);
extern FILE *fopen (const char_t *__filename, const char_t *__modes);
extern size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream);
extern size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__s);
extern int fseek (FILE *__stream, long int __off, int __whence);
extern long int ftell (FILE *__stream);
extern int feof (FILE *__stream);
extern int fprintf (FILE *__stream, const wchar_t *__format, ...);
extern int printf (const wchar_t *__format, ...);
extern int sprintf (wchar_t *__s, const wchar_t *__format, ...);
extern int vfprintf (FILE *__s, const wchar_t *__format, __builtin_va_list __arg);
extern int vprintf (const wchar_t *__format, __builtin_va_list __arg);
extern int vsprintf (wchar_t *__s, const wchar_t *__format, __builtin_va_list __arg);
extern int snprintf (wchar_t *__s, size_t __maxlen, const wchar_t *__format, ...);
extern int vsnprintf (wchar_t *__s, size_t __maxlen, const wchar_t *__format, __builtin_va_list __arg);
extern int fprintf (FILE *__stream, const char_t *__format, ...);
extern int printf (const char_t *__format, ...);
extern int sprintf (char_t *__s, const char_t *__format, ...);
extern int vfprintf (FILE *__s, const char_t *__format, __builtin_va_list __arg);
extern int vprintf (const char_t *__format, __builtin_va_list __arg);
extern int vsprintf (char_t *__s, const char_t *__format, __builtin_va_list __arg);
extern int snprintf (char_t *__s, size_t __maxlen, const char_t *__format, ...);
extern int vsnprintf (char_t *__s, size_t __maxlen, const char_t *__format, __builtin_va_list __arg);
extern int getchar (void);
/* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */
extern int getchar_ifany (void);
extern int putchar (int __c);
extern uint8_t *getenv(wchar_t *name, uintn_t *len);
extern int setenv(wchar_t *name, uintn_t len, uint8_t *data);
/* string.h */
#ifndef __clang__
@ -1309,19 +1320,19 @@ extern void *memrchr (const void *__s, int __c, size_t __n);
#endif
void *memmem(const void *haystack, size_t hl, const void *needle, size_t nl);
void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl);
extern wchar_t *strcpy (wchar_t *__dest, const wchar_t *__src);
extern wchar_t *strncpy (wchar_t *__dest, const wchar_t *__src, size_t __n);
extern wchar_t *strcat (wchar_t *__dest, const wchar_t *__src);
extern wchar_t *strncat (wchar_t *__dest, const wchar_t *__src, size_t __n);
extern int strcmp (const wchar_t *__s1, const wchar_t *__s2);
extern int strncmp (const wchar_t *__s1, const wchar_t *__s2, size_t __n);
extern wchar_t *strdup (const wchar_t *__s);
extern wchar_t *strchr (const wchar_t *__s, int __c);
extern wchar_t *strrchr (const wchar_t *__s, int __c);
extern wchar_t *strstr (const wchar_t *__haystack, const wchar_t *__needle);
extern wchar_t *strtok (wchar_t *__s, const wchar_t *__delim);
extern wchar_t *strtok_r (wchar_t *__s, const wchar_t *__delim, wchar_t **__save_ptr);
extern size_t strlen (const wchar_t *__s);
extern char_t *strcpy (char_t *__dest, const char_t *__src);
extern char_t *strncpy (char_t *__dest, const char_t *__src, size_t __n);
extern char_t *strcat (char_t *__dest, const char_t *__src);
extern char_t *strncat (char_t *__dest, const char_t *__src, size_t __n);
extern int strcmp (const char_t *__s1, const char_t *__s2);
extern int strncmp (const char_t *__s1, const char_t *__s2, size_t __n);
extern char_t *strdup (const char_t *__s);
extern char_t *strchr (const char_t *__s, int __c);
extern char_t *strrchr (const char_t *__s, int __c);
extern char_t *strstr (const char_t *__haystack, const char_t *__needle);
extern char_t *strtok (char_t *__s, const char_t *__delim);
extern char_t *strtok_r (char_t *__s, const char_t *__delim, char_t **__save_ptr);
extern size_t strlen (const char_t *__s);
/* sys/stat.h */
#define S_IREAD 0400 /* Read by owner. */
@ -1342,9 +1353,9 @@ struct stat {
time_t st_mtime;
time_t st_ctime;
};
extern int stat (const wchar_t *__file, struct stat *__buf);
extern int stat (const char_t *__file, struct stat *__buf);
extern int fstat (FILE *__f, struct stat *__buf);
extern int mkdir (const wchar_t *__path, mode_t __mode);
extern int mkdir (const char_t *__path, mode_t __mode);
/* time.h */
struct tm {