├── test ├── test5.txt ├── test3_in.txt ├── test4_in.txt ├── hello.c ├── test2.c ├── test7.c ├── test6.c ├── test1.c ├── test3.c ├── Makefile ├── test4.c ├── test5.c └── test8.c ├── .gitignore ├── licence.txt ├── nocrt_mem.h ├── nocrt_mem_win.c ├── nocrt_dll.c ├── README.md ├── nocrt_file.h ├── nocrt_math.c ├── nocrt.h ├── nocrt_exe.c ├── nocrt_math_calc.c ├── nocrt_file_win.c └── nocrt.c /test/test5.txt: -------------------------------------------------------------------------------- 1 | abcd1234 2 | 1234 3 | -------------------------------------------------------------------------------- /test/test3_in.txt: -------------------------------------------------------------------------------- 1 | test 2 | testtest 3 | -------------------------------------------------------------------------------- /test/test4_in.txt: -------------------------------------------------------------------------------- 1 | test 2 | 1234 3 | data 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # generated and temporary files 2 | *.bak 3 | *.com 4 | *.o 5 | *.exe 6 | 7 | -------------------------------------------------------------------------------- /test/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "nocrt.h" 5 | 6 | int main() 7 | { 8 | printf("Hello World!"); 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nocrt.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int i; 7 | for(i = 0; i < argc; i++) 8 | { 9 | printf("argv[%d] = \"%s\";\n", i, argv[i]); 10 | } 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/test7.c: -------------------------------------------------------------------------------- 1 | /* example from: https://cplusplus.com/reference/cstdlib/strtol/ */ 2 | #include 3 | #include 4 | #include "nocrt.h" 5 | 6 | int main() 7 | { 8 | char szNumbers[] = "2001 60c0c0 -1101110100110100100000 0x6fffff"; 9 | char * pEnd; 10 | long int li1, li2, li3, li4; 11 | li1 = strtol (szNumbers,&pEnd,10); 12 | li2 = strtol (pEnd,&pEnd,16); 13 | li3 = strtol (pEnd,&pEnd,2); 14 | li4 = strtol (pEnd,NULL,0); 15 | printf ("The decimal equivalents are: %ld, %ld, %ld and %ld.\n", li1, li2, li3, li4); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/test6.c: -------------------------------------------------------------------------------- 1 | /* strstr example from https://cplusplus.com/reference/cstring/strstr/ */ 2 | #include 3 | #include 4 | #include "nocrt.h" 5 | 6 | int main () 7 | { 8 | char str[] = "This is a simple string"; 9 | char *pch; 10 | pch = strstr(str,"simple"); 11 | if(pch != NULL) 12 | { 13 | strncpy(pch,"sample",6); 14 | } 15 | puts(str); 16 | 17 | char str2[] = "short"; 18 | 19 | pch = strstr(str2, "very long"); 20 | printf("%p\n", pch); 21 | pch = strstr(str2, "short"); 22 | printf("%d\n", pch == str2); 23 | pch = strstr(str2, "shortt"); 24 | printf("%p\n", pch); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/test1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nocrt.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | (void)argc; 7 | (void)argv; 8 | 9 | printf("Hello %s!\n", "world"); 10 | 11 | printf("Hello numbers: %d %x %o\n", 123, 124, 125); 12 | 13 | printf("More format test: %04d %4x %#2o %016b\n", 123, 123, 123, 123); 14 | 15 | printf("Floats: %f, %e, %g\n", 0.6, 123.0, 1.0/3); 16 | 17 | 18 | /* example from https://cplusplus.com/reference/cstring/strncat/ */ 19 | char str1[20]; 20 | char str2[20]; 21 | 22 | strcpy(str1, "To be "); 23 | strcpy(str2,"or not to be"); 24 | strncat(str1, str2, 6); 25 | puts(str1); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /test/test3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nocrt.h" 3 | 4 | #define BUF_LEN 32 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | (void)argc; 9 | (void)argv; 10 | char buf[BUF_LEN]; 11 | int i = 0; 12 | int c; 13 | 14 | printf("Repeater, empty line to exit\n"); 15 | do 16 | { 17 | printf("Type something: "); 18 | do 19 | { 20 | c = getchar(); 21 | if(i < BUF_LEN-1) 22 | { 23 | if(c != '\r') 24 | { 25 | buf[i++] = c; 26 | } 27 | } 28 | } while(c != '\n' && c != EOF); 29 | 30 | if(c == EOF) 31 | { 32 | buf[i-1] = '\0'; 33 | } 34 | else 35 | { 36 | buf[i] = '\0'; 37 | } 38 | 39 | printf("You typed (%d): %s", strlen(buf), buf); 40 | i = 0; 41 | 42 | } while(c != EOF && strlen(buf) > 1); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-std=c99 -Wall -Wextra -O2 -I.. 3 | OBJ_SUFFIX = .o 4 | LDFLAGS=-static 5 | LIBS=-luser32 -lkernel32 -Wl,-subsystem,console 6 | 7 | DEPS = Makefile 8 | 9 | TESTS := hello.exe test1.exe test2.exe test3.exe test4.exe test5.exe test6.exe test7.exe test8.exe 10 | 11 | NOCRT=1 12 | 13 | all: $(TESTS) 14 | 15 | .PHONY: all clean 16 | 17 | SOURCES := 18 | 19 | ifdef NOCRT 20 | SOURCES += ../nocrt.c ../nocrt_exe.c ../nocrt_file_win.c ../nocrt_mem_win.c ../nocrt_math.c ../nocrt_math_calc.c 21 | LDFLAGS += -nostdlib -nodefaultlibs -lgcc 22 | CFLAGS += -DNOCRT -DNOCRT_FILE -DNOCRT_FLOAT -DNOCRT_MEM -DNOCRT_CALC -ffreestanding -nostdlib 23 | endif 24 | 25 | OBJS := $(SOURCES:.c=.c$(OBJ_SUFFIX)) 26 | 27 | %.c.o: %.c $(DEPS) 28 | $(CC) $(CFLAGS) -c -o $@ $< 29 | 30 | %.exe: %.c.o $(OBJS) 31 | $(CC) $(CFLAGS) $< $(OBJS) $(LDFLAGS) -o $@ $(LIBS) 32 | 33 | clean: 34 | -$(RM) $(OBJS) 35 | -$(RM) $(TESTS) 36 | -------------------------------------------------------------------------------- /licence.txt: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright 2022 Jaroslav Hensl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 18 | IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /test/test4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nocrt.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | (void)argc; 7 | (void)argv; 8 | int c; 9 | 10 | FILE *fr = fopen("test4_in.txt", "rb"); 11 | 12 | if(!fr) 13 | { 14 | printf("Fopen failer\n"); 15 | return 0; 16 | } 17 | else 18 | { 19 | printf("Fopen success\n"); 20 | } 21 | 22 | while(!feof(fr)) 23 | { 24 | c = fgetc(fr); 25 | putchar(c); 26 | } 27 | 28 | rewind(fr); 29 | printf("====\n"); 30 | 31 | for(;;) 32 | { 33 | c = fgetc(fr); 34 | if(c == EOF) break; 35 | putchar(c); 36 | } 37 | 38 | rewind(fr); 39 | printf("====\n"); 40 | 41 | fseek(fr, 0, SEEK_END); 42 | size_t pos = ftell(fr); 43 | char *ptr = NULL; 44 | printf("File end: %lu\n", pos); 45 | 46 | if(feof(fr)) 47 | { 48 | printf("EOF seek to set\n"); 49 | fseek(fr, 0, SEEK_SET); 50 | } 51 | 52 | ptr = malloc(pos); 53 | if(ptr == NULL) 54 | { 55 | printf("malloc FAIL!\n"); 56 | } 57 | else 58 | { 59 | printf("fread: %lu\n", fread(ptr, pos, 1, fr)); 60 | 61 | fwrite(ptr, 1, pos, stdout); 62 | 63 | free(ptr); 64 | } 65 | 66 | fclose(fr); 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /test/test5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nocrt.h" 3 | 4 | const char test1[] = "abcdefgh"; 5 | const char test2[] = "1234"; 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | (void)argc; 10 | (void)argv; 11 | 12 | FILE *fw = fopen("test5.txt", "w+"); 13 | if(!fw) 14 | { 15 | printf("Fopen failed!\n"); 16 | return 1; 17 | } 18 | 19 | fwrite(test1, 1, strlen(test1), fw); 20 | if(feof(fw)) 21 | { 22 | printf("Yes, this is end file\n"); 23 | } 24 | else 25 | { 26 | printf("no EOF, something is wrong!\n"); 27 | } 28 | 29 | fseek(fw, -4, SEEK_CUR); // move 4 bytes back 30 | 31 | feof(fw); // feof is implement as attempt to read one byte (the byte is buffered, so next read return it + read rest) 32 | feof(fw); // but this internal move file position sould be invisible for runtime user! 33 | feof(fw); 34 | if(feof(fw)) 35 | { 36 | printf("rech EOF, something is wrong!\n"); 37 | } 38 | 39 | fwrite(test2, 1, strlen(test2), fw); 40 | 41 | fclose(fw); 42 | 43 | FILE *fa = fopen("test5.txt", "a"); 44 | if(!fa) 45 | { 46 | printf("Fopen failed\n"); 47 | return 2; 48 | } 49 | 50 | fputc('\n', fa); 51 | fwrite(test2, 1, strlen(test2), fa); 52 | fputc('\n', fa); 53 | 54 | fclose(fa); 55 | 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /test/test8.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "nocrt.h" 6 | 7 | int main() 8 | { 9 | printf("SIN (double): %lf %lf %lf %lf %lf\n", sin(0), sin(1), sin(NOCRT_PI), sin(NOCRT_PI/2), sin(NOCRT_PI/3)); 10 | printf("SIN (float): %f %f %f %f %f\n", sinf(0), sinf(1), sinf(NOCRT_PI), sinf(NOCRT_PI/2), sinf(NOCRT_PI/3)); 11 | printf("SIN (taylor): %lf %lf %lf %lf %lf\n", 12 | nocrt_sin_eps(0, NOCRT_DOUBLE_MAX_DIGITS), 13 | nocrt_sin_eps(1, NOCRT_DOUBLE_MAX_DIGITS), 14 | nocrt_sin_eps(NOCRT_PI, NOCRT_DOUBLE_MAX_DIGITS), 15 | nocrt_sin_eps((NOCRT_PI/2), NOCRT_DOUBLE_MAX_DIGITS), 16 | nocrt_sin_eps((NOCRT_PI/3), NOCRT_DOUBLE_MAX_DIGITS) 17 | ); 18 | 19 | printf("COS (double): %lf %lf %lf %lf %lf\n", cos(0), sin(1), cos(NOCRT_PI), cos(NOCRT_PI/2), cos(NOCRT_PI/3)); 20 | printf("COS (float): %f %f %f %f %f\n", cosf(0), cosf(1), cosf(NOCRT_PI), cosf(NOCRT_PI/2), cosf(NOCRT_PI/3)); 21 | printf("COS (taylor): %lf %lf %lf %lf %lf\n", 22 | nocrt_cos_eps(0, NOCRT_DOUBLE_MAX_DIGITS), 23 | nocrt_cos_eps(1, NOCRT_DOUBLE_MAX_DIGITS), 24 | nocrt_cos_eps(NOCRT_PI, NOCRT_DOUBLE_MAX_DIGITS), 25 | nocrt_cos_eps((NOCRT_PI/2), NOCRT_DOUBLE_MAX_DIGITS), 26 | nocrt_cos_eps((NOCRT_PI/3), NOCRT_DOUBLE_MAX_DIGITS) 27 | ); 28 | 29 | printf("TAN (double): %lf %lf %lf %lf %lf\n", tan(0), tan(1), tan(NOCRT_PI), tan(NOCRT_PI/2), tan(NOCRT_PI/3)); 30 | printf("TAN (float): %f %f %f %f %f\n", tanf(0), tanf(1), tanf(NOCRT_PI), tanf(NOCRT_PI/2), tanf(NOCRT_PI/3)); 31 | printf("TAN (taylor): %lf %lf %lf %lf %lf\n", 32 | nocrt_tan_eps(0, NOCRT_DOUBLE_MAX_DIGITS), 33 | nocrt_tan_eps(1, NOCRT_DOUBLE_MAX_DIGITS), 34 | nocrt_tan_eps(NOCRT_PI, NOCRT_DOUBLE_MAX_DIGITS), 35 | nocrt_tan_eps(NOCRT_PI/2, NOCRT_DOUBLE_MAX_DIGITS), 36 | nocrt_tan_eps(NOCRT_PI/3, NOCRT_DOUBLE_MAX_DIGITS) 37 | ); 38 | 39 | return EXIT_SUCCESS; 40 | } 41 | -------------------------------------------------------------------------------- /nocrt_mem.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright 2023 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #ifndef __NOCRT_MEM_H__INCLUDED__ 23 | #define __NOCRT_MEM_H__INCLUDED__ 24 | 25 | #ifdef NOCRT 26 | 27 | void *nocrt_malloc(size_t size); 28 | void *nocrt_realloc(void *ptr, size_t new_size); 29 | void *nocrt_calloc(size_t num, size_t size); 30 | void nocrt_free(void *ptr); 31 | 32 | #define malloc nocrt_malloc 33 | #define realloc nocrt_realloc 34 | #define calloc nocrt_calloc 35 | #define free nocrt_free 36 | 37 | #endif /* NOCRT */ 38 | 39 | #endif /* __NOCRT_MEM_H__INCLUDED__ */ 40 | -------------------------------------------------------------------------------- /nocrt_mem_win.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright 2023 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #ifdef NOCRT_MEM 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "nocrt.h" 29 | #include "nocrt_mem.h" 30 | 31 | void *nocrt_malloc(size_t size) 32 | { 33 | return HeapAlloc(GetProcessHeap(), 0, size); 34 | } 35 | 36 | void *nocrt_realloc(void *ptr, size_t new_size) 37 | { 38 | return HeapReAlloc(GetProcessHeap(), 0, ptr, new_size); 39 | } 40 | 41 | void *nocrt_calloc(size_t num, size_t size) 42 | { 43 | size_t total = num*size; 44 | 45 | return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total); 46 | } 47 | 48 | void nocrt_free(void *ptr) 49 | { 50 | HeapFree(GetProcessHeap(), 0, ptr); 51 | } 52 | 53 | #endif /* NOCRT_MEM */ 54 | -------------------------------------------------------------------------------- /nocrt_dll.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright 2023 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #include 23 | #include "nocrt.h" 24 | 25 | /* security cookie = buffer overrun protection */ 26 | #ifdef _WIN64 27 | #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll 28 | #else 29 | #define DEFAULT_SECURITY_COOKIE 0xBB40E64E 30 | #endif 31 | 32 | DECLSPEC_SELECTANY UINT_PTR __security_cookie = DEFAULT_SECURITY_COOKIE; 33 | DECLSPEC_SELECTANY UINT_PTR __security_cookie_complement = ~(DEFAULT_SECURITY_COOKIE); 34 | 35 | typedef union 36 | { 37 | unsigned __int64 ft_scalar; 38 | FILETIME ft_struct; 39 | } FT; 40 | 41 | void __cdecl __security_init_cookie (void); 42 | 43 | void __cdecl 44 | __security_init_cookie (void) 45 | { 46 | UINT_PTR cookie; 47 | FT systime = { 0, }; 48 | LARGE_INTEGER perfctr; 49 | 50 | if (__security_cookie != DEFAULT_SECURITY_COOKIE) 51 | { 52 | __security_cookie_complement = ~__security_cookie; 53 | return; 54 | } 55 | 56 | GetSystemTimeAsFileTime (&systime.ft_struct); 57 | #ifdef _WIN64 58 | cookie = systime.ft_scalar; 59 | #else 60 | cookie = systime.ft_struct.dwLowDateTime; 61 | cookie ^= systime.ft_struct.dwHighDateTime; 62 | #endif 63 | 64 | cookie ^= GetCurrentProcessId (); 65 | cookie ^= GetCurrentThreadId (); 66 | cookie ^= GetTickCount (); 67 | 68 | QueryPerformanceCounter (&perfctr); 69 | #ifdef _WIN64 70 | cookie ^= perfctr.QuadPart; 71 | #else 72 | cookie ^= perfctr.LowPart; 73 | cookie ^= perfctr.HighPart; 74 | #endif 75 | 76 | #ifdef _WIN64 77 | cookie &= 0x0000ffffffffffffll; 78 | #endif 79 | 80 | if (cookie == DEFAULT_SECURITY_COOKIE) 81 | cookie = DEFAULT_SECURITY_COOKIE + 1; 82 | __security_cookie = cookie; 83 | __security_cookie_complement = ~cookie; 84 | } 85 | 86 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); 87 | 88 | /* DllMain caller and I/O initializer */ 89 | __declspec(noinline) WINBOOL 90 | __DllMainCRTStartup (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) 91 | { 92 | WINBOOL retcode; 93 | retcode = DllMain(hDllHandle, dwReason, lpreserved); 94 | return retcode ; 95 | } 96 | 97 | /* entry point */ 98 | WINBOOL WINAPI DllMainCRTStartup (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) 99 | { 100 | if (dwReason == DLL_PROCESS_ATTACH) 101 | { 102 | __security_init_cookie(); 103 | } 104 | return __DllMainCRTStartup (hDllHandle, dwReason, lpreserved); 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOCRT - simple replacement of some parts of C runtime library 2 | 3 | This code was created because sometimes C runtime is broken, outdated, missing or is too large and occupied too much valuable space in device ROM. Some of function are bit complex (for example `printf` and all its variants), so I decided to copy out my individual implementations of same function to separate library. Usage is now limited to Windows and GCC (MinGW), other platforms (AVR, Watcom) may come later. 4 | 5 | **This is NOT complete reimplementation C runtime! Only small subset of frequently used functions. ** 6 | 7 | 8 | ## Usage 9 | 10 | Place nocrt.h AFTER standard headers: 11 | 12 | ``` 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | .... 20 | ``` 21 | 22 | By using define (or better `-D` on command line), set subset of functions which do you want to use: 23 | - `NOCRT`: basic subset (platform independent) 24 | - `NOCRT_FLOAT`: working with floats (for example `%f` in printf), require some assembly (for X86 in `nocrt_math.c`) 25 | - `NOCRT_MEM`: malloc and similar functions, depends on platform (for WINAPI is in `nocrt_mem_win.c`) 26 | - `NOCRT_FILE`: working with files (and standard input/output), depends on platform (for WINAPI is in `nocrt_file_win.c`) 27 | 28 | Add `-ffreestanding` to *CFLAGS* 29 | 30 | Add `-nostdlib` `-nodefaultlibs` `-lgcc` to *LDFLAGS* 31 | 32 | After all, you still need some startup code, for Windows EXE is in `nocrt_exe.c` and for Windows DLL is in `nocrt_dll.c` 33 | 34 | ## Hello World for WIN32 35 | 36 | Console applications, `hello.c`: 37 | 38 | ``` 39 | #include 40 | #include 41 | 42 | #include "nocrt.h" 43 | 44 | int main() 45 | { 46 | printf("Hello World!"); 47 | 48 | return 0; 49 | } 50 | ``` 51 | 52 | Compile files as: 53 | 54 | ``` 55 | gcc -std=c99 -Wall -Wextra -O2 -DNOCRT -DNOCRT_FILE -DNOCRT_FLOAT -DNOCRT_MEM -ffreestanding -nostdlib -c -o nocrt.c.o nocrt.c 56 | gcc -std=c99 -Wall -Wextra -O2 -DNOCRT -DNOCRT_FILE -DNOCRT_FLOAT -DNOCRT_MEM -ffreestanding -nostdlib -c -o nocrt_math.c.o nocrt_math.c 57 | gcc -std=c99 -Wall -Wextra -O2 -DNOCRT -DNOCRT_FILE -DNOCRT_FLOAT -DNOCRT_MEM -ffreestanding -nostdlib -c -o nocrt_file_win.c.o nocrt_file_win.c 58 | gcc -std=c99 -Wall -Wextra -O2 -DNOCRT -DNOCRT_FILE -DNOCRT_FLOAT -DNOCRT_MEM -ffreestanding -nostdlib -c -o nocrt_mem_win.c.o nocrt_mem_win.c 59 | gcc -std=c99 -Wall -Wextra -O2 -DNOCRT -DNOCRT_FILE -DNOCRT_FLOAT -DNOCRT_MEM -ffreestanding -nostdlib -c -o nocrt_exe.c.o nocrt_exe.c 60 | gcc -std=c99 -Wall -Wextra -O2 -DNOCRT -DNOCRT_FILE -DNOCRT_FLOAT -DNOCRT_MEM -ffreestanding -nostdlib \ 61 | hello.c.o nocrt.c.o nocrt_exe.c.o nocrt_file_win.c.o nocrt_mem_win.c.o nocrt_math.c.o \ 62 | -static -nostdlib -nodefaultlibs -lgcc -o hello.exe -luser32 -lkernel32 -Wl,-subsystem,console 63 | ``` 64 | 65 | Windows application (without console), `hello_win.c`: 66 | 67 | ``` 68 | #include 69 | 70 | #include "nocrt.h" 71 | 72 | int main() 73 | { 74 | MessageBox(NULL, "Hello World!", "NOCRT example", MB_ICONINFORMATION); 75 | return 0; 76 | } 77 | ``` 78 | 79 | Compile is simitar but link as: 80 | ``` 81 | gcc -std=c99 -Wall -Wextra -O2 -DNOCRT -DNOCRT_FILE -DNOCRT_FLOAT -DNOCRT_MEM -ffreestanding -nostdlib \ 82 | hello_win.c.o nocrt.c.o nocrt_exe.c.o nocrt_file_win.c.o nocrt_mem_win.c.o nocrt_math.c.o \ 83 | -static -nostdlib -nodefaultlibs -lgcc -o hello.exe -luser32 -lkernel32 -Wl,-subsystem,windows 84 | ``` 85 | 86 | ## Binary replacement 87 | 88 | This project can't replace `libmsvcrt.a` from MinGW. If need write or port C++ program for Windows 9x (95 + 98 + Me) using newer MinGW, you've got 2 options: 89 | 1) Use my fixed `libpthread.a`: https://github.com/JHRobotics/pthread9x (missing parts of old MSVCRT are included) 90 | You still need some `msvcrt.dll` (included with Internet Explorer 4), but your program should now run on Vanila 98 and Me. On 95 you must install IE or separated Visual C redistributable, anyway is still possible, that your program still won't work on 95, because in newer MinGW are some SSE instructions hardcoded in libraries. This can be solved with the force (https://github.com/JHRobotics/simd95) or using older MinGW (I'm using 4.8.5). 91 | 2) Replace msvcrt.dll to one from Visual Studio Redistributable 7.0 (7.0, not 7.1!), it still works on 9x and is full compatible with `libmsvcrt.a` from MinGW. 92 | 93 | ## Licence 94 | 95 | All code in this repository is under Public Domain. You are free to include it to your project if you find it useful! 96 | -------------------------------------------------------------------------------- /nocrt_file.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright 2023 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #ifndef __NOCRT_FILE_H__INCLUDED__ 23 | 24 | #ifdef NOCRT 25 | 26 | struct _nocrt_FILE; 27 | typedef struct _nocrt_FILE nocrt_FILE; 28 | 29 | nocrt_FILE *nocrt_fopen(const char *fn, const char *mode); 30 | void nocrt_fclose(nocrt_FILE *stream); 31 | size_t nocrt_fread(void *ptr, size_t size, size_t count, nocrt_FILE *stream); 32 | size_t nocrt_fwrite(const void * ptr, size_t size, size_t count, nocrt_FILE *stream); 33 | int nocrt_fseek(nocrt_FILE *stream, long long offset, int origin); 34 | long long nocrt_ftell(nocrt_FILE *stream); 35 | int nocrt_fgetc(nocrt_FILE *stream); 36 | int nocrt_fputc(int c, nocrt_FILE *stream); 37 | char *nocrt_fgets(char* str, int num, nocrt_FILE* stream); 38 | int nocrt_fputs(const char *str, nocrt_FILE* stream); 39 | int nocrt_vfprintf(nocrt_FILE *stream, const char *format, va_list arg); 40 | int nocrt_fprintf(nocrt_FILE *stream, const char *format, ...); 41 | void nocrt_rewind(nocrt_FILE *stream); 42 | int nocrt_feof(nocrt_FILE *stream); 43 | int nocrt_ferror(nocrt_FILE * stream); 44 | int nocrt_fflush(nocrt_FILE *stream); 45 | 46 | int nocrt_vprintf(const char *format, va_list arg); 47 | int nocrt_printf(const char *format, ...); 48 | int nocrt_puts(const char *str); 49 | int nocrt_getchar(); 50 | int nocrt_putchar(int character); 51 | 52 | int nocrt_rename(const char *oldname, const char *newname); 53 | int nocrt_mkdir(const char *path, int mode); 54 | int nocrt_unlink(const char *path); 55 | 56 | extern nocrt_FILE *nocrt_stdin; 57 | extern nocrt_FILE *nocrt_stdout; 58 | extern nocrt_FILE *nocrt_stderr; 59 | 60 | #define fopen nocrt_fopen 61 | #define fclose nocrt_fclose 62 | #define fread nocrt_fread 63 | #define fwrite nocrt_fwrite 64 | #define fseek nocrt_fseek 65 | #define ftell nocrt_ftell 66 | #define fgetc nocrt_fgetc 67 | #define fputc nocrt_fputc 68 | #define fgets nocrt_fgets 69 | #define fputs nocrt_fputs 70 | #define vfprintf nocrt_vfprintf 71 | #define fprintf nocrt_fprintf 72 | #define rewind nocrt_rewind 73 | #define vprintf nocrt_vprintf 74 | #define printf nocrt_printf 75 | #define puts nocrt_puts 76 | #define getchar nocrt_getchar 77 | #define putchar nocrt_putchar 78 | #define feof nocrt_feof 79 | #define ferror nocrt_ferror 80 | #define fflush nocrt_fflush 81 | 82 | #define rename nocrt_rename 83 | #define mkdir nocrt_mkdir 84 | #define _mkdir(_d) nocrt_mkdir(_d, 0) 85 | #define unlink nocrt_unlink 86 | 87 | 88 | #define FILE nocrt_FILE 89 | 90 | #ifdef stdin 91 | #undef stdin 92 | #endif 93 | #define stdin nocrt_stdin 94 | 95 | 96 | #ifdef stdout 97 | #undef stdout 98 | #endif 99 | #define stdout nocrt_stdout 100 | 101 | #ifdef stderr 102 | #undef stderr 103 | #endif 104 | #define stderr nocrt_stderr 105 | 106 | #ifndef SEEK_SET 107 | #define SEEK_SET 0 108 | #endif 109 | 110 | #ifndef SEEK_CUR 111 | #define SEEK_CUR 1 112 | #endif 113 | 114 | #ifndef SEEK_END 115 | #define SEEK_END 2 116 | #endif 117 | 118 | #endif /* NOCRT */ 119 | 120 | #endif /* __NOCRT_FILE_H__INCLUDED__ */ 121 | -------------------------------------------------------------------------------- /nocrt_math.c: -------------------------------------------------------------------------------- 1 | /** 2 | * This file has no copyright assigned and is placed in the Public Domain. 3 | * This file is part of the mingw-w64 runtime package. 4 | * No warranty is given; refer to the file DISCLAIMER.PD within this package. 5 | */ 6 | #include 7 | #include "nocrt.h" 8 | 9 | #ifdef NOCRT_FLOAT 10 | 11 | double nocrt_fmod(double x, double y) 12 | { 13 | double res = 0.0; 14 | 15 | __asm volatile ( 16 | "1:\tfprem\n\t" 17 | "fstsw %%ax\n\t" 18 | "sahf\n\t" 19 | "jp 1b\n\t" 20 | "fstp %%st(1)" 21 | : "=t" (res) : "0" (x), "u" (y) : "ax", "st(1)"); 22 | return res; 23 | } 24 | 25 | #define nocrt_isinf(_v) (((_v)==INFINITY) || (_v)==-INFINITY) 26 | 27 | double nocrt_modf(double value, double* iptr) 28 | { 29 | double int_part = 0.0; 30 | /* truncate */ 31 | #if defined(_AMD64_) || defined(__x86_64__) 32 | __asm volatile ("subq $8, %%rsp\n" 33 | "fnstcw 4(%%rsp)\n" 34 | "movzwl 4(%%rsp), %%eax\n" 35 | "orb $12, %%ah\n" 36 | "movw %%ax, (%%rsp)\n" 37 | "fldcw (%%rsp)\n" 38 | "frndint\n" 39 | "fldcw 4(%%rsp)\n" 40 | "addq $8, %%rsp\n" : "=t" (int_part) : "0" (value) : "eax"); /* round */ 41 | #elif defined(_X86_) || defined(__i386__) 42 | __asm volatile ( 43 | "push %%eax\n" 44 | "subl $8, %%esp\n" 45 | "fnstcw 4(%%esp)\n" 46 | "movzwl 4(%%esp), %%eax\n" 47 | "orb $12, %%ah\n" 48 | "movw %%ax, (%%esp)\n" 49 | "fldcw (%%esp)\n" 50 | "frndint\n" 51 | "fldcw 4(%%esp)\n" 52 | "addl $8, %%esp\n" 53 | "pop %%eax\n" 54 | : "=t" (int_part) : "0" (value) : "eax"); /* round */ 55 | #else 56 | int_part = trunc(value); 57 | #endif 58 | if (iptr) 59 | *iptr = int_part; 60 | 61 | return (nocrt_isinf(value) ? 0.0 : value - int_part); 62 | } 63 | 64 | double nocrt_sin(double x) 65 | { 66 | double y; 67 | #if defined(_X86_) || defined(__i386__) 68 | __asm volatile ( 69 | "fldl %1\n" 70 | "fsin\n" 71 | "fstpl %0" : "=m"(y) : "m"(x) 72 | ); 73 | #else 74 | y = nocrt_sin_eps(x, NOCRT_DOUBLE_MAX_DIGITS); 75 | #endif 76 | return y; 77 | } 78 | 79 | float nocrt_sinf(float x) 80 | { 81 | float y; 82 | #if defined(_X86_) || defined(__i386__) 83 | __asm volatile ( 84 | "flds %1\n" 85 | "fsin\n" 86 | "fstps %0" : "=m"(y) : "m"(x) 87 | ); 88 | #else 89 | y = nocrt_sin_eps(x, NOCRT_FLOAT_MAX_DIGITS); 90 | #endif 91 | return y; 92 | } 93 | 94 | double nocrt_cos(double x) 95 | { 96 | double y; 97 | #if defined(_X86_) || defined(__i386__) 98 | __asm volatile ( 99 | "fldl %1\n" 100 | "fcos\n" 101 | "fstpl %0" : "=m"(y) : "m"(x) 102 | ); 103 | #else 104 | y = nocrt_cos_eps(x, NOCRT_DOUBLE_MAX_DIGITS); 105 | #endif 106 | return y; 107 | } 108 | 109 | float nocrt_cosf(float x) 110 | { 111 | float y; 112 | #if defined(_X86_) || defined(__i386__) 113 | __asm volatile ( 114 | "flds %1\n" 115 | "fcos\n" 116 | "fstps %0" : "=m"(y) : "m"(x) 117 | ); 118 | #else 119 | y = nocrt_cos_eps(x, NOCRT_FLOAT_MAX_DIGITS); 120 | #endif 121 | return y; 122 | } 123 | 124 | static double tan_base(double x) 125 | { 126 | if(x > NOCRT_PI_2) 127 | { 128 | double r; 129 | double f = (x / NOCRT_PI) + 0.5; 130 | nocrt_modf(f, &r); 131 | return x - r * NOCRT_PI; 132 | } 133 | else if(x < NOCRT_PI_2) 134 | { 135 | double r; 136 | double f = (x / NOCRT_PI) - 0.5; 137 | nocrt_modf(f, &r); 138 | return x - r * NOCRT_PI; 139 | } 140 | 141 | return x; 142 | } 143 | 144 | #define EPS_DOUBLE 0.000000000000001d 145 | #define EPS_FLOAT 0.0000001f 146 | 147 | double nocrt_tan(double x) 148 | { 149 | double y; 150 | #if defined(_X86_) || defined(__i386__) 151 | double x1 = tan_base(x); 152 | 153 | if(x1 >= (NOCRT_PI_2-EPS_DOUBLE) && x1 <= (NOCRT_PI_2+EPS_DOUBLE)) 154 | { 155 | return INFINITY; 156 | } 157 | 158 | if(x1 >= (-NOCRT_PI_2-EPS_DOUBLE) && x1 <= (-NOCRT_PI_2+EPS_DOUBLE)) 159 | { 160 | return -INFINITY; 161 | } 162 | 163 | __asm volatile ( 164 | "fldl %1\n" 165 | "fptan\n" 166 | "fxch %%st(1)\n" 167 | "fstpl %0" : "=m"(y) : "m"(x1) : "st(1)" 168 | ); 169 | #else 170 | y = nocrt_tan_eps(x, NOCRT_DOUBLE_MAX_DIGITS); 171 | #endif 172 | return y; 173 | } 174 | 175 | float nocrt_tanf(float x) 176 | { 177 | float y; 178 | #if defined(_X86_) || defined(__i386__) 179 | float x1 = tan_base(x); 180 | 181 | if(x1 >= (NOCRT_PI_2-EPS_FLOAT) && x1 <= (NOCRT_PI_2+EPS_FLOAT)) 182 | { 183 | return INFINITY; 184 | } 185 | 186 | if(x1 >= (-NOCRT_PI_2-EPS_FLOAT) && x1 <= (-NOCRT_PI_2+EPS_FLOAT)) 187 | { 188 | return -INFINITY; 189 | } 190 | 191 | __asm volatile ( 192 | "flds %1\n" 193 | "fptan\n" 194 | "fxch %%st(1)\n" 195 | "fstps %0" : "=m"(y) : "m"(x1) : "st(1)" 196 | ); 197 | #else 198 | y = nocrt_tan_eps(x, NOCRT_FLOAT_MAX_DIGITS); 199 | #endif 200 | return y; 201 | } 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /nocrt.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright 2023 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #ifndef __NOCRT_H__INCLUDED__ 23 | #define __NOCRT_H__INCLUDED__ 24 | 25 | #ifdef NOCRT 26 | 27 | int nocrt_strcmp(const char *s1, const char *s2); 28 | int nocrt_stricmp(const char *s1, const char *s2); 29 | int nocrt_strnicmp(const char *s1, const char *s2, size_t num); 30 | char *nocrt_strcpy(char *dst, const char *src); 31 | char *nocrt_strcat(char *dst, const char *src); 32 | char *nocrt_strncat(char *dst, const char *src, size_t num); 33 | void *nocrt_memcpy(void *dst, const void *src, size_t num); 34 | void *nocrt_memset(void *ptr, int value, size_t num); 35 | char *nocrt_strrchr(const char *str, int character); 36 | char *nocrt_strchr(const char *str, int character); 37 | int nocrt_vsprintf(char *str, const char *format, va_list arg); 38 | int nocrt_sprintf(char *str, const char *format, ...); 39 | int nocrt_strncmp(const char *s1, const char *s2, size_t num); 40 | size_t nocrt_strlen(const char *s); 41 | char *nocrt_strncpy(char *dst, const char *src, size_t num); 42 | char *nocrt_strstr(const char *str1, const char *str2); 43 | unsigned long int nocrt_strtoul(const char* str, char** endptr, int base); 44 | typedef void (*formatf_callback_t)(void *resource, char c); 45 | size_t nocrt_vformatf(void *resource, formatf_callback_t f, size_t n, const char *fmt, va_list args); 46 | int nocrt_memcmp(const void *ptr1, const void *ptr2, size_t num); 47 | int nocrt_tolower(int c); 48 | int nocrt_toupper(int c); 49 | int nocrt_isdigit(int c); 50 | int nocrt_isxdigit(int c); 51 | int nocrt_isspace(int c); 52 | int nocrt_isblank(int c); 53 | int nocrt_islower(int c); 54 | int nocrt_isupper(int c); 55 | int nocrt_isalpha(int c); 56 | int nocrt_isalnum(int c); 57 | int nocrt_iscntrl(int c); 58 | int nocrt_isprint(int c); 59 | int nocrt_isgraph(int c); 60 | int nocrt_ispunct(int c); 61 | long int nocrt_strtol(const char* str, char** endptr, int base); 62 | long int nocrt_atol(const char *str); 63 | int nocrt_atoi(const char *str); 64 | 65 | #define strcmp nocrt_strcmp 66 | #define stricmp nocrt_stricmp 67 | #define strnicmp nocrt_strnicmp 68 | #define strncmp nocrt_strncmp 69 | #define strcpy nocrt_strcpy 70 | #define strcat nocrt_strcat 71 | #define strncat nocrt_strncat 72 | #define memcpy nocrt_memcpy 73 | #define memset nocrt_memset 74 | #define strrchr nocrt_strrchr 75 | #define strchr nocrt_strchr 76 | #define vsprintf nocrt_vsprintf 77 | #define sprintf nocrt_sprintf 78 | #define strlen nocrt_strlen 79 | #define strncpy nocrt_strncpy 80 | #define strstr nocrt_strstr 81 | #define strtoul nocrt_strtoul 82 | #define memcmp nocrt_memcmp 83 | #define tolower nocrt_tolower 84 | #define toupper nocrt_toupper 85 | #define isdigit nocrt_isdigit 86 | #define isxdigit nocrt_isxdigit 87 | #define isspace nocrt_isspace 88 | #define isblank nocrt_isblank 89 | #define islower nocrt_islower 90 | #define isupper nocrt_isupper 91 | #define isalpha nocrt_isalpha 92 | #define isalnum nocrt_isalnum 93 | #define iscntrl nocrt_iscntrl 94 | #define isprint nocrt_isprint 95 | #define isgraph nocrt_isgraph 96 | #define ispunct nocrt_ispunct 97 | #define strtol nocrt_strtol 98 | #define atoi nocrt_atoi 99 | #define atol nocrt_atol 100 | 101 | #ifdef main 102 | #undef main 103 | #endif 104 | 105 | #ifdef ceil 106 | #undef ceil 107 | #endif 108 | 109 | #define ceil(_f) (_f + 0.5) 110 | 111 | #endif 112 | 113 | #define NOCRT_MIN(_a, _b) (((_b) < (_a)) ? (_b) : (_a)) 114 | #define NOCRT_MAX(_a, _b) (((_b) > (_a)) ? (_b) : (_a)) 115 | 116 | #ifdef NOCRT_FLOAT 117 | double nocrt_fmod(double x, double y); 118 | double nocrt_modf(double value, double* iptr); 119 | #endif 120 | 121 | #ifdef NOCRT_CALC 122 | float nocrt_logf(float x); 123 | float nocrt_sinf(float x); 124 | float nocrt_cosf(float x); 125 | float nocrt_tanf(float x); 126 | double nocrt_log(double x); 127 | double nocrt_sin(double x); 128 | double nocrt_cos(double x); 129 | double nocrt_tan(double x); 130 | 131 | #define NOCRT_DOUBLE_MAX_DIGITS 16 /*ceil(log(10, 2^52)) */ 132 | #define NOCRT_FLOAT_MAX_DIGITS 7 /*ceil(log(10, 2^22)) */ 133 | 134 | double nocrt_log_eps(double z, unsigned int digits); 135 | double nocrt_sin_eps(double x, int digits); 136 | double nocrt_cos_eps(double x, int digits); 137 | double nocrt_tan_eps(double x, int digits); 138 | #endif 139 | 140 | #if defined(NOCRT_FLOAT) || defined(NOCRT_CALC) 141 | # define logf nocrt_logf 142 | # define sinf nocrt_sinf 143 | # define cosf nocrt_cosf 144 | # define tanf nocrt_tanf 145 | # define log nocrt_log 146 | # define sin nocrt_sin 147 | # define cos nocrt_cos 148 | # define tan nocrt_tan 149 | #endif 150 | 151 | #define NOCRT_LN2 0.69314718055994530941 /* ln(2) */ 152 | #define NOCRT_PI 3.14159265358979323846 153 | #define NOCRT_PI_2 1.57079632679489661923 154 | 155 | #ifdef NOCRT_MEM 156 | # include "nocrt_mem.h" 157 | #endif 158 | 159 | #ifdef NOCRT_FILE 160 | # include "nocrt_file.h" 161 | #endif 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /nocrt_exe.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright 2023 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #include 23 | #include "nocrt.h" 24 | 25 | /* security cookie = buffer overrun protection */ 26 | #ifdef _WIN64 27 | #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll 28 | #else 29 | #define DEFAULT_SECURITY_COOKIE 0xBB40E64E 30 | #endif 31 | 32 | DECLSPEC_SELECTANY UINT_PTR __security_cookie = DEFAULT_SECURITY_COOKIE; 33 | DECLSPEC_SELECTANY UINT_PTR __security_cookie_complement = ~(DEFAULT_SECURITY_COOKIE); 34 | 35 | typedef union 36 | { 37 | unsigned __int64 ft_scalar; 38 | FILETIME ft_struct; 39 | } FT; 40 | 41 | void __cdecl __security_init_cookie(void); 42 | 43 | void __cdecl 44 | __security_init_cookie(void) 45 | { 46 | UINT_PTR cookie; 47 | FT systime = { 0, }; 48 | LARGE_INTEGER perfctr; 49 | 50 | if (__security_cookie != DEFAULT_SECURITY_COOKIE) 51 | { 52 | __security_cookie_complement = ~__security_cookie; 53 | return; 54 | } 55 | 56 | GetSystemTimeAsFileTime(&systime.ft_struct); 57 | #ifdef _WIN64 58 | cookie = systime.ft_scalar; 59 | #else 60 | cookie = systime.ft_struct.dwLowDateTime; 61 | cookie ^= systime.ft_struct.dwHighDateTime; 62 | #endif 63 | 64 | cookie ^= GetCurrentProcessId (); 65 | cookie ^= GetCurrentThreadId (); 66 | cookie ^= GetTickCount (); 67 | 68 | QueryPerformanceCounter (&perfctr); 69 | #ifdef _WIN64 70 | cookie ^= perfctr.QuadPart; 71 | #else 72 | cookie ^= perfctr.LowPart; 73 | cookie ^= perfctr.HighPart; 74 | #endif 75 | 76 | #ifdef _WIN64 77 | cookie &= 0x0000ffffffffffffll; 78 | #endif 79 | 80 | if (cookie == DEFAULT_SECURITY_COOKIE) 81 | cookie = DEFAULT_SECURITY_COOKIE + 1; 82 | __security_cookie = cookie; 83 | __security_cookie_complement = ~cookie; 84 | } 85 | 86 | static int def_argc = 1; 87 | static char *def_argv[] = {"null.exe"}; 88 | 89 | static char *main_argv_mem = NULL; 90 | static int main_argc = 0; 91 | static char **main_argv_vect = NULL; 92 | 93 | #define ESCAPE_CHR '^' 94 | 95 | static int parse_command_line(const char *cmdline, char *argv_mem, char **argv_vect) 96 | { 97 | int in_quotes = 0; 98 | size_t j = 0; 99 | int argc = 0; 100 | 101 | char *next_ptr = argv_mem; 102 | int arg_length = 0; 103 | 104 | for(size_t i = 0; cmdline[i] != '\0'; i++) 105 | { 106 | char c = cmdline[i]; 107 | 108 | if(c == ESCAPE_CHR) 109 | { 110 | if(i > 0 && cmdline[i-1] == ESCAPE_CHR) 111 | { 112 | if(argv_mem != NULL) argv_mem[j++] = c; 113 | arg_length++; 114 | } 115 | } 116 | else if(in_quotes) 117 | { 118 | if(c == in_quotes) 119 | { 120 | if(i > 0) 121 | { 122 | if(cmdline[i-1] == ESCAPE_CHR) 123 | { 124 | if(argv_mem != NULL) argv_mem[j++] = c; 125 | arg_length++; 126 | } 127 | else 128 | { 129 | in_quotes = 0; 130 | } 131 | } 132 | else 133 | { 134 | in_quotes = 0; 135 | } 136 | } 137 | else 138 | { 139 | if(argv_mem != NULL) argv_mem[j++] = c; 140 | arg_length++; 141 | } 142 | } 143 | else 144 | { 145 | switch(c) 146 | { 147 | case '"': 148 | case '\'': 149 | if(!(i > 0 && cmdline[i-1] == ESCAPE_CHR)) 150 | { 151 | in_quotes = c; 152 | } 153 | else 154 | { 155 | if(argv_mem != NULL) argv_mem[j++] = c; 156 | arg_length++; 157 | } 158 | break; 159 | case ' ': 160 | case '\t': 161 | case '\n': 162 | case '\r': 163 | if(!(i > 0 && cmdline[i-1] == ESCAPE_CHR)) 164 | { 165 | if(arg_length > 0) 166 | { 167 | if(argv_vect != NULL && argv_mem != NULL) 168 | { 169 | argv_mem[j++] = '\0'; 170 | 171 | argv_vect[argc] = next_ptr; 172 | 173 | next_ptr = &(argv_mem[j]); 174 | } 175 | argc++; 176 | } 177 | arg_length = 0; 178 | } 179 | else 180 | { 181 | if(argv_mem != NULL) argv_mem[j++] = c; 182 | } 183 | break; 184 | default: 185 | if(argv_mem != NULL) argv_mem[j++] = c; 186 | arg_length++; 187 | } // switch 188 | } 189 | } 190 | 191 | if(arg_length > 0) 192 | { 193 | if(argv_vect != NULL && argv_mem != NULL) 194 | { 195 | argv_mem[j++] = '\0'; 196 | argv_vect[argc] = next_ptr; 197 | next_ptr = &(argv_mem[j]); 198 | } 199 | argc++; 200 | } 201 | 202 | return argc; 203 | } 204 | 205 | BOOL alloc_argv() 206 | { 207 | const char *cmd = GetCommandLineA(); 208 | 209 | if(cmd != NULL) 210 | { 211 | size_t mem_size = strlen(cmd)+1; 212 | main_argc = parse_command_line(cmd, NULL, NULL); 213 | 214 | if(main_argc > 0) 215 | { 216 | main_argv_mem = HeapAlloc(GetProcessHeap(), 0, mem_size); 217 | if(main_argv_mem == NULL) 218 | { 219 | return FALSE; 220 | } 221 | 222 | main_argv_vect = HeapAlloc(GetProcessHeap(), 0, main_argc * sizeof(char*)); 223 | if(main_argv_vect == NULL) 224 | { 225 | HeapFree(GetProcessHeap(), 0, main_argv_mem); 226 | return FALSE; 227 | } 228 | 229 | parse_command_line(cmd, main_argv_mem, main_argv_vect); 230 | return TRUE; 231 | } 232 | } 233 | 234 | return FALSE; 235 | } 236 | 237 | void free_argv() 238 | { 239 | if(main_argv_mem != NULL) 240 | { 241 | HeapFree(GetProcessHeap(), 0, main_argv_mem); 242 | } 243 | 244 | if(main_argv_vect != NULL) 245 | { 246 | HeapFree(GetProcessHeap(), 0, main_argv_vect); 247 | } 248 | } 249 | 250 | int main(int argc, char **argv); 251 | 252 | int WinMainCRTStartup(void) 253 | { 254 | __security_init_cookie(); 255 | if(alloc_argv()) 256 | { 257 | int r = main(main_argc, main_argv_vect); 258 | free_argv(); 259 | return r; 260 | } 261 | 262 | return main(def_argc, def_argv); 263 | } 264 | 265 | int mainCRTStartup(void) 266 | { 267 | __security_init_cookie(); 268 | if(alloc_argv()) 269 | { 270 | int r; 271 | AllocConsole(); 272 | r = main(main_argc, main_argv_vect); 273 | free_argv(); 274 | return r; 275 | } 276 | 277 | AllocConsole(); 278 | return main(def_argc, def_argv); 279 | } 280 | 281 | int 282 | #ifdef __GNUC__ 283 | __attribute__((externally_visible)) 284 | /* fix for LTO */ 285 | #endif 286 | atexit(void (*func)(void)) 287 | { 288 | (void)func; 289 | return 0; 290 | } 291 | -------------------------------------------------------------------------------- /nocrt_math_calc.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright (c) 2010-2024 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #include 23 | 24 | #include "nocrt.h" 25 | 26 | /* JH 2024: this all is pretty naive, but also fast way how make code portable, 27 | * but very ineffective! 28 | */ 29 | 30 | typedef union _editable_double_t 31 | { 32 | double number; 33 | unsigned char direct[sizeof(double)]; 34 | } editable_double_t; 35 | 36 | #ifdef __BIG_ENDIAN__ 37 | # define ED_FIRST_BYTE 0 38 | # define ED_SECOND_BYTE 1 39 | #else 40 | # define ED_FIRST_BYTE 7 41 | # define ED_SECOND_BYTE 6 42 | #endif 43 | 44 | 45 | #define P2_DEF_EXP 0x3FF /* exponent of number 1.0 */ 46 | 47 | #define REM_SING(_ed) _ed.direct[ED_FIRST_BYTE] &= 0x7F 48 | 49 | #define EXP_GET(_ed) (((_ed.direct[ED_FIRST_BYTE]&0x7F) << 4) | \ 50 | (_ed.direct[ED_SECOND_BYTE] >> 4)) 51 | 52 | #define EXP_SET(_ed, exp) _ed.direct[ED_FIRST_BYTE] &= 0x80; \ 53 | _ed.direct[ED_FIRST_BYTE] |= (exp >> 4) & 0x7F; \ 54 | _ed.direct[ED_SECOND_BYTE] &= 0x0F; _ed.direct[ED_SECOND_BYTE] |= exp << 4; 55 | 56 | static double eps_tables[NOCRT_DOUBLE_MAX_DIGITS] = 57 | { 58 | 1, 59 | 0.1d, 60 | 0.01d, 61 | 0.001d, 62 | 0.0001d, 63 | 0.00001d, 64 | 0.000001d, 65 | 0.0000001d, 66 | 0.00000001d, 67 | 0.000000001d, 68 | 0.0000000001d, 69 | 0.00000000001d, 70 | 0.000000000001d, 71 | 0.0000000000001d, 72 | 0.00000000000001d, 73 | 0.000000000000001d 74 | }; 75 | 76 | static double nocrt_eps(unsigned int digits) 77 | { 78 | if(digits >= NOCRT_DOUBLE_MAX_DIGITS) 79 | digits = NOCRT_DOUBLE_MAX_DIGITS-1; 80 | 81 | return eps_tables[digits]; 82 | } 83 | 84 | double nocrt_log_eps(double z, unsigned int digits) 85 | { 86 | double from; 87 | unsigned int counter = 0; 88 | double powered; 89 | double rval = 0; 90 | double eps = nocrt_eps(digits); 91 | editable_double_t last, test; 92 | short exp; 93 | 94 | if(isnan(z) || z < 0 || z == INFINITY || digits <= 0) 95 | { 96 | return NAN; 97 | } 98 | 99 | if(z == 0) 100 | { 101 | return -INFINITY; 102 | } 103 | 104 | /* get a exponent */ 105 | test.number = z; 106 | exp = EXP_GET(test); 107 | exp -= P2_DEF_EXP; 108 | /* set the exponent to same as have 1.0f */ 109 | EXP_SET(test, P2_DEF_EXP); 110 | z = test.number; 111 | 112 | counter = 3; /* ve start at 3! */ 113 | from = (z-1)/(z+1); /* the base of series */ 114 | powered = from; 115 | rval = powered; 116 | last.number = rval; 117 | REM_SING(last); /* same as abs(last) */ 118 | test.number = 0; 119 | 120 | while(last.number > test.number) 121 | { 122 | powered *= from * from; /* power on 3 */ 123 | last.number = (powered/counter); 124 | rval += last.number; 125 | counter += 2; /* we moving by 2 steps like 3! 5! 7! ... */ 126 | 127 | test.number = rval * eps; 128 | REM_SING(last); /* same as last = abs(last) */ 129 | REM_SING(test); /* same as test = abs(test) */ 130 | } 131 | 132 | return rval * 2 + exp * NOCRT_LN2; /* P2_LN2 is constant for fast calculation */ 133 | } 134 | 135 | double nocrt_sin_eps(double x, int digits) 136 | { 137 | editable_double_t test, last; 138 | double fact = 1.0f; 139 | double powered = x; 140 | double counter = 1.0f; 141 | double rval = x; 142 | double eps = nocrt_eps(digits); 143 | double add_sub = -1.0; 144 | 145 | if(x == NAN || x == INFINITY || digits <= 0) 146 | { 147 | return NAN; 148 | } 149 | 150 | last.number = x; 151 | test.number = x * eps; 152 | REM_SING(last); 153 | REM_SING(test); 154 | 155 | while(last.number > test.number) 156 | { 157 | powered *= x * x; 158 | fact *= (counter + 1) * (counter + 2); /* factorial calculation */ 159 | counter += 2; /* plus 2, because ve move by 2 */ 160 | last.number = powered/fact; 161 | rval += last.number * add_sub; 162 | test.number = rval * eps; 163 | add_sub = -add_sub; 164 | REM_SING(test); /* same as test = abs(test) */ 165 | REM_SING(last); /* same as last = abs(last) */ 166 | } 167 | 168 | return rval; 169 | } 170 | 171 | double nocrt_cos_eps(double x, int digits) 172 | { 173 | editable_double_t test, last; 174 | double fact = 2.0f; 175 | double powered = 1.0f; 176 | double counter = 2.0f; 177 | double rval = 1.0f; 178 | double eps = nocrt_eps(digits); 179 | double add_sub = -1.0; 180 | 181 | if(x == NAN || x == INFINITY || digits <= 0) 182 | { 183 | return NAN; 184 | } 185 | 186 | last.number = x; 187 | test.number = x * eps; 188 | REM_SING(last); 189 | REM_SING(test); 190 | 191 | while(last.number > test.number) 192 | { 193 | powered *= x * x; 194 | last.number = powered/fact; 195 | rval += last.number * add_sub; 196 | test.number = rval * eps; 197 | 198 | fact *= (counter + 1) * (counter + 2); /* factorial calculation */ 199 | counter += 2; /* plus 2, because ve move by 2 */ 200 | add_sub = -add_sub; 201 | REM_SING(test); /* same as test = abs(test) */ 202 | REM_SING(last); /* same as last = abs(last) */ 203 | } 204 | 205 | return rval; 206 | } 207 | 208 | double nocrt_tan_eps(double x, int digits) 209 | { 210 | double eps = nocrt_eps(digits); 211 | double a = nocrt_sin_eps(x, digits); 212 | double b = nocrt_cos_eps(x, digits); 213 | if(b >= -eps && b <= eps) 214 | { 215 | if(a >= 0) 216 | { 217 | return INFINITY; 218 | } 219 | else 220 | { 221 | return -INFINITY; 222 | } 223 | } 224 | 225 | return a/b; 226 | } 227 | 228 | float nocrt_logf(float x) 229 | { 230 | return nocrt_log_eps(x, NOCRT_FLOAT_MAX_DIGITS); 231 | } 232 | 233 | /* exports */ 234 | 235 | #ifndef NOCRT_FLOAT 236 | 237 | float nocrt_sinf(float x) 238 | { 239 | return nocrt_sin_eps(x, NOCRT_FLOAT_MAX_DIGITS); 240 | } 241 | 242 | float nocrt_cosf(float x) 243 | { 244 | return nocrt_cos_eps(x, NOCRT_FLOAT_MAX_DIGITS); 245 | } 246 | 247 | float nocrt_tanf(float x) 248 | { 249 | return nocrt_tan_eps(x, NOCRT_FLOAT_MAX_DIGITS); 250 | } 251 | 252 | double nocrt_log(double x) 253 | { 254 | return nocrt_log_eps(x, NOCRT_DOUBLE_MAX_DIGITS); 255 | } 256 | 257 | double nocrt_sin(double x) 258 | { 259 | return nocrt_sin_eps(x, NOCRT_DOUBLE_MAX_DIGITS); 260 | } 261 | 262 | double nocrt_cos(double x) 263 | { 264 | return nocrt_cos_eps(x, NOCRT_DOUBLE_MAX_DIGITS); 265 | } 266 | 267 | float nocrt_tan(float x) 268 | { 269 | return nocrt_tan_eps(x, NOCRT_DOUBLE_MAX_DIGITS); 270 | } 271 | 272 | #endif 273 | -------------------------------------------------------------------------------- /nocrt_file_win.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright 2023 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #ifdef NOCRT_FILE 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "nocrt.h" 30 | #include "nocrt_mem.h" 31 | #include "nocrt_file.h" 32 | 33 | #define NOCRT_FILE_MAGIC 0x0C0CF11E 34 | 35 | typedef struct _nocrt_FILE 36 | { 37 | uint32_t magic; 38 | HANDLE handle; 39 | DWORD stdhandle; 40 | int errcode; 41 | char charbuf; 42 | int charpresent; 43 | } nocrt_FILE; 44 | 45 | nocrt_FILE nocrt_fdesc[] = 46 | { 47 | {0x0C0CF11E, INVALID_HANDLE_VALUE, STD_INPUT_HANDLE, 0, 0, 0}, 48 | {0x0C0CF11E, INVALID_HANDLE_VALUE, STD_OUTPUT_HANDLE, 0, 0, 0}, 49 | {0x0C0CF11E, INVALID_HANDLE_VALUE, STD_ERROR_HANDLE, 0, 0, 0}, 50 | }; 51 | 52 | nocrt_FILE *nocrt_stdin = &nocrt_fdesc[0]; 53 | nocrt_FILE *nocrt_stdout = &nocrt_fdesc[1]; 54 | nocrt_FILE *nocrt_stderr = &nocrt_fdesc[2]; 55 | 56 | nocrt_FILE *nocrt_fopen(const char *filename, const char *mode) 57 | { 58 | BOOL m_read = FALSE; 59 | BOOL m_write = FALSE; 60 | BOOL m_append = FALSE; 61 | BOOL m_rw = FALSE; 62 | const char *p = mode; 63 | HANDLE hf = INVALID_HANDLE_VALUE; 64 | 65 | nocrt_FILE *mem = (nocrt_FILE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(nocrt_FILE)); 66 | 67 | while(*p != '\0') 68 | { 69 | switch(*p) 70 | { 71 | case 'w': 72 | case 'W': 73 | m_write = TRUE; 74 | break; 75 | case 'r': 76 | case 'R': 77 | m_read = TRUE; 78 | break; 79 | case 'a': 80 | case 'A': 81 | m_append = TRUE; 82 | break; 83 | case '+': 84 | m_rw = TRUE; 85 | break; 86 | } 87 | p++; 88 | } 89 | 90 | if(mem == NULL) return NULL; 91 | 92 | 93 | if(m_read && !m_rw) 94 | { 95 | hf = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 96 | } 97 | else if(m_read && m_rw) 98 | { 99 | hf = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 100 | } 101 | else if(m_write && !m_rw) 102 | { 103 | hf = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 104 | } 105 | else if(m_write && m_rw) 106 | { 107 | hf = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 108 | } 109 | else if(m_append) 110 | { 111 | hf = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 112 | if(hf != INVALID_HANDLE_VALUE) 113 | { 114 | SetFilePointer(hf, 0, NULL, FILE_END); 115 | } 116 | } 117 | 118 | if(hf == INVALID_HANDLE_VALUE) 119 | { 120 | HeapFree(GetProcessHeap(), 0, mem); 121 | return NULL; 122 | } 123 | 124 | mem->magic = NOCRT_FILE_MAGIC; 125 | mem->handle = hf; 126 | mem->stdhandle = 0; 127 | mem->errcode = 0; 128 | 129 | return mem; 130 | } 131 | 132 | #define CHECK_MAGIC(_f) ((_f) != NULL && (_f)->magic == NOCRT_FILE_MAGIC) 133 | 134 | void nocrt_fclose(nocrt_FILE *stream) 135 | { 136 | if(!CHECK_MAGIC(stream)) return; 137 | 138 | if(stream->stdhandle != 0) return; 139 | 140 | if(stream->handle != INVALID_HANDLE_VALUE) 141 | { 142 | CloseHandle(stream->handle); 143 | } 144 | 145 | HeapFree(GetProcessHeap(), 0, stream); 146 | } 147 | 148 | static BOOL nocrt_createdefault(nocrt_FILE *stream) 149 | { 150 | if(!CHECK_MAGIC(stream)) return FALSE; 151 | 152 | if(stream->stdhandle != 0 && stream->handle == INVALID_HANDLE_VALUE) 153 | { 154 | stream->handle = GetStdHandle(stream->stdhandle); 155 | } 156 | 157 | if(stream->handle == INVALID_HANDLE_VALUE) 158 | { 159 | return FALSE; 160 | } 161 | 162 | return TRUE; 163 | } 164 | 165 | size_t nocrt_fread(void *ptr, size_t size, size_t count, nocrt_FILE *stream) 166 | { 167 | DWORD readed = 0; 168 | DWORD readed_extra = 0; 169 | size_t total = size*count; 170 | unsigned char *uptr = ptr; 171 | 172 | if(total == 0) return 0; 173 | 174 | if(!nocrt_createdefault(stream)) return 0; 175 | 176 | if(stream->charpresent) 177 | { 178 | *uptr = stream->charbuf; 179 | stream->charpresent = 0; 180 | uptr++; 181 | 182 | total--; 183 | readed_extra++; 184 | } 185 | 186 | if(ReadFile(stream->handle, uptr, total, &readed, NULL)) 187 | { 188 | return (readed_extra + readed) / size; 189 | } 190 | 191 | return 0; 192 | } 193 | 194 | size_t nocrt_fwrite(const void *ptr, size_t size, size_t count, nocrt_FILE *stream) 195 | { 196 | DWORD writed; 197 | 198 | if(!nocrt_createdefault(stream)) return 0; 199 | 200 | if(stream->charpresent) 201 | { 202 | nocrt_fseek(stream, -1, FILE_CURRENT); 203 | } 204 | 205 | if(WriteFile(stream->handle, ptr, size*count, &writed, NULL)) 206 | { 207 | return writed / size; 208 | } 209 | 210 | return 0; 211 | } 212 | 213 | #pragma pack(push) 214 | #pragma pack(1) 215 | typedef union _store64 216 | { 217 | struct { 218 | uint32_t low; 219 | int32_t high; 220 | } a32; 221 | int64_t a64; 222 | } store64_t; 223 | #pragma pack(pop) 224 | 225 | int nocrt_fseek(nocrt_FILE *stream, long long offset, int origin) 226 | { 227 | store64_t s; 228 | s.a64 = offset; 229 | int win_origin = 0; 230 | DWORD r; 231 | 232 | if(!nocrt_createdefault(stream)) return 0; 233 | 234 | switch(origin) 235 | { 236 | case SEEK_SET: 237 | win_origin = FILE_BEGIN; 238 | stream->charpresent = 0; 239 | break; 240 | case SEEK_CUR: 241 | win_origin = FILE_CURRENT; 242 | if(stream->charpresent && offset != 0) 243 | { 244 | offset--; 245 | stream->charpresent = 0; 246 | } 247 | break; 248 | case SEEK_END: 249 | win_origin = FILE_END; 250 | stream->charpresent = 0; 251 | break; 252 | default: return 2; 253 | } 254 | 255 | r = SetFilePointer(stream->handle, s.a32.low, (PLONG)&(s.a32.high), win_origin); 256 | if(r != INVALID_SET_FILE_POINTER || GetLastError() == ERROR_SUCCESS) 257 | { 258 | return 0; 259 | } 260 | 261 | return 1; 262 | } 263 | 264 | long long nocrt_ftell(nocrt_FILE *stream) 265 | { 266 | DWORD r; 267 | 268 | store64_t s; 269 | s.a64 = 0; 270 | 271 | if(!nocrt_createdefault(stream)) return -1; 272 | 273 | r = SetFilePointer(stream->handle, s.a32.low, (PLONG)&(s.a32.high), FILE_CURRENT); 274 | if(r != INVALID_SET_FILE_POINTER || GetLastError() == ERROR_SUCCESS) 275 | { 276 | s.a32.low = r; 277 | 278 | if(stream->charpresent) 279 | { 280 | s.a64--; 281 | } 282 | 283 | return s.a64; 284 | } 285 | 286 | return -1; 287 | } 288 | 289 | int nocrt_fgetc(nocrt_FILE *stream) 290 | { 291 | unsigned char dest; 292 | 293 | if(nocrt_fread(&dest, 1, 1, stream) == 1) 294 | { 295 | return dest; 296 | } 297 | 298 | return EOF; 299 | } 300 | 301 | int nocrt_fputc(int c, nocrt_FILE *stream) 302 | { 303 | unsigned char dest = (unsigned char)c; 304 | 305 | if(nocrt_fwrite(&dest, 1, 1, stream) == 1) 306 | { 307 | return c; 308 | } 309 | 310 | return EOF; 311 | } 312 | 313 | char *nocrt_fgets(char* str, int num, nocrt_FILE* stream) 314 | { 315 | char *ptr = str; 316 | 317 | while(num > 0) 318 | { 319 | int c = nocrt_fgetc(stream); 320 | if(c == EOF) 321 | { 322 | if(ptr == str) 323 | { 324 | return NULL; 325 | } 326 | *ptr = '\0'; 327 | break; 328 | } 329 | 330 | if(c == '\n') 331 | { 332 | if(num == 1) 333 | { 334 | *ptr = '\0'; 335 | } 336 | else 337 | { 338 | *ptr = c; 339 | ptr++; 340 | *ptr = '\0'; 341 | } 342 | break; 343 | } 344 | 345 | *ptr = c; 346 | ptr++; 347 | num--; 348 | } 349 | 350 | return str; 351 | } 352 | 353 | int nocrt_fputs(const char *str, nocrt_FILE* stream) 354 | { 355 | size_t to_write = nocrt_strlen(str); 356 | 357 | if(nocrt_fwrite(str, 1, to_write, stream) == to_write) 358 | { 359 | return 1; 360 | } 361 | 362 | return EOF; 363 | } 364 | 365 | 366 | int nocrt_feof(nocrt_FILE *stream) 367 | { 368 | if(!nocrt_createdefault(stream)) return 1; 369 | 370 | if(!stream->charpresent) 371 | { 372 | DWORD readed = 0; 373 | if(ReadFile(stream->handle, &(stream->charbuf), 1, &readed, NULL)) 374 | { 375 | if(readed == 1) 376 | { 377 | stream->charpresent = 1; 378 | } 379 | else 380 | { 381 | return 1; 382 | } 383 | } 384 | else 385 | { 386 | return 1; 387 | } 388 | } 389 | 390 | 391 | return 0; 392 | } 393 | 394 | int nocrt_ferror(nocrt_FILE * stream) 395 | { 396 | return stream->errcode; 397 | } 398 | 399 | int nocrt_fflush(nocrt_FILE *stream) 400 | { 401 | if(stream == NULL) 402 | { 403 | return -1; 404 | } 405 | 406 | if(!nocrt_createdefault(stream)) return 1; 407 | 408 | if(!FlushFileBuffers(stream->handle)) 409 | { 410 | return 1; 411 | } 412 | 413 | return 0; 414 | } 415 | 416 | static void nocrt_vfprintf_putc(void *resource, char c) 417 | { 418 | nocrt_FILE *stream = (nocrt_FILE*)resource; 419 | 420 | nocrt_fputc(c, stream); 421 | } 422 | 423 | int nocrt_vfprintf(nocrt_FILE *stream, const char *format, va_list arg) 424 | { 425 | return nocrt_vformatf(stream, nocrt_vfprintf_putc, ULONG_MAX, format, arg); 426 | } 427 | 428 | int nocrt_fprintf(nocrt_FILE *stream, const char *format, ...) 429 | { 430 | int r; 431 | va_list arg; 432 | va_start(arg, format); 433 | r = nocrt_vfprintf(stream, format, arg); 434 | va_end(arg); 435 | 436 | return r; 437 | } 438 | 439 | void nocrt_rewind(nocrt_FILE *stream) 440 | { 441 | nocrt_fseek(stream, 0, SEEK_SET); 442 | } 443 | 444 | int nocrt_vprintf(const char *format, va_list arg) 445 | { 446 | return nocrt_vfprintf(nocrt_stdout, format, arg); 447 | } 448 | 449 | int nocrt_printf(const char *format, ...) 450 | { 451 | int r; 452 | va_list arg; 453 | va_start(arg, format); 454 | r = nocrt_vprintf(format, arg); 455 | va_end(arg); 456 | 457 | return r; 458 | } 459 | 460 | int nocrt_puts(const char *str) 461 | { 462 | int r = nocrt_fputs(str, nocrt_stdout); 463 | nocrt_fputc('\n', nocrt_stdout); 464 | 465 | return r; 466 | } 467 | 468 | int nocrt_getchar() 469 | { 470 | return nocrt_fgetc(nocrt_stdin); 471 | } 472 | 473 | int nocrt_putchar(int character) 474 | { 475 | return nocrt_fputc(character, stdout); 476 | } 477 | 478 | int nocrt_rename(const char *oldname, const char *newname) 479 | { 480 | if(MoveFileExA(oldname, newname, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) 481 | { 482 | return 0; 483 | } 484 | 485 | return -1; 486 | } 487 | 488 | /* some posix filesystem functions */ 489 | int nocrt_mkdir(const char *path, int mode) 490 | { 491 | (void)mode; 492 | 493 | return (CreateDirectoryA(path, NULL) != FALSE) ? 0 : -1; 494 | } 495 | 496 | int nocrt_unlink(const char *path) 497 | { 498 | return (DeleteFileA(path) != FALSE) ? 0 : -1; 499 | } 500 | 501 | #endif /* NOCRT_FILE */ 502 | -------------------------------------------------------------------------------- /nocrt.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************\ 2 | * MIT No Attribution * 3 | * * 4 | * Copyright 2023 Jaroslav Hensl * 5 | * * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy * 7 | * of this software and associated documentation files (the "Software"), to deal* 8 | * in the Software without restriction, including without limitation the rights * 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so. * 12 | * * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * 19 | * IN THE SOFTWARE. * 20 | \******************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "nocrt.h" 28 | 29 | #ifdef NOCRT 30 | 31 | #define ZEROES(_s) nocrt_memset(&(_s), 0, sizeof(_s)) 32 | 33 | size_t nocrt_strlen(const char *s) 34 | { 35 | const char *ptr = s; 36 | while(*ptr != '\0') ptr++; 37 | return ptr - s; 38 | } 39 | 40 | int nocrt_strcmp(const char *s1, const char *s2) 41 | { 42 | const unsigned char *p1 = (const unsigned char *)s1; 43 | const unsigned char *p2 = (const unsigned char *)s2; 44 | 45 | while(*p1 == *p2) 46 | { 47 | if(*p1 == '\0') break; 48 | p1++; 49 | p2++; 50 | } 51 | 52 | return *p1 - *p2; 53 | } 54 | 55 | int nocrt_strncmp(const char *s1, const char *s2, size_t num) 56 | { 57 | const unsigned char *p1 = (const unsigned char *)s1; 58 | const unsigned char *p2 = (const unsigned char *)s2; 59 | 60 | while(num > 0 && *p1 == *p2) 61 | { 62 | if(*p1 == '\0') break; 63 | p1++; 64 | p2++; 65 | num--; 66 | } 67 | 68 | if(num == 0) return 0; 69 | 70 | return *p1 - *p2; 71 | } 72 | 73 | int nocrt_memcmp(const void *ptr1, const void *ptr2, size_t num) 74 | { 75 | const unsigned char *p1 = (const unsigned char *)ptr1; 76 | const unsigned char *p2 = (const unsigned char *)ptr2; 77 | 78 | if(num == 0) return 0; 79 | 80 | while(num > 1 && *p1 == *p2) 81 | { 82 | p1++; 83 | p2++; 84 | num--; 85 | } 86 | 87 | return *p1 - *p2; 88 | } 89 | 90 | static char nocrt_case_norm(char c) 91 | { 92 | if(c >= 'A' && c <= 'Z') 93 | { 94 | return (c - 'A') + 'a'; 95 | } 96 | 97 | return c; 98 | } 99 | 100 | int nocrt_stricmp(const char *s1, const char *s2) 101 | { 102 | const char *p1 = s1; 103 | const char *p2 = s2; 104 | 105 | while(nocrt_case_norm(*p1) == nocrt_case_norm(*p2)) 106 | { 107 | if(*p1 == '\0') break; 108 | p1++; 109 | p2++; 110 | } 111 | 112 | return (unsigned char)nocrt_case_norm(*p1) - (unsigned char)nocrt_case_norm(*p2); 113 | } 114 | 115 | int nocrt_strnicmp(const char *s1, const char *s2, size_t num) 116 | { 117 | const unsigned char *p1 = (const unsigned char *)s1; 118 | const unsigned char *p2 = (const unsigned char *)s2; 119 | 120 | while(num > 0 && nocrt_case_norm(*p1) == nocrt_case_norm(*p2)) 121 | { 122 | if(*p1 == '\0') break; 123 | p1++; 124 | p2++; 125 | num--; 126 | } 127 | 128 | if(num == 0) return 0; 129 | 130 | return nocrt_case_norm(*p1) - nocrt_case_norm(*p2); 131 | } 132 | 133 | char *nocrt_strcpy(char *dst, const char *src) 134 | { 135 | char *pdst = dst; 136 | 137 | while(*src != '\0') 138 | { 139 | *pdst = *src; 140 | src++; 141 | pdst++; 142 | } 143 | 144 | *pdst = '\0'; 145 | 146 | return dst; 147 | } 148 | 149 | char *nocrt_strncpy(char *dst, const char *src, size_t num) 150 | { 151 | char *pdst = dst; 152 | 153 | while(num > 0 && *src != '\0') 154 | { 155 | *pdst = *src; 156 | src++; 157 | pdst++; 158 | num--; 159 | } 160 | 161 | if(num > 0) 162 | { 163 | *pdst = '\0'; 164 | } 165 | 166 | return dst; 167 | } 168 | 169 | char *nocrt_strcat(char *dst, const char *src) 170 | { 171 | size_t i = nocrt_strlen(dst); 172 | nocrt_strcpy(dst+i, src); 173 | return dst; 174 | } 175 | 176 | char *nocrt_strncat(char *dst, const char *src, size_t num) 177 | { 178 | char *ptr = dst + nocrt_strlen(dst); 179 | const char *sptr = src; 180 | while(num-- > 0) 181 | { 182 | if(*sptr == '\0') break; 183 | 184 | *ptr = *sptr; 185 | ptr++; 186 | sptr++; 187 | } 188 | 189 | *ptr = '\0'; 190 | 191 | return dst; 192 | } 193 | 194 | void *nocrt_memcpy(void *dst, const void *src, size_t num) 195 | { 196 | if(num % sizeof(long) == 0) 197 | { 198 | num /= sizeof(long); 199 | unsigned long *pdst32 = dst; 200 | const unsigned long *psrc32 = src; 201 | 202 | while(num--) *(pdst32++) = *(psrc32++); 203 | } 204 | else 205 | { 206 | unsigned char *pdst = dst; 207 | const unsigned char *psrc = src; 208 | 209 | while(num--) *(pdst++) = *(psrc++); 210 | } 211 | 212 | return dst; 213 | } 214 | 215 | char *nocrt_strrchr(const char *str, int character) 216 | { 217 | char *r = NULL; 218 | while(*str != '\0') 219 | { 220 | if(*str == character) 221 | { 222 | r = (char *)str; 223 | } 224 | str++; 225 | } 226 | 227 | return r; 228 | } 229 | 230 | char *nocrt_strchr(const char *str, int character) 231 | { 232 | char *r = NULL; 233 | while(*str != '\0') 234 | { 235 | if(*str == character) 236 | { 237 | r = (char *)str; 238 | break; 239 | } 240 | str++; 241 | } 242 | 243 | return r; 244 | } 245 | 246 | char *nocrt_strstr(const char *str1, const char *str2) 247 | { 248 | size_t i; 249 | size_t str1_len = nocrt_strlen(str1); 250 | size_t str2_len = nocrt_strlen(str2); 251 | size_t cmpmax = str1_len - str2_len; 252 | 253 | if(str2_len > str1_len) 254 | { 255 | return NULL; 256 | } 257 | 258 | for(i = 0; i <= cmpmax; i++) 259 | { 260 | if(nocrt_strncmp(str1+i, str2, str2_len) == 0) 261 | { 262 | return (char*)str1+i; 263 | } 264 | } 265 | 266 | return NULL; 267 | } 268 | 269 | unsigned long int nocrt_strtoul(const char* str, char** endptr, int base) 270 | { 271 | unsigned long num = 0; 272 | const char* ptr = str; 273 | unsigned long digit; 274 | int numcnt = 0; 275 | 276 | for(; *ptr != '\0'; ptr++) 277 | { 278 | switch(*ptr) 279 | { 280 | case '0': 281 | if(num == 0 && base == 0) 282 | { 283 | base = 8; 284 | } 285 | /* FALLTHRU */ 286 | case '1' ... '9': 287 | digit = *ptr - '0'; 288 | break; 289 | case 'A' ... 'Z': 290 | digit = *ptr - 'A' + 10; 291 | break; 292 | case 'x': 293 | if(num == 0 && (base = 8 || base == 16 || base == 0)) 294 | { 295 | digit = 0; 296 | base = 16; 297 | break; 298 | } 299 | /* FALLTHRU */ 300 | case 'a' ... 'w': 301 | case 'y' ... 'z': 302 | digit = *ptr - 'a' + 10; 303 | break; 304 | case '-': 305 | case '+': 306 | numcnt++; 307 | continue; 308 | default: 309 | if(nocrt_isspace(*ptr) && numcnt == 0) 310 | { 311 | continue; 312 | } 313 | goto strtoul_dingo; 314 | } 315 | 316 | numcnt++; 317 | 318 | if(digit != 0) 319 | { 320 | if(base == 0) 321 | { 322 | base = 10; 323 | } 324 | } 325 | 326 | if((int)digit < base) 327 | { 328 | num *= base; 329 | num += digit; 330 | } 331 | else 332 | { 333 | break; 334 | } 335 | } 336 | strtoul_dingo: 337 | 338 | if(endptr != NULL) 339 | { 340 | *endptr = (char*)ptr; 341 | } 342 | 343 | return num; 344 | } 345 | 346 | long int nocrt_strtol(const char* str, char** endptr, int base) 347 | { 348 | unsigned long num = 0; 349 | const char* ptr = str; 350 | unsigned long digit; 351 | int negative = 0; 352 | int numcnt = 0; 353 | 354 | for(; *ptr != '\0'; ptr++) 355 | { 356 | switch(*ptr) 357 | { 358 | case '0': 359 | if(num == 0 && base == 0) 360 | { 361 | base = 8; 362 | } 363 | /* FALLTHRU */ 364 | case '1' ... '9': 365 | digit = *ptr - '0'; 366 | break; 367 | case 'A' ... 'Z': 368 | digit = *ptr - 'A' + 10; 369 | break; 370 | case 'x': 371 | if(num == 0 && (base = 8 || base == 16 || base == 0)) 372 | { 373 | digit = 0; 374 | base = 16; 375 | break; 376 | } 377 | /* FALLTHRU */ 378 | case 'a' ... 'w': 379 | case 'y' ... 'z': 380 | digit = *ptr - 'a' + 10; 381 | break; 382 | case '-': 383 | numcnt++; 384 | negative = 1; 385 | continue; 386 | case '+': 387 | numcnt++; 388 | continue; 389 | default: 390 | if(nocrt_isspace(*ptr) && numcnt == 0) 391 | { 392 | continue; 393 | } 394 | goto strtol_dingo; 395 | } 396 | numcnt++; 397 | 398 | if(digit != 0) 399 | { 400 | if(base == 0) 401 | { 402 | base = 10; 403 | } 404 | } 405 | 406 | if((int)digit < base) 407 | { 408 | num *= base; 409 | num += digit; 410 | } 411 | else 412 | { 413 | break; 414 | } 415 | } 416 | strtol_dingo: 417 | if(negative) 418 | { 419 | num = ~num + 1; 420 | } 421 | 422 | if(endptr != NULL) 423 | { 424 | *endptr = (char*)ptr; 425 | } 426 | 427 | return num; 428 | } 429 | 430 | long int nocrt_atol(const char *str) 431 | { 432 | return nocrt_strtol(str, NULL, 10); 433 | } 434 | 435 | int nocrt_atoi(const char *str) 436 | { 437 | return (int)nocrt_strtol(str, NULL, 10); 438 | } 439 | 440 | #define FMT_LEN_NORMAL 0 441 | #define FMT_LEN_HALF -1 442 | #define FMT_LEN_LONG 1 443 | #define FMT_LEN_LONGLONG 2 444 | #define FMT_LEN_TURBO 100 445 | 446 | typedef struct _fmt_spec 447 | { 448 | int dec_point; 449 | int width; 450 | int width_dec; 451 | int length; 452 | int leftalign; 453 | int sign_force; 454 | int sign_pad; 455 | int num_prefix; 456 | int zerofill; 457 | } fmt_spec_t; 458 | 459 | typedef unsigned long long maxint_t; 460 | typedef signed long long maxsint_t; 461 | #define MAXINT_SIGN (((unsigned long long)LLONG_MAX)+1) 462 | 463 | #define MAXINT_BUFFER 128+2+1 464 | 465 | static size_t vformat_dec(void *resource, formatf_callback_t f, size_t *pn, fmt_spec_t *spec, char type, va_list *args) 466 | { 467 | static char buf[MAXINT_BUFFER]; 468 | static const char alphabet[] = "0123456789abcdef"; 469 | static const char Alphabet[] = "0123456789ABCDEF"; 470 | 471 | const char *alpha = alphabet; 472 | 473 | maxint_t v = 0; 474 | int is_sign = 0; 475 | int is_negative = 0; 476 | maxint_t base = 10; 477 | size_t buf_pos = 0; 478 | 479 | switch(type) 480 | { 481 | case 'i': 482 | case 'd': 483 | is_sign = 1; 484 | base = 10; 485 | break; 486 | case 'u': base = 10; break; 487 | case 'o': base = 8; break; 488 | case 'x': base = 16; break; 489 | case 'X': base = 16; alpha = Alphabet; break; 490 | case 'b': base = 2; break; 491 | } 492 | 493 | if(spec->length <= -2) 494 | { 495 | if(is_sign) v = (maxint_t)((maxsint_t)va_arg(*args, int)); 496 | else v = va_arg(*args, int); 497 | } 498 | else if(spec->length == -1) 499 | { 500 | if(is_sign) v = (maxint_t)((maxsint_t)va_arg(*args, int)); 501 | else v = va_arg(*args, int); 502 | } 503 | else if(spec->length == 0) 504 | { 505 | if(is_sign) v = (maxint_t)((maxsint_t)va_arg(*args, int)); 506 | else v = va_arg(*args, unsigned int); 507 | } 508 | else if(spec->length == 1) 509 | { 510 | if(is_sign) v = (maxint_t)((maxsint_t)va_arg(*args, long)); 511 | else v = va_arg(*args, unsigned long); 512 | } 513 | else 514 | { 515 | if(is_sign) v = (maxint_t)((maxsint_t)va_arg(*args, long long)); 516 | else v = va_arg(*args, unsigned long long); 517 | } 518 | 519 | if(is_sign) 520 | { 521 | if((v & MAXINT_SIGN) != 0) 522 | { 523 | is_negative = 1; 524 | v = (~v)+1; 525 | } 526 | } 527 | 528 | if(spec->zerofill) 529 | { 530 | nocrt_memset(buf, '0', MAXINT_BUFFER); 531 | } 532 | else 533 | { 534 | nocrt_memset(buf, ' ', MAXINT_BUFFER); 535 | } 536 | 537 | if(v == 0) 538 | { 539 | buf[buf_pos++] = '0'; 540 | } 541 | 542 | while(v) 543 | { 544 | buf[buf_pos] = alpha[v % base]; 545 | v /= base; 546 | buf_pos++; 547 | } 548 | 549 | if(spec->width > 0) 550 | { 551 | if((size_t)spec->width > buf_pos) 552 | { 553 | buf_pos = spec->width; 554 | } 555 | } 556 | 557 | if(spec->num_prefix) 558 | { 559 | switch(type) 560 | { 561 | case 'X': 562 | buf[buf_pos++] = 'X'; 563 | buf[buf_pos++] = '0'; 564 | break; 565 | case 'x': 566 | buf[buf_pos++] = 'x'; 567 | buf[buf_pos++] = '0'; 568 | break; 569 | case 'o': 570 | buf[buf_pos++] = '0'; 571 | break; 572 | case 'b': 573 | buf[buf_pos++] = 'b'; 574 | buf[buf_pos++] = '0'; 575 | break; 576 | } 577 | } 578 | 579 | if(is_negative) 580 | { 581 | buf[buf_pos++] = '-'; 582 | } 583 | else if(spec->sign_force) 584 | { 585 | buf[buf_pos++] = '+'; 586 | } 587 | else if(spec->sign_pad) 588 | { 589 | buf[buf_pos++] = ' '; 590 | } 591 | 592 | for(size_t i = buf_pos; i > 0; i--) 593 | { 594 | if((*pn) == 0) break; 595 | 596 | f(resource, buf[i-1]); 597 | 598 | (*pn)--; 599 | } 600 | 601 | return buf_pos; 602 | } 603 | 604 | typedef double maxfloat_t; 605 | #define MAXFLOAT_BUFFER 64 606 | 607 | static size_t vformat_float(void *resource, formatf_callback_t f, size_t *pn, fmt_spec_t *spec, char type, va_list *args) 608 | { 609 | static char bufup[MAXFLOAT_BUFFER]; 610 | static char bufdown[MAXFLOAT_BUFFER]; 611 | size_t posup = 0; 612 | size_t posdown = 0; 613 | int negative = 0; 614 | size_t r = 0; 615 | (void)type; 616 | 617 | maxfloat_t v, v1, v2, rf = 0.5; 618 | 619 | if(spec->length < 0) 620 | { 621 | v = va_arg(*args, double); // float are stored as double for variable length arguments 622 | } 623 | else if(spec->length >= FMT_LEN_TURBO) 624 | { 625 | v = va_arg(*args, long double); 626 | } 627 | else 628 | { 629 | v = va_arg(*args, double); 630 | } 631 | 632 | #ifdef NOCRT_FLOAT 633 | int width_dec = spec->width_dec; 634 | if(width_dec == 0) width_dec = 6; 635 | 636 | if(v == INFINITY || v == -INFINITY) 637 | { 638 | if(v == -INFINITY) 639 | { 640 | f(resource, '-'); 641 | r++; 642 | } 643 | else if(spec->sign_force) 644 | { 645 | f(resource, '+'); 646 | r++; 647 | } 648 | 649 | f(resource, 'i'); 650 | f(resource, 'n'); 651 | f(resource, 'f'); 652 | 653 | r += 3; 654 | return r; 655 | } 656 | 657 | if(isnan(v)) 658 | { 659 | f(resource, 'n'); 660 | f(resource, 'a'); 661 | f(resource, 'n'); 662 | return 3; 663 | } 664 | 665 | if(v < 0.0f) 666 | { 667 | negative = 1; 668 | v = 0 - v; 669 | } 670 | 671 | /* round last decimal place */ 672 | for(int i = 0; i < width_dec; i++) 673 | { 674 | rf /= 10; 675 | } 676 | v += rf; 677 | 678 | if(v < 1.0f) 679 | { 680 | bufup[posup++] = '0'; 681 | } 682 | 683 | v2 = nocrt_modf(v, &v1); 684 | 685 | while(v1 >= 1 && posup < MAXFLOAT_BUFFER) 686 | { 687 | unsigned int d = (unsigned int)nocrt_fmod(v1, 10); 688 | if(d >= 10) d = 0; 689 | 690 | bufup[posup] = '0' + d; 691 | posup++; 692 | v1 /= 10.0f; 693 | } 694 | 695 | for(int i = 0; i < width_dec && posdown < MAXFLOAT_BUFFER; i++) 696 | { 697 | maxfloat_t d; 698 | v2 = nocrt_modf(v2*10.0f, &d); 699 | unsigned int di = (unsigned int)d; 700 | if(di >= 10) di = 0; 701 | 702 | bufdown[posdown] = '0' + di; 703 | posdown++; 704 | } 705 | 706 | /* print sign */ 707 | if(negative) 708 | { 709 | if(*pn > 0) 710 | { 711 | f(resource, '-'); 712 | (*pn)--; 713 | } 714 | r += 1; 715 | } 716 | else if(spec->sign_force) 717 | { 718 | if(*pn > 0) 719 | { 720 | f(resource, '+'); 721 | (*pn)--; 722 | } 723 | r += 1; 724 | } 725 | else if(spec->sign_pad) 726 | { 727 | if(*pn > 0) 728 | { 729 | f(resource, ' '); 730 | (*pn)--; 731 | } 732 | r += 1; 733 | } 734 | 735 | /* print digits before decimal point */ 736 | for(size_t i = posup; i > 0; i--) 737 | { 738 | if(*pn == 0) break; 739 | 740 | f(resource, bufup[i-1]); 741 | 742 | (*pn)--; 743 | } 744 | r += posup; 745 | 746 | /* print decimal point */ 747 | if(width_dec != 0) 748 | { 749 | r += 1; 750 | 751 | if(*pn > 0) 752 | { 753 | f(resource, '.'); 754 | (*pn)--; 755 | } 756 | } 757 | 758 | /* print digits after */ 759 | for(size_t i = 0; i < posdown; i++) 760 | { 761 | if(*pn == 0) break; 762 | 763 | f(resource, bufdown[i]); 764 | 765 | (*pn)--; 766 | } 767 | r += posdown; 768 | #endif /* NOCRT_FLOAT */ 769 | 770 | return r; 771 | } 772 | 773 | static const char vformatf_nullstr[] = "(null)"; 774 | 775 | size_t nocrt_vformatf(void *resource, formatf_callback_t f, size_t n, const char *fmt, va_list args) 776 | { 777 | int ctrl = 0; 778 | size_t left = n; 779 | size_t cnt = 0; 780 | fmt_spec_t spec; 781 | ZEROES(spec); 782 | 783 | for(const char *ptr = fmt; *ptr != '\0'; ptr++) 784 | { 785 | if(ctrl) 786 | { 787 | switch(*ptr) 788 | { 789 | /* final format specifier */ 790 | case 'i': 791 | case 'd': 792 | case 'u': 793 | case 'o': 794 | case 'x': 795 | case 'X': 796 | case 'b': /* ext: binary */ 797 | cnt += vformat_dec(resource, f, &left, &spec, *ptr, &args); 798 | ctrl = 0; 799 | ZEROES(spec); 800 | break; 801 | case 'f': 802 | case 'F': 803 | case 'e': 804 | case 'E': 805 | case 'g': 806 | case 'G': 807 | cnt += vformat_float(resource, f, &left, &spec, *ptr, &args); 808 | ctrl = 0; 809 | ZEROES(spec); 810 | break; 811 | case 'c': 812 | if(spec.length > 0) 813 | { 814 | /*wchar_t junk = */va_arg(args, int); 815 | /* TODO: wchar */ 816 | } 817 | else 818 | { 819 | char c = va_arg(args, int); 820 | if(left){f(resource, c); left--;} 821 | cnt++; 822 | ctrl = 0; 823 | ZEROES(spec); 824 | } 825 | break; 826 | case 's': 827 | if(spec.length > 0) 828 | { 829 | /*wchar_t *junk = */va_arg(args, const wchar_t*); 830 | /* TODO: wchar */ 831 | } 832 | else 833 | { 834 | const char *ptr = va_arg(args, const char*); 835 | size_t ptr_len; 836 | if(ptr == NULL) 837 | { 838 | ptr = vformatf_nullstr; 839 | } 840 | 841 | ptr_len = nocrt_strlen(ptr); 842 | 843 | /* right align of string */ 844 | if(!spec.leftalign && ptr_len < (size_t)spec.width) 845 | { 846 | for(size_t i = 0; i < spec.width-ptr_len; i++) 847 | { 848 | if(left){f(resource, ' '); left--;} 849 | cnt++; 850 | } 851 | } 852 | 853 | /* out the string */ 854 | for(size_t i = 0; i < ptr_len; i++) 855 | { 856 | if(left){f(resource, ptr[i]); left--;} 857 | cnt++; 858 | } 859 | 860 | /* left align of string */ 861 | if(spec.leftalign && ptr_len < (size_t)spec.width) 862 | { 863 | for(size_t i = 0; i < spec.width-ptr_len; i++) 864 | { 865 | if(left){f(resource, ' '); left--;} 866 | cnt++; 867 | } 868 | } 869 | } 870 | ctrl = 0; 871 | ZEROES(spec); 872 | break; 873 | case 'p': 874 | if(sizeof(void*) == 4) 875 | { 876 | spec.length = FMT_LEN_LONG; 877 | } 878 | else if(sizeof(void*) == 8) 879 | { 880 | spec.length = FMT_LEN_LONGLONG; 881 | } 882 | cnt += vformat_dec(resource, f, &left, &spec, 'x', &args); 883 | ctrl = 0; 884 | ZEROES(spec); 885 | break; 886 | case '%': 887 | if(left){f(resource, '%'); left--;} 888 | cnt++; 889 | ctrl = 0; 890 | ZEROES(spec); 891 | break; 892 | case 'n': 893 | /* use number function to calculate number size but with no output */ 894 | vformat_dec(resource, f, 0, &spec, *ptr, &args); 895 | ctrl = 0; 896 | ZEROES(spec); 897 | break; 898 | /* flags */ 899 | case '-': spec.leftalign = 1; break; 900 | case '+': spec.sign_force = 1; break; 901 | case ' ': spec.sign_pad = 1; break; 902 | case '#': spec.num_prefix = 1; break; 903 | /* length */ 904 | case 'h': spec.length += FMT_LEN_HALF; break; 905 | case 'l': spec.length += FMT_LEN_LONG; break; 906 | case 'z': spec.length += FMT_LEN_LONGLONG; break; 907 | case 'L': spec.length += FMT_LEN_TURBO; break; 908 | /* width / flag */ 909 | case '0': 910 | if(spec.dec_point == 0 && spec.width == 0) 911 | { 912 | spec.zerofill = 1; 913 | break; 914 | } 915 | /* FALLTHRU */ 916 | /* width */ 917 | case '1' ... '9': 918 | if(spec.dec_point) 919 | { 920 | spec.width_dec *= 10; 921 | spec.width_dec += *ptr - '0'; 922 | } 923 | else 924 | { 925 | spec.width *= 10; 926 | spec.width += *ptr - '0'; 927 | } 928 | break; 929 | /* precision */ 930 | case '.': spec.dec_point = 1; break; 931 | /* width from args */ 932 | case '*': 933 | if(spec.dec_point) 934 | { 935 | spec.width_dec = va_arg(args, int); 936 | } 937 | else 938 | { 939 | spec.width = va_arg(args, int); 940 | } 941 | break; 942 | } 943 | } 944 | else 945 | { 946 | if(*ptr != '%') 947 | { 948 | if(left){f(resource, *ptr); left--;} 949 | cnt++; 950 | } 951 | else 952 | { 953 | ctrl = 1; 954 | } 955 | } 956 | } 957 | 958 | return cnt; 959 | } 960 | 961 | static void nocrt_vsprintf_putc(void *res, char c) 962 | { 963 | char **pptr = (char **)res; 964 | 965 | **pptr = c; 966 | (*pptr)++; 967 | } 968 | 969 | int nocrt_vsnprintf(char *str, size_t n, const char *format, va_list arg) 970 | { 971 | char *ptr = str; 972 | 973 | size_t pos = 0; 974 | 975 | if(str == NULL) 976 | { 977 | pos = nocrt_vformatf(&ptr, nocrt_vsprintf_putc, 0, format, arg); 978 | } 979 | else 980 | { 981 | pos = nocrt_vformatf(&ptr, nocrt_vsprintf_putc, n, format, arg); 982 | size_t term = NOCRT_MIN(pos, n-1); 983 | str[term] = '\0'; 984 | } 985 | 986 | return (int)pos; 987 | } 988 | 989 | int nocrt_vsprintf(char *str, const char *format, va_list arg) 990 | { 991 | return nocrt_vsnprintf(str, ULONG_MAX, format, arg); 992 | } 993 | 994 | int nocrt_sprintf(char *str, const char *format, ...) 995 | { 996 | int res = 0; 997 | va_list vl; 998 | va_start(vl, format); 999 | res = nocrt_vsprintf(str, format, vl); 1000 | va_end(vl); 1001 | 1002 | return res; 1003 | } 1004 | 1005 | /* all ctype function ignores locale and works as locale "C" */ 1006 | int nocrt_tolower(int c) 1007 | { 1008 | if(c >= 'A' && c <= 'Z') 1009 | { 1010 | return (c - 'A') + 'a'; 1011 | } 1012 | 1013 | return c; 1014 | } 1015 | 1016 | int nocrt_toupper(int c) 1017 | { 1018 | if(c >= 'a' && c <= 'z') 1019 | { 1020 | return (c - 'a') + 'A'; 1021 | } 1022 | 1023 | return c; 1024 | } 1025 | 1026 | int nocrt_isdigit(int c) 1027 | { 1028 | if(c >= '0' && c <= '9') 1029 | { 1030 | return 1; 1031 | } 1032 | 1033 | return 0; 1034 | } 1035 | 1036 | int nocrt_isxdigit(int c) 1037 | { 1038 | if(c >= '0' && c <= '9') 1039 | { 1040 | return 1; 1041 | } 1042 | 1043 | if(c >= 'A' && c <= 'F') 1044 | { 1045 | return 1; 1046 | } 1047 | 1048 | if(c >= 'a' && c <= 'f') 1049 | { 1050 | return 1; 1051 | } 1052 | 1053 | return 0; 1054 | } 1055 | 1056 | int nocrt_isspace(int c) 1057 | { 1058 | switch(c) 1059 | { 1060 | case ' ': 1061 | case '\t': 1062 | case '\n': 1063 | case '\v': 1064 | case '\f': 1065 | case '\r': 1066 | return 1; 1067 | } 1068 | 1069 | return 0; 1070 | } 1071 | 1072 | int nocrt_isblank(int c) 1073 | { 1074 | switch(c) 1075 | { 1076 | case ' ': 1077 | case '\t': 1078 | return 1; 1079 | } 1080 | 1081 | return 0; 1082 | } 1083 | 1084 | int nocrt_islower(int c) 1085 | { 1086 | if(c >= 'a' && c <= 'z') 1087 | { 1088 | return 1; 1089 | } 1090 | 1091 | return 0; 1092 | } 1093 | 1094 | int nocrt_isupper(int c) 1095 | { 1096 | if(c >= 'A' && c <= 'Z') 1097 | { 1098 | return 1; 1099 | } 1100 | 1101 | return 0; 1102 | } 1103 | 1104 | int nocrt_isalpha(int c) 1105 | { 1106 | return nocrt_islower(c) || nocrt_isupper(c); 1107 | } 1108 | 1109 | int nocrt_isalnum(int c) 1110 | { 1111 | return nocrt_isalpha(c) || nocrt_isdigit(c); 1112 | } 1113 | 1114 | int nocrt_iscntrl(int c) 1115 | { 1116 | if(c <= 0x1f) /* from NUL to US */ 1117 | return 1; 1118 | 1119 | if(c == 0x7f) /* DEL */ 1120 | return 1; 1121 | 1122 | return 0; 1123 | } 1124 | 1125 | int nocrt_isprint(int c) 1126 | { 1127 | return !nocrt_iscntrl(c); 1128 | } 1129 | 1130 | int nocrt_isgraph(int c) 1131 | { 1132 | return (c != ' ') && nocrt_isprint(c); 1133 | } 1134 | 1135 | int nocrt_ispunct(int c) 1136 | { 1137 | return nocrt_isgraph(c) && !nocrt_isalnum(c); 1138 | } 1139 | 1140 | #define MEMSET_DEF(_fname) \ 1141 | void *_fname(void *ptr, int value, size_t num){ \ 1142 | unsigned char *pdst = ptr; \ 1143 | while(num--) *(pdst++) = value; \ 1144 | return ptr; } 1145 | 1146 | MEMSET_DEF(nocrt_memset) 1147 | 1148 | #ifdef NOCRT_BUILD_MEMSET 1149 | 1150 | #ifdef memset 1151 | #undef memset 1152 | #endif 1153 | 1154 | MEMSET_DEF(memset) 1155 | #endif 1156 | 1157 | #endif /* NOCRT */ 1158 | 1159 | --------------------------------------------------------------------------------