diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index a784916d..645cfa18 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -9,8 +9,9 @@ "cStandard": "c99", "cppStandard": "c++98", "intelliSenseMode": "linux-clang-x86", - "compilerPath": "" + "compilerPath": "", + "configurationProvider": "ms-vscode.makefile-tools" } ], "version": 4 -} +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 46e0a2b2..80c6ee7a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -57,7 +57,8 @@ "gxpriv.h": "c", "osfastcast.h": "c", "osfont.h": "c", - "arq.h": "c" + "arq.h": "c", + "string.h": "c" }, "files.autoSave": "onFocusChange", "files.insertFinalNewline": true, diff --git a/configure.py b/configure.py index bb6af526..f664fa79 100755 --- a/configure.py +++ b/configure.py @@ -872,15 +872,15 @@ LIBS = [ ["Runtime/file_io", True], ["Runtime/errno", True], ["Runtime/FILE_POS", True], - "Runtime/mbstring", + ["Runtime/mbstring", True], ["Runtime/mem", True], ["Runtime/mem_funcs", True], ["Runtime/misc_io", True], "Runtime/printf", ["Runtime/qsort", False], ["Runtime/rand", True], - "Runtime/sscanf", - "Runtime/string", + ["Runtime/sscanf", True], + ["Runtime/string", True], ["Runtime/float", True], "Runtime/strtold", ["Runtime/uart_console_io", True], diff --git a/libc/errno.h b/libc/errno.h index 982e8ec2..f06a6615 100644 --- a/libc/errno.h +++ b/libc/errno.h @@ -10,8 +10,9 @@ extern int errno; #define ENOERR 0 #define EDOM 33 #define ERANGE 34 -#define EFPOS 40 #define ESIGPARM 36 +#define EFPOS 40 +#define EILSEQ 84 #ifdef __cplusplus } diff --git a/libc/stdio.h b/libc/stdio.h index 7fb47db7..9937d4d0 100644 --- a/libc/stdio.h +++ b/libc/stdio.h @@ -99,6 +99,21 @@ typedef struct _IO_FILE { struct _IO_FILE* next_file_struct; } FILE; +typedef struct { + char* CharStr; + size_t MaxCharCount; + size_t CharsWritten; +} __OutStrCtrl; + +typedef struct { + char* NextChar; + int NullCharDetected; +} __InStrCtrl; + +#define EOF -1L + +enum __ReadProcActions { __GetChar, __UngetChar, __CheckForError }; + #define _IONBF 0 #define _IOLBF 1 #define _IOFBF 2 @@ -110,7 +125,7 @@ int vprintf(const char* format, va_list arg); int vsprintf(char* s, const char* format, va_list arg); size_t fread(const void*, size_t memb_size, size_t num_memb, FILE*); size_t fwrite(const void*, size_t memb_size, size_t num_memb, FILE*); -int fseek(FILE * file, long offset, int mode); +int fseek(FILE* file, long offset, int mode); size_t __fwrite(const void*, size_t, size_t, FILE*); #ifdef __cplusplus diff --git a/src/Runtime/mbstring.c b/src/Runtime/mbstring.c new file mode 100644 index 00000000..a7819ee3 --- /dev/null +++ b/src/Runtime/mbstring.c @@ -0,0 +1,116 @@ +#include "errno.h" +#include "stdio.h" +#include "string.h" +#include "wstring.h" + +#pragma ANSI_strict off + +#ifndef __WINT_TYPE__ +#define __WINT_TYPE__ unsigned int +#endif + +typedef struct { + int __count; + union { + __WINT_TYPE__ __wch; + char __wchb[4]; + } __value; /* Value so far. */ +} mbstate_t; + +static int is_utf8_complete(const char* s, size_t n); +static int is_utf8_complete(const char* s, size_t n) { + if (n <= 0) /* 0 or fewer characters do not form a valid multibyte character */ + return (-1); + + if (*s == 0x00) + return (0); + + if ((*s & 0x80) == 0x00) + return (1); + else if ((*s & 0xe0) == 0xc0) /* need 2 bytes */ + if (n >= 2) + if (((*(s + 1) & 0x80) == 0x80)) + return (2); + else + return (-1); + else + return (-2); + + else if ((*s & 0xf0) == 0xe0) + if (n >= 3) + if (((*(s + 1) & 0x80) == 0x80) && ((*(s + 2) & 0x80) == 0x80)) + return (3); + else + return (-1); + else if (((n == 2) && ((*(s + 1) & 0x80) == 0x80)) || (n == 1)) + return (-2); + else + return (-1); + else + return (-1); +} + +#pragma dont_inline on +static int unicode_to_UTF8(char* s, wchar_t wchar) { + int number_of_bytes; + wchar_t wide_char; + char* target_ptr; + char first_byte_mark[4] = {0x00, 0x00, 0xc0, 0xe0}; + + if (!s) { + return 0; + } + + wide_char = wchar; + if (wide_char < 0x0080) + number_of_bytes = 1; + else if (wide_char < 0x0800) + number_of_bytes = 2; + else + number_of_bytes = 3; + + target_ptr = s + number_of_bytes; + + switch (number_of_bytes) { + case 3: + *--target_ptr = (wide_char & 0x003f) | 0x80; + wide_char >>= 6; + case 2: + *--target_ptr = (wide_char & 0x003f) | 0x80; + wide_char >>= 6; + case 1: + *--target_ptr = wide_char | first_byte_mark[number_of_bytes]; + } + + return (number_of_bytes); +} +#pragma dont_inline reset + +int wctomb(char* s, wchar_t wchar) { return (unicode_to_UTF8(s, wchar)); } + +size_t wcstombs(char* s, const wchar_t* pwcs, size_t n) { + int chars_written = 0; + int result; + char temp[3]; + wchar_t* source; + + if (!s || !pwcs) + return (0); + + source = (wchar_t*)pwcs; + while (chars_written <= n) { + if (!*source) { + *(s + chars_written) = '\0'; + break; + } else { + result = wctomb(temp, *source++); + if ((chars_written + result) <= n) { + strncpy(s + chars_written, temp, result); + chars_written += result; + } else + break; + } + } + + return (chars_written); +} diff --git a/src/Runtime/sscanf.c b/src/Runtime/sscanf.c new file mode 100644 index 00000000..171ee58b --- /dev/null +++ b/src/Runtime/sscanf.c @@ -0,0 +1,26 @@ +#include "stdio.h" + +int __StringRead(void* isc, int ch, int Action) { + char ret; + __InStrCtrl* iscp = (__InStrCtrl*)isc; + switch (Action) { + case __GetChar: + ret = *(iscp->NextChar); + if (ret == '\0') { + iscp->NullCharDetected = 1; + return (EOF); + } else { + iscp->NextChar++; + return ((unsigned char)ret); + } + case __UngetChar: + if (!iscp->NullCharDetected) + iscp->NextChar--; + else + iscp->NullCharDetected = 0; + return (ch); + case __CheckForError: + return (iscp->NullCharDetected); + } + return 0; +} diff --git a/src/Runtime/string.c b/src/Runtime/string.c new file mode 100644 index 00000000..82ca5688 --- /dev/null +++ b/src/Runtime/string.c @@ -0,0 +1,201 @@ +#include "string.h" + +size_t strlen(const char* str) { + size_t len = -1; + unsigned char* p = (unsigned char*)str - 1; + do { + len++; + } while (*++p); + return len; +} + +char*(strcpy)(char* dst, const char* src) { + unsigned char *destb, *fromb; + unsigned int w, t, align; + unsigned int k1; + unsigned int k2; + + fromb = (unsigned char*)src; + destb = (unsigned char*)dst; + + if ((align = ((int)fromb & 3)) != ((int)destb & 3)) { + goto bytecopy; + } + + if (align) { + if ((*destb = *fromb) == 0) { + return dst; + } + + for (align = 3 - align; align; align--) { + if ((*(++destb) = *(++fromb)) == 0) { + return dst; + } + } + ++destb; + ++fromb; + } + + k1 = 0x80808080; + k2 = 0xfefefeff; + + w = *((int*)(fromb)); + t = w + k2; + t &= k1; + if (t) { + goto bytecopy; + } + + --((int*)(destb)); + + do { + *(++((int*)(destb))) = w; + w = *(++((int*)(fromb))); + + t = w + k2; + t &= k1; + if (t) + goto adjust; + } while (1); + +adjust: + ++((int*)(destb)); + +bytecopy: + if ((*destb = *fromb) == 0) + return (dst); + do { + if ((*(++destb) = *(++fromb)) == 0) + return dst; + } while (1); + + return dst; +} + +char* strncpy(char* dst, const char* src, size_t n) { + const unsigned char* p = (const unsigned char*)src - 1; + unsigned char* q = (unsigned char*)dst - 1; + unsigned char zero = 0; + + n++; + + while (--n) + if (!(*++q = *++p)) { + while (--n) + *++q = 0; + break; + } + + return dst; +} + +int strcmp(const char* str1, const char* str2) { + unsigned char* left = (unsigned char*)str1; + unsigned char* right = (unsigned char*)str2; + unsigned int k1, k2, align, l1, r1, x; + + l1 = *left; + r1 = *right; + if (l1 - r1) { + return l1 - r1; + } + + if ((align = ((int)left & 3)) != ((int)right & 3)) { + goto bytecopy; + } + if (align) { + if (l1 == 0) { + return 0; + } + for (align = 3 - align; align; align--) { + l1 = *(++left); + r1 = *(++right); + if (l1 - r1) { + return l1 - r1; + } + if (l1 == 0) { + return 0; + } + } + left++; + right++; + } + + k1 = 0x80808080; + k2 = 0xfefefeff; + + l1 = *(int*)left; + r1 = *(int*)right; + x = l1 + k2; + if (x & k1) { + goto adjust; + } + while (l1 == r1) { + l1 = *(++((int*)(left))); + r1 = *(++((int*)(right))); + x = l1 + k2; + if (x & k1) { + goto adjust; + } + } + + if (l1 > r1) { + return 1; + } + + return -1; + +adjust: + l1 = *left; + r1 = *right; + if (l1 - r1) { + return l1 - r1; + } + +bytecopy: + if (l1 == 0) { + return 0; + } + + do { + l1 = *(++left); + r1 = *(++right); + if (l1 - r1) { + return l1 - r1; + } + if (l1 == 0) { + return 0; + } + } while (1); +} + +int strncmp(const char* str1, const char* str2, size_t n) { + const unsigned char* p1 = (unsigned char*)str1 - 1; + const unsigned char* p2 = (unsigned char*)str2 - 1; + unsigned long c1, c2; + + n++; + + while (--n) { + if ((c1 = *++p1) != (c2 = *++p2)) { + return (c1 - c2); + } else if (!c1) { + break; + } + } + + return 0; +} + +char* strchr(const char* str, int chr) { + const unsigned char* p = (unsigned char*)str - 1; + unsigned long c = (chr & 0xff); + unsigned long ch; + + while (ch = *++p) { + if (ch == c) + return ((char*)p); + } + + return (c ? 0 : (char*)p); +}