diff --git a/djstdlib/.clangd b/djstdlib/.clangd deleted file mode 100644 index 5467e39..0000000 --- a/djstdlib/.clangd +++ /dev/null @@ -1,3 +0,0 @@ -CompileFlags: - Add: - - -DOS_LINUX diff --git a/djstdlib/app.cpp b/djstdlib/app.cpp deleted file mode 100644 index d1a01a3..0000000 --- a/djstdlib/app.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "core.cpp" -#include "core.h" - -int main(int argc, char **argv) { - int statusCode = 0; - initialiseCore(); - Arena *arena = arenaAlloc(Megabytes(64)); - list args = getArgs(arena, argc, argv); - - prinft("%S", strSplit(arena, "-"_s, "hallo-world"_s)); - - return statusCode; -} diff --git a/djstdlib/build b/djstdlib/build deleted file mode 100644 index 5601ac6..0000000 --- a/djstdlib/build +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -g++ -g -g3 -lm -DOS_LINUX=1 -DENABLE_ASSERT=1 ./app.cpp -o ./target/app diff --git a/djstdlib/build.bat b/djstdlib/build.bat deleted file mode 100644 index 4d507fb..0000000 --- a/djstdlib/build.bat +++ /dev/null @@ -1,27 +0,0 @@ -@echo off - -if NOT EXIST .\target mkdir .\target - -set commonLinkerFlags=-opt:ref -set commonCompilerFlags=^ - -MT %= Make sure the C runtime library is statically linked =%^ - -Gm- %= Turns off incremental building =%^ - -nologo %= No one cares you made the compiler Microsoft =%^ - -Oi %= Always use intrinsics =%^ - -EHa- %= Disable exception handling =%^ - -GR- %= Never use runtime type info from C++ =%^ - -WX -W4 -wd4201 -wd4100 -wd4189 -wd4505 %= Compiler warnings, -WX warnings as errors, -W4 warning level 4, -wdXXXX disable warning XXXX =%^ - -DAPP_DEBUG=0 -DENABLE_ASSERT=1 -DOS_WINDOWS=1 %= Custom #defines =%^ - -D_CRT_SECURE_NO_WARNINGS=1^ - -FC %= Full path of source code file in diagnostics =%^ - -Zi %= Generate debugger info =% - -pushd .\target -cl %commonCompilerFlags% -Fe:.\app.exe ..\app.cpp /link -incremental:no %commonLinkerFlags% -popd - -exit /b - -:error -echo Failed with error #%errorlevel%. -exit /b %errorlevel% diff --git a/djstdlib/core.cpp b/djstdlib/core.cpp deleted file mode 100644 index 0f931ca..0000000 --- a/djstdlib/core.cpp +++ /dev/null @@ -1,436 +0,0 @@ -#include "os.cpp" -#include -#include -#include "core.h" -#define STB_SPRINTF_IMPLEMENTATION -#include "vendor/stb_sprintf.h" - -void *pushSizeFill(Arena *arena, size_t bytes, byte fill) { - if (arena->capacity - arena->head >= bytes) { - void *ptr = (char *)arena->memory + arena->head; - arena->head += bytes; - memset(ptr, fill, bytes); - return ptr; - } - return 0; -} - -void *pushSize(Arena *arena, size_t bytes) { - if (arena->capacity - arena->head >= bytes) { - void *ptr = (char *)arena->memory + arena->head; - arena->head += bytes; - return ptr; - } - return 0; -} - -Arena *arenaAlloc(size_t capacity) { - Arena *result = (Arena *)os_alloc(sizeof(Arena) + capacity); - result->memory = result + sizeof(Arena); - result->capacity = capacity; - result->head = 0; - return result; -} - -void arenaFree(Arena *arena) { - os_free(arena, arena->capacity); -} - -void arenaFreeFrom(Arena *arena, size_t position) { - arena->head = position; -} - -void arenaPopTo(Arena *arena, void *position) { - arena->head = (byte *)position - (byte *)arena->memory; -} - -Arena *scratchArenas[2]; - -void initialiseCore() { - for (EachInArray(scratchArenas, i)) { - scratchArenas[i] = arenaAlloc(Megabytes(64)); - } -} - -Scratch scratchStart(Arena **conflicts, size_t conflictCount) { - Scratch scratch = {0}; - for (size_t i = 0; i < ArrayCount(scratchArenas); i += 1) { - bool conflicted = false; - for (Arena **conflict = conflicts; conflict < conflicts + conflictCount; conflict += 1) { - if (*conflict == scratchArenas[i]) { - conflicted = true; - break; - } - } - if (conflicted == false) { - scratch.arena = scratchArenas[i]; - scratch.start = scratch.arena->head; - break; - } - } - return scratch; -} - -#define DeferLoop(begin_stmnt, end_stmnt) for(int __defer_i = ((begin_stmnt), 0); __defer_i < 1; (++__defer_i, (end_stmnt))) -#define WithScratch(scratchName) Scratch scratchName; DeferLoop(scratchName = scratchStart(0, 0), scratchEnd(scratchName)) - -void scratchEnd(Scratch scratch) { - arenaFreeFrom(scratch.arena, scratch.start); -} - -template -T *appendList(list *list, T element) { - if (list->head < list->length) { - list->data[list->head] = element; - list->head++; - return &(list->data[list->head - 1]); - } else { - return 0; - } -} - -template -void zeroListFull(list *list) { - memset(list->data, 0, list->head * sizeof(T)); -} - -template -void zeroList(list *list) { - list->head = 0; - memset(list->data, 0, list->head * sizeof(T)); -} - -inline string operator""_s(const char *cstrLiteral, size_t length) { - return { - (char *)cstrLiteral, - length, - }; -} - -const char *cstring(Arena *arena, list buf) { - char *arr = PushArray(arena, char, buf.length + 1); - memmove(arr, buf.data, buf.length); - arr[buf.length] = '\0'; - return arr; -} - -const char *cstring(Arena *arena, string str) { - char *arr = PushArray(arena, char, str.length + 1); - memmove(arr, str.str, str.length); - arr[str.length] = '\0'; - return arr; -} - -bool strStartsWith(string str, string testStr) { - if (str.length < testStr.length) { - return false; - } - for (size_t i = 0; i < testStr.length; i++) { - if (str.str[i] != testStr.str[i]) { - return false; - } - } - return true; -} - -bool strEql(string s1, string s2) { - if (s1.length != s2.length) { - return false; - } - for (size_t i = 0; i < s1.length; i++) { - if (s1.str[i] != s2.str[i]) { - return false; - } - } - return true; -} - -size_t calcStringLen(const char *str) { - size_t size = 0; - if (str == NULL) { - return size; - } - while (str[size] != '\0') { - size++; - } - return size; -} - -string strFromCString(Arena *arena, const char *str) { - string result = PushString(arena, calcStringLen(str)); - memcpy(result.str, str, result.length); - return result; -} - -string strReverse(Arena *arena, string str) { - string reversed = PushString(arena, str.length); - for ( - size_t mainIndex = str.length - 1, reversedIndex = 0; - mainIndex < str.length; - mainIndex--, reversedIndex++ - ) { - reversed.str[reversedIndex] = str.str[mainIndex]; - } - return reversed; -} - -string strPrintfv(Arena *arena, const char *fmt, va_list args) { - string result = {0}; - va_list argsCopy; - va_copy(argsCopy, args); - uint64 bufSize = stb_vsnprintf(0, 0, fmt, args) + 1; - result.str = PushArray(arena, char, bufSize); - result.length = bufSize - 1; - stb_vsnprintf((char *)result.str, (int)bufSize, fmt, argsCopy); - return result; -} - -string strPrintf(Arena *arena, const char *fmt, ...) { - string result = {0}; - va_list args; - va_start(args, fmt); - result = strPrintfv(arena, fmt, args); - va_end(args); - return result; -} - -template -list listSlice(list l, size_t start, size_t stop) { - if (stop == 0) { - stop = l.head; - } - // TODO(djledda): maybe assert instead - if (stop > l.head || start > stop) { - return {0}; - } - return { - l.data + start, - stop - start, - stop - start, - }; -} - -string strSlice(string str, size_t start, size_t stop) { - if (stop == 0) { - stop = str.length; - } - // TODO(djledda): maybe assert instead - if (stop > str.length || start > stop) { - return {0}; - } - return { - str.str + start, - stop - start, - }; -} - -string strSlice(char *data, size_t start, size_t stop) { - return { - data + start, - stop - start, - }; -} - -bool stringContains(string str, char c) { - for (size_t i = 0; i < str.length; i++) { - if (str.str[i] == c) { - return true; - } - } - return false; -} - -string NUMERIC_CHARS = "0123456789"_s; -inline bool isNumeric(char c) { - return stringContains(NUMERIC_CHARS, c); -} - -list strSplit(Arena *arena, string splitStr, string inputStr) { - list result = {0}; - if (inputStr.length > 0) { - size_t splitCount = 0; - size_t c = 0; - size_t start = 0; - void *beginning = (char *)arena->memory + arena->head; - while (c < inputStr.length - splitStr.length) { - if (strEql(strSlice(inputStr, c, c + splitStr.length), splitStr)) { - string *splitString = PushStruct(arena, string); - splitString->str = inputStr.str + start; - splitString->length = c - start; - splitCount++; - start = c + 1; - } - c++; - } - - string *splitString = PushStruct(arena, string); - splitString->str = inputStr.str + start; - splitString->length = inputStr.length - start; - splitCount++; - result.data = (string *)beginning, - result.head = splitCount, - result.length = splitCount; - } - return result; -} - -ParsePositiveIntResult parsePositiveInt(string str, size_t *lengthPointer) { - size_t numEnd = 0; - char currChar = str.str[numEnd]; - while (numEnd < str.length && isNumeric(currChar)) { - currChar = str.str[++numEnd]; - *lengthPointer += 1; - } - *lengthPointer -= 1; - if (numEnd > 0) { - uint8 result = 0; - for (size_t i = 0; i < numEnd; i++) { - result *= 10; - result += str.str[i] - '0'; - } - return {result, true}; - } else { - return {0, false}; - } -} - -ParsePositiveReal32Result parsePositiveReal32(string str, size_t *lengthPointer) { - ParsePositiveReal32Result result = {NAN, false}; - - string wholePartStr = string{0}; - string fractionalPartStr = string{0}; - - bool split = false; - size_t c = 0; - while (c < str.length) { - if (str.str[c] == '.') { - wholePartStr.str = str.str; - wholePartStr.length = c; - fractionalPartStr.str = str.str + c + 1; - fractionalPartStr.length = str.length - c - 1; - split = true; - break; - } - c++; - } - if (split) { - ParsePositiveIntResult wholePartParsed = parsePositiveInt(wholePartStr, lengthPointer); - *lengthPointer += 1; - ParsePositiveIntResult fractionalPartParsed = parsePositiveInt(fractionalPartStr, lengthPointer); - if (wholePartParsed.valid && fractionalPartParsed.valid) { - // TODO(dledda): implement powf with intrinsics? or just custom - real32 fractionalPartMultiplier = 1.0f / powf(10.0f, (real32)fractionalPartStr.length); - result.result = (real32)wholePartParsed.result + (real32)fractionalPartParsed.result * (real32)fractionalPartMultiplier; - result.valid = true; - } - } else if (c > 0) { - ParsePositiveIntResult intPartParsed = parsePositiveInt(str, lengthPointer); - if (intPartParsed.valid) { - result.result = (real32)intPartParsed.result; - result.valid = true; - } - } - return result; -} - -list getArgs(Arena *arena, int argc, char **argv) { - list args = PushList(arena, string, (size_t)argc - 1); - for (int i = 1; i < argc; i++) { - appendList(&args, strFromCString(arena, argv[i])); - } - return args; -} - -UnixTimestamp getSystemUnixTime() { - time_t now; - time(&now); - return (UnixTimestamp)now; -} - -Timestamp timestampFromUnixTime(UnixTimestamp *unixTimestamp) { - tm timestamp = {0}; - gmtime_r((time_t *)unixTimestamp, ×tamp); - return timestamp; -} - -string formatTimeHms(Arena *arena, UnixTimestamp time) { - local_persist const string format = "HH-MM-SS"_s; - string buf = PushString(arena, format.length); - tm *timestamp = gmtime((time_t *)&time); - strftime(buf.str, buf.length + 1, "%T", timestamp); - return buf; -} - -string formatTimeHms(Arena *arena, Timestamp *time) { - local_persist const string format = "HH-MM-SS"_s; - string buf = PushString(arena, format.length); - strftime(buf.str, buf.length + 1, "%T", (tm *)time); - return buf; -} - -string formatTimeYmd(Arena *arena, UnixTimestamp time) { - local_persist const string format = "YYYY-mm-dd"_s; - string buf = PushString(arena, format.length); - tm *timestamp = gmtime((time_t *)&time); - strftime(buf.str, buf.length + 1, "%Y-%m-%d", timestamp); - return buf; -} - -string formatTimeYmd(Arena *arena, Timestamp *time) { - local_persist const string format = "YYYY-mm-dd"_s; - string buf = PushString(arena, format.length); - strftime(buf.str, buf.length + 1, "%Y-%m-%d", (tm *)time); - return buf; -} - -void logErr(const char *fmt, ...) { - va_list argList; - va_start(argList, fmt); - os_log(LogTarget_stdout, fmt, argList); - va_end(argList); -} - -function void logStdout(const char *fmt, ...) { - va_list argList; - va_start(argList, fmt); - os_log(LogTarget_stdout, fmt, argList); - va_end(argList); -} - -void log(const char *fmt, ...) { - va_list argList; - va_start(argList, fmt); - os_log(LogTarget_stdout, fmt, argList); - va_end(argList); -} - -void log(list l, LogTarget target) { - void (*logFn)(const char *fmt, ...) = target == LogTarget_stdout ? &logStdout : &logErr; - logFn("{ "); - for (size_t i = 0; i < l.length; i++) { - if (i != 0) { - logFn(", "); - } - logFn("%i", l.data[i]); - } - logFn(" } length: %zu, head: %zu\n", l.length, l.head); -} - -void log(list l, LogTarget target) { - void (*logFn)(const char *fmt, ...) = target == LogTarget_stdout ? &logStdout : &logErr; - logFn("{ "); - for (size_t i = 0; i < l.length; i++) { - if (i != 0) { - logFn(", "); - } - logFn("\"%S\"", l.data[i]); - } - logFn(" } length: %zu, head: %zu\n", l.length, l.head); -} - -int intCompare(const void *a, const void *b) { - int *x = (int *)a; - int *y = (int *)b; - return (*x > *y) - (*x < *y); -} - diff --git a/djstdlib/core.h b/djstdlib/core.h deleted file mode 100644 index 257cb65..0000000 --- a/djstdlib/core.h +++ /dev/null @@ -1,270 +0,0 @@ -#ifndef CORE_H -#define CORE_H - -// cstdlib includes -#include -#include // necessary for int type sizes -#include -#include // TODO(djledda): try not to depend on this one - -// ### Misc macros ### -#if ENABLE_ASSERT -#define Assert(expression) if (!(expression)) {*(volatile int *)0 = 0;} -#else -#define Assert(expression) -#endif - -#define function static -#define global static -#define local_persist static - -// ### Types ### -typedef int8_t int8; -typedef int16_t int16; -typedef int32_t int32; -typedef int64_t int64; -typedef uint8_t uint8; -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint64_t uint64; -typedef uint8_t byte; -typedef float real32; -typedef double real64; - -// ### Sizes and Numbers ### -#define Bytes(n) (n) -#define Kilobytes(n) (n << 10) -#define Megabytes(n) (n << 20) -#define Gigabytes(n) (((uint64)n) << 30) -#define Terabytes(n) (((uint64)n) << 40) - -#define Thousand(n) ((n)*1000) -#define Million(n) ((n)*1000000) -#define Billion(n) ((n)*1000000000LL) - -#define ArrayCount(arr) (sizeof(arr) / sizeof((arr)[0])) - -// ### Arenas ### -struct Arena { - void *memory; - size_t capacity; - size_t head; -}; - -struct Scratch { - Arena *arena; - size_t start; -}; - -void *pushSize(Arena *arena, size_t bytes); -void *pushSizeFill(Arena *arena, size_t bytes, byte fill); -Arena *arenaAlloc(size_t capacity); -void arenaFree(Arena *arena); -void arenaFreeFrom(Arena *arena, size_t pos); -void arenaPopTo(Arena *arena, void *pos); - -void initialiseCore(); - -Scratch scratchStart(Arena **conflicts, size_t conflictCount); -void scratchEnd(Scratch scratch); - -#define PushArray(arena, type, size) (type *)pushSize(arena, sizeof(type) * (size)) -#define PushArrayZero(arena, type, size) (type *)pushSizeFill(arena, sizeof(type) * (size), 0) -#define PushStruct(arena, type) (type *)pushSize(arena, sizeof(type)) -#define PushStructZero(arena, type) (type *)pushSizeFill(arena, sizeof(type), 0) - -// ### Vectors ### -template -union Vector2 { - struct { - T x; - T y; - }; - T vec[2]; -}; -template -inline function Vector2 vec2(T x, T y) { - Vector2 result = {0}; - result.x = x; - result.y = y; - return result; -} - -template -union Vector3 { - struct { - T x; - T y; - T z; - }; - T vec[3]; -}; -template -inline function Vector3 vec3(T x, T y, T z) { - Vector3 result = {0}; - result.x = x; - result.y = y; - result.z = z; - return result; -} - -template -union Vector4 { - struct { - T x; - T y; - T z; - T w; - }; - T vec[4]; -}; -template -inline function Vector4 vec4(T x, T y, T z, T w) { - Vector4 result = {0}; - result.x = x; - result.y = y; - result.z = z; - result.w = w; - return result; -} - -// ### Lists ### -template -struct list { - T* data; - size_t length; - size_t head; -}; - -#define PushList(arena, type, size) (list{ PushArray(arena, type, size), size, 0 }) -#define PushListZero(arena, type, size) (list{ PushArrayZero(arena, type, size), size, 0 }) -#define PushFullList(arena, type, size) (list{ PushArray(arena, type, size), size, size }) -#define PushFullListZero(arena, type, size) (list{ PushArrayZero(arena, type, size), size, size }) - -template T *appendList(list *list, T element); -template void zeroList(list *list); -template void zeroListFull(list *list); -template list listSlice(list l, size_t start, size_t stop = 0); - -// ### Strings ### -struct string { - char *str; - size_t length; -}; -#define STB_SPRINTF_DECORATE(name) stb_##name // define this before including if you want to change the names -#include "vendor/stb_sprintf.h" - -#define strlit(lit) (string{(char *)(lit), sizeof(lit) - 1}) -#define PushString(arena, length) (string{ (char *)pushSize(arena, length), (length) }) -#define PushStringFill(arena, length, characterByte) (string{ (char *)pushSizeFill(arena, length, characterByte), (length) }) -string operator""_s(const char *cstrLiteral, size_t length); - -// C Strings -const char *cstring(Arena *arena, list buf); -const char *cstring(Arena *arena, string str); -size_t calcStringLen(const char *str); -string strFromCString(Arena *arena, const char *str); - -bool strEql(string s1, string s2); -bool strStartsWith(string str, string testStr); -bool stringContains(string str, char c); - -string strReverse(Arena *arena, string str); -string strSlice(string str, size_t start, size_t stop = 0); -string strSlice(char *data, size_t start, size_t stop = 0); -list strSplit(Arena *arena, string splitStr, string inputStr); -string strPrintfv(Arena *arena, const char *fmt, va_list args); -string strPrintf(Arena *arena, const char *fmt, ...); - -struct ParsePositiveIntResult { uint8 result; bool valid; }; -ParsePositiveIntResult parsePositiveInt(string str, size_t *lengthPointer); -struct ParsePositiveReal32Result { real32 result; bool valid; }; -ParsePositiveReal32Result parsePositiveReal32(Arena *arena, string str, size_t *lengthPointer); - -inline function bool isNumeric(char c); - -// ### Cmdline ### -list getArgs(Arena *arena, int argc, char **argv); - -// ### Time ### -typedef uint64 UnixTimestamp; -typedef tm Timestamp; - -UnixTimestamp getSystemUnixTime(); -Timestamp timestampFromUnixTime(UnixTimestamp *unixTimestamp); -string formatTimeHms(Arena *arena, UnixTimestamp time); -string formatTimeHms(Arena *arena, Timestamp *time); -string formatTimeYmd(Arena *arena, UnixTimestamp time); -string formatTimeYmd(Arena *arena, Timestamp *time); - -// ### Linked Lists ### -// TODO(djledda): implement basic linked lists (based on arenas?) - -// ### Logging ### -enum LogTarget { - LogTarget_stdout, - LogTarget_stdin, - LogTarget_stderr, - LogTarget_count, -}; - -#define ANSI_INSTRUCTION_FROM_ENUM(ansiCodeEnum) ANSI_INSTRUCTION(ansiCodeEnum) -#define ANSI_INSTRUCTION(ansiCode) "\u001b[" #ansiCode "m" -#define ANSI_INSTRUCTION_STR(ansiCodeStr) "\u001b[" ansiCodeStr "m" -#define ANSI_RESET ANSI_INSTRUCTION(0) - -#define ANSI_fg_black 30 -#define ANSI_fg_red 31 -#define ANSI_fg_green 32 -#define ANSI_fg_yellow 33 -#define ANSI_fg_blue 34 -#define ANSI_fg_magenta 35 -#define ANSI_fg_cyan 36 -#define ANSI_fg_white 37 - -#define ANSI_fg_bblack 90 -#define ANSI_fg_bred 91 -#define ANSI_fg_bgreen 92 -#define ANSI_fg_byellow 93 -#define ANSI_fg_bblue 94 -#define ANSI_fg_bmagenta 95 -#define ANSI_fg_bcyan 96 -#define ANSI_fg_bwhite 97 - -#define ANSI_bg_black 40 -#define ANSI_bg_red 41 -#define ANSI_bg_green 42 -#define ANSI_bg_yellow 43 -#define ANSI_bg_blue 44 -#define ANSI_bg_magenta 45 -#define ANSI_bg_cyan 46 -#define ANSI_bg_white 47 - -#define ANSI_bg_bblack 100 -#define ANSI_bg_bred 101 -#define ANSI_bg_bgreen 102 -#define ANSI_bg_byellow 103 -#define ANSI_bg_bblue 104 -#define ANSI_bg_bmagenta 105 -#define ANSI_bg_bcyan 106 -#define ANSI_bg_bwhite 107 - -#define COLOR_TEXT(text, foregroundcolor) ANSI_INSTRUCTION_FROM_ENUM(foregroundcolor) text ANSI_RESET -#define COLOR_TEXT_BG(text, backgroundcolor) ANSI_INSTRUCTION_FROM_ENUM(backgroundcolor) text ANSI_RESET -#define COLOR_TEXT_FG_BG(text, foregroundcolor, backgroundcolor) ANSI_INSTRUCTION_FROM_ENUM(foregroundcolor) ANSI_INSTRUCTION_FROM_ENUM(backgroundcolor) text ANSI_RESET -#define COLOR_TEXT_RGB(text, red, green, blue) ANSI_INSTRUCTION_STR("38;2;" #red ";" #green ";" #blue) text ANSI_RESET - -void log(list l, LogTarget target = LogTarget_stdout); -void log(list l, LogTarget target = LogTarget_stdout); -void log(const char *fmt, ...); -void logError(const char *fmt, ...); - -// ### Loops ### -#define EachIn(list, it) size_t it = 0; it < (list).head; it++ -#define EachInReversed(list, it) size_t it = (list).head - 1; it >= 0 && it < (list).head; it-- -#define EachInArray(arr, it) size_t it = 0; it < ArrayCount(arr); ++it - -// ### Misc ### -int intCompare(const void *a, const void *b); - -#endif diff --git a/djstdlib/os.cpp b/djstdlib/os.cpp deleted file mode 100644 index 64a2575..0000000 --- a/djstdlib/os.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef OS_CPP -#define OS_CPP - -#if OS_WINDOWS -#include "os_win32.cpp" -#elif OS_LINUX -#include "os_linux.cpp" -#else - #error Development environment not supported. -#endif - -#endif diff --git a/djstdlib/os.h b/djstdlib/os.h deleted file mode 100644 index 07b654e..0000000 --- a/djstdlib/os.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef OS_H -#define OS_H - -#include "core.h" - -// ### Memory ### -void *os_alloc(size_t capacity); -void os_reserve(void *ptr); -void os_decommit(void *ptr); -void os_free(void *ptr, size_t freeSize); - -// ### File IO ### -string os_readEntireFile(Arena *arena, string filename); -bool os_writeEntireFile(Arena *arena, string filename, const byte *contents, size_t contentsLength); -bool os_fileAppend(Arena *arena, string filename, const byte *contents, size_t contentsLength); - -// ### Standard IO ### -void os_log(LogTarget target, const char *fmt, va_list argList); - -#endif diff --git a/djstdlib/os_linux.cpp b/djstdlib/os_linux.cpp deleted file mode 100644 index 69817d7..0000000 --- a/djstdlib/os_linux.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef OS_IMPL_LINUX_CPP -#define OS_IMPL_LINUX_CPP - -#include "os.h" - -#include -#include -#include - -void *os_alloc(size_t capacity) { - return mmap(0, capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -} - -void os_commit(void *ptr) { -} - -void os_decommit(void *ptr) { -} - -void os_free(void *ptr, size_t size) { - int err = munmap(ptr, size); - Assert(err != -1); -} - -string os_readEntireFile(Arena *arena, string filename) { - Scratch temp = scratchStart(&arena, 1); - - FILE *input = fopen(cstring(temp.arena, filename), "r"); - string readBuffer; - if (input) { - struct stat st; - stat((char *)filename.str, &st); - size_t fsize = st.st_size; - readBuffer = PushString(arena, fsize); - fread(readBuffer.str, sizeof(byte), readBuffer.length, input); - fclose(input); - } else { - readBuffer = PushString(arena, 0); - } - - scratchEnd(temp); - return readBuffer; -} - -bool os_writeEntireFile(Arena *arena, string filename, const byte *contents, size_t contentsLength) { - Scratch temp = scratchStart(&arena, 1); - - bool result = false; - FILE *output = fopen(cstring(temp.arena, filename), "w"); - if (output) { - fwrite(contents, sizeof(byte), contentsLength, output); - fclose(output); - result = true; - } - - scratchEnd(temp); - return result; -} - -bool os_fileAppend(Arena *arena, string filename, const byte *contents, size_t contentsLength) { - Scratch temp = scratchStart(&arena, 1); - - bool result = false; - FILE *output = fopen(cstring(temp.arena, filename), "a"); - if (output) { - fwrite(contents, sizeof(byte), contentsLength, output); - fclose(output); - result = true; - } - - scratchEnd(temp); - return result; -} - -void os_log(LogTarget target, const char *fmt, va_list argList) { - Scratch temp = scratchStart(0, 0); - - string result = strPrintfv(temp.arena, fmt, argList); - // TODO(djledda): finish implementation without cstdlib - switch (target) { - case LogTarget_stdin: - write(0, (const void *)result.str, result.length); - break; - case LogTarget_stderr: - fflush(stderr); - write(2, (const void *)result.str, result.length); - break; - case LogTarget_stdout: - default: - fflush(stdout); - write(1, (const void *)result.str, result.length); - break; - } - - scratchEnd(temp); -} - -#endif diff --git a/djstdlib/os_win32.cpp b/djstdlib/os_win32.cpp deleted file mode 100644 index 70ba555..0000000 --- a/djstdlib/os_win32.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef OS_IMPL_WIN32_CPP -#define OS_IMPL_WIN32_CPP - -#include "Windows.h" -#include "os.h" - -void *os_alloc(size_t commitSize) { - return VirtualAlloc(NULL, commitSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); -} - -void os_reserve(void *ptr) { -} - -void os_decommit(void *ptr) { -} - -void os_free(void *ptr, size_t size) { - VirtualFree(ptr, NULL, MEM_RELEASE); -} - -string os_readEntireFile(Arena *arena, string filename) { - string result = {0}; - HANDLE fileHandle = CreateFileA(cstring(arena, filename), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); - if (fileHandle != INVALID_HANDLE_VALUE) { - LARGE_INTEGER fileSize; - if (GetFileSizeEx(fileHandle, &fileSize)) { - string readfile = PushString(arena, (size_t)fileSize.QuadPart); - if (readfile.str) { - DWORD bytesRead; - if (ReadFile(fileHandle, readfile.str, (DWORD)fileSize.QuadPart, &bytesRead, NULL) && (fileSize.QuadPart == bytesRead)) { - result = readfile; - } - } - } - CloseHandle(fileHandle); - } - return result; -} - -bool os_writeEntireFile(Arena *arena, string filename, const byte *contents, size_t contentsLength) { - bool result = false; - HANDLE fileHandle = CreateFileA(cstring(arena, filename), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL); - if (fileHandle != INVALID_HANDLE_VALUE) { - DWORD bytesWritten; - if (WriteFile(fileHandle, contents, (DWORD)contentsLength, &bytesWritten, NULL)) { - // file written successfully - result = bytesWritten == contentsLength; - } - CloseHandle(fileHandle); - } - return result; -} - -bool os_fileAppend(Arena *arena, string filename, const byte *contents, size_t contentsLength) { - bool result = false; - HANDLE fileHandle = CreateFileA(cstring(arena, filename), FILE_APPEND_DATA | FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (fileHandle != INVALID_HANDLE_VALUE) { - DWORD bytesWritten; - DWORD position = SetFilePointer(fileHandle, 0, NULL, FILE_END); - if (WriteFile(fileHandle, contents, (DWORD)contentsLength, &bytesWritten, NULL)) { - // file written successfully - result = bytesWritten == contentsLength; - } - CloseHandle(fileHandle); - } - return result; -} - -function void os_log(LogTarget target, const char *fmt, va_list argList) { - Scratch scratch = scratchStart(0, 0); - string result = strPrintfv(scratch.arena, fmt, argList); - DWORD done; - HANDLE stdHandle; - switch (target) { - case LogTarget_stdin: - stdHandle = GetStdHandle(STD_INPUT_HANDLE); - break; - case LogTarget_stdout: - stdHandle = GetStdHandle(STD_ERROR_HANDLE); - break; - case LogTarget_stderr: - stdHandle = GetStdHandle(STD_OUTPUT_HANDLE); - break; - default: - stdHandle = GetStdHandle(STD_OUTPUT_HANDLE); - break; - } - WriteFile(stdHandle, result.str, (DWORD)result.length, &done, 0); - scratchEnd(scratch); -} - -#endif diff --git a/djstdlib/vendor/stb_sprintf.h b/djstdlib/vendor/stb_sprintf.h deleted file mode 100644 index 6c2fd25..0000000 --- a/djstdlib/vendor/stb_sprintf.h +++ /dev/null @@ -1,1923 +0,0 @@ -// NOTE(djledda): This library has been modified to support my string struct, inspired by the Digital Grove codebase by Ryan Fleury. - -// stb_sprintf - v1.10 - public domain snprintf() implementation -// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 -// http://github.com/nothings/stb -// -// allowed types: sc uidBboXx p AaGgEef n -// lengths : hh h ll j z t I64 I32 I -// -// Contributors: -// Fabian "ryg" Giesen (reformatting) -// github:aganm (attribute format) -// -// Contributors (bugfixes): -// github:d26435 -// github:trex78 -// github:account-login -// Jari Komppa (SI suffixes) -// Rohit Nirmal -// Marcin Wojdyr -// Leonard Ritter -// Stefano Zanotti -// Adam Allison -// Arvid Gerstmann -// Markus Kolb -// -// LICENSE: -// -// See end of file for license information. - -#ifndef STB_SPRINTF_H_INCLUDE -#define STB_SPRINTF_H_INCLUDE - -/* -Single file sprintf replacement. - -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. -Hereby placed in public domain. - -This is a full sprintf replacement that supports everything that -the C runtime sprintfs support, including float/double, 64-bit integers, -hex floats, field parameters (%*.*d stuff), length reads backs, etc. - -Why would you need this if sprintf already exists? Well, first off, -it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements -that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use -the same format strings in cross platform code. - -It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get -the header file function definitions. To get the code, you include -it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. - -It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does -drag in CRT code on most platforms. - -It compiles to roughly 8K with float support, and 4K without. -As a comparison, when using MSVC static libs, calling sprintf drags -in 16K. - -API: -==== -int stbsp_sprintf( char * buf, char const * fmt, ... ) -int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) - Convert an arg list into a buffer. stbsp_snprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) -int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) - Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns - a zero-terminated string (unlike regular snprintf). - -int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) - typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); - Convert into a buffer, calling back every STB_SPRINTF_MIN chars. - Your callback can then copy the chars out, print them or whatever. - This function is actually the workhorse for everything else. - The buffer you pass in must hold at least STB_SPRINTF_MIN characters. - // you return the next buffer to use or 0 to stop converting - -void stbsp_set_separators( char comma, char period ) - Set the comma and period characters to use. - -FLOATS/DOUBLES: -=============== -This code uses a internal float->ascii conversion method that uses -doubles with error correction (double-doubles, for ~105 bits of -precision). This conversion is round-trip perfect - that is, an atof -of the values output here will give you the bit-exact double back. - -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 -doesn't either). - -If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT -and you'll save 4K of code space. - -64-BIT INTS: -============ -This library also supports 64-bit integers and you can use MSVC style or -GCC style indicators (%I64d or %lld). It supports the C99 specifiers -for size_t and ptr_diff_t (%jd %zd) as well. - -EXTRAS: -======= -Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 -would print 12,345. - -For integers and floats, you can use a "$" specifier and the number -will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn -2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three -$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the -suffix, add "_" specifier: "%_$d" -> "2.53M". - -In addition to octal and hexadecimal conversions, you can print -integers in binary: "%b" for 256 would print 100. - -PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): -=================================================================== -"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) -"%24d" across all 32-bit ints (4.5x/4.2x faster) -"%x" across all 32-bit ints (4.5x/3.8x faster) -"%08x" across all 32-bit ints (4.3x/3.8x faster) -"%f" across e-10 to e+10 floats (7.3x/6.0x faster) -"%e" across e-10 to e+10 floats (8.1x/6.0x faster) -"%g" across e-10 to e+10 floats (10.0x/7.1x faster) -"%f" for values near e-300 (7.9x/6.5x faster) -"%f" for values near e+300 (10.0x/9.1x faster) -"%e" for values near e-300 (10.1x/7.0x faster) -"%e" for values near e+300 (9.2x/6.0x faster) -"%.320f" for values near e-300 (12.6x/11.2x faster) -"%a" for random values (8.6x/4.3x faster) -"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) -"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) -"%s%s%s" for 64 char strings (7.1x/7.3x faster) -"...512 char string..." ( 35.0x/32.5x faster!) -*/ - -#if defined(__clang__) - #if defined(__has_feature) && defined(__has_attribute) - #if __has_feature(address_sanitizer) - #if __has_attribute(__no_sanitize__) - #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) - #elif __has_attribute(__no_sanitize_address__) - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #elif __has_attribute(__no_address_safety_analysis__) - #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) - #endif - #endif - #endif -#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #endif -#endif - -#ifndef STBSP__ASAN -#define STBSP__ASAN -#endif - -#ifdef STB_SPRINTF_STATIC -#define STBSP__PUBLICDEC static -#define STBSP__PUBLICDEF static STBSP__ASAN -#else -#ifdef __cplusplus -#define STBSP__PUBLICDEC extern "C" -#define STBSP__PUBLICDEF extern "C" STBSP__ASAN -#else -#define STBSP__PUBLICDEC extern -#define STBSP__PUBLICDEF STBSP__ASAN -#endif -#endif - -#if defined(__has_attribute) - #if __has_attribute(format) - #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) - #endif -#endif - -#ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) -#endif - -#ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) -#else -#define STBSP__NOTUSED(v) (void)sizeof(v) -#endif - -#include // for va_arg(), va_list() -#include // size_t, ptrdiff_t - -#ifndef STB_SPRINTF_MIN -#define STB_SPRINTF_MIN 512 // how many characters per callback -#endif -typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); - -#ifndef STB_SPRINTF_DECORATE -#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names -#endif - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); - -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); - -#endif // STB_SPRINTF_H_INCLUDE - -#ifdef STB_SPRINTF_IMPLEMENTATION - -#define stbsp__uint32 unsigned int -#define stbsp__int32 signed int - -#ifdef _MSC_VER -#define stbsp__uint64 unsigned __int64 -#define stbsp__int64 signed __int64 -#else -#define stbsp__uint64 unsigned long long -#define stbsp__int64 signed long long -#endif -#define stbsp__uint16 unsigned short - -#ifndef stbsp__uintptr -#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) -#define stbsp__uintptr stbsp__uint64 -#else -#define stbsp__uintptr stbsp__uint32 -#endif -#endif - -#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define STB_SPRINTF_MSVC_MODE -#endif -#endif - -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses -#define STBSP__UNALIGNED(code) -#else -#define STBSP__UNALIGNED(code) code -#endif - -#ifndef STB_SPRINTF_NOFLOAT -// internal float utility functions -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); -#define STBSP__SPECIAL 0x7000 -#endif - -static char stbsp__period = '.'; -static char stbsp__comma = ','; -static struct -{ - short temp; // force next field to be 2-byte aligned - char pair[201]; -} stbsp__digitpair = -{ - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899" -}; - -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) -{ - stbsp__period = pperiod; - stbsp__comma = pcomma; -} - -#define STBSP__LEFTJUST 1 -#define STBSP__LEADINGPLUS 2 -#define STBSP__LEADINGSPACE 4 -#define STBSP__LEADING_0X 8 -#define STBSP__LEADINGZERO 16 -#define STBSP__INTMAX 32 -#define STBSP__TRIPLET_COMMA 64 -#define STBSP__NEGATIVE 128 -#define STBSP__METRIC_SUFFIX 256 -#define STBSP__HALFWIDTH 512 -#define STBSP__METRIC_NOSPACE 1024 -#define STBSP__METRIC_1024 2048 -#define STBSP__METRIC_JEDEC 4096 - -static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) -{ - sign[0] = 0; - if (fl & STBSP__NEGATIVE) { - sign[0] = 1; - sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { - sign[0] = 1; - sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { - sign[0] = 1; - sign[1] = '+'; - } -} - -static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) -{ - char const * sn = s; - - // get up to 4-byte alignment - for (;;) { - if (((stbsp__uintptr)sn & 3) == 0) - break; - - if (!limit || *sn == 0) - return (stbsp__uint32)(sn - s); - - ++sn; - --limit; - } - - // scan over 4 bytes at a time to find terminating 0 - // this will intentionally scan up to 3 bytes past the end of buffers, - // but becase it works 4B aligned, it will never cross page boundaries - // (hence the STBSP__ASAN markup; the over-read here is intentional - // and harmless) - while (limit >= 4) { - stbsp__uint32 v = *(stbsp__uint32 *)sn; - // bit hack to find if there's a 0 byte in there - if ((v - 0x01010101) & (~v) & 0x80808080UL) - break; - - sn += 4; - limit -= 4; - } - - // handle the last few characters to find actual size - while (limit && *sn) { - ++sn; - --limit; - } - - return (stbsp__uint32)(sn - s); -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) -{ - static char hex[] = "0123456789abcdefxp"; - static char hexu[] = "0123456789ABCDEFXP"; - char *bf; - char const *f; - int tlen = 0; - - bf = buf; - f = fmt; - for (;;) { - stbsp__int32 fw, pr, tz; - stbsp__uint32 fl; - - // macros for the callback buffer stuff - #define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } - #define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } - #define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer - #define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } - - // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { - schk1: - if (f[0] == '%') - goto scandd; - schk2: - if (f[0] == 0) - goto endfmt; - stbsp__chk_cb_buf(1); - *bf++ = f[0]; - ++f; - } - for (;;) { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v, c; - v = *(stbsp__uint32 *)f; - c = (~v) & 0x80808080; - if (((v ^ 0x25252525) - 0x01010101) & c) - goto schk1; - if ((v - 0x01010101) & c) - goto schk2; - if (callback) - if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) - goto schk1; - #ifdef STB_SPRINTF_NOUNALIGNED - if(((stbsp__uintptr)bf) & 3) { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } else - #endif - { - *(stbsp__uint32 *)bf = v; - } - bf += 4; - f += 4; - } - } - scandd: - - ++f; - - // ok, we have a percent, read the modifiers first - fw = 0; - pr = -1; - fl = 0; - tz = 0; - - // flags - for (;;) { - switch (f[0]) { - // if we have left justify - case '-': - fl |= STBSP__LEFTJUST; - ++f; - continue; - // if we have leading plus - case '+': - fl |= STBSP__LEADINGPLUS; - ++f; - continue; - // if we have leading space - case ' ': - fl |= STBSP__LEADINGSPACE; - ++f; - continue; - // if we have leading 0x - case '#': - fl |= STBSP__LEADING_0X; - ++f; - continue; - // if we have thousand commas - case '\'': - fl |= STBSP__TRIPLET_COMMA; - ++f; - continue; - // if we have kilo marker (none->kilo->kibi->jedec) - case '$': - if (fl & STBSP__METRIC_SUFFIX) { - if (fl & STBSP__METRIC_1024) { - fl |= STBSP__METRIC_JEDEC; - } else { - fl |= STBSP__METRIC_1024; - } - } else { - fl |= STBSP__METRIC_SUFFIX; - } - ++f; - continue; - // if we don't want space between metric suffix and number - case '_': - fl |= STBSP__METRIC_NOSPACE; - ++f; - continue; - // if we have leading zero - case '0': - fl |= STBSP__LEADINGZERO; - ++f; - goto flags_done; - default: goto flags_done; - } - } - flags_done: - - // get the field width - if (f[0] == '*') { - fw = va_arg(va, stbsp__uint32); - ++f; - } else { - while ((f[0] >= '0') && (f[0] <= '9')) { - fw = fw * 10 + f[0] - '0'; - f++; - } - } - // get the precision - if (f[0] == '.') { - ++f; - if (f[0] == '*') { - pr = va_arg(va, stbsp__uint32); - ++f; - } else { - pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) { - pr = pr * 10 + f[0] - '0'; - f++; - } - } - } - - // handle integer size overrides - switch (f[0]) { - // are we halfwidth? - case 'h': - fl |= STBSP__HALFWIDTH; - ++f; - if (f[0] == 'h') - ++f; // QUARTERWIDTH - break; - // are we 64-bit (unix style) - case 'l': - fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); - ++f; - if (f[0] == 'l') { - fl |= STBSP__INTMAX; - ++f; - } - break; - // are we 64-bit on intmax? (c99) - case 'j': - fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - case 't': - fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; - ++f; - break; - // are we 64-bit (msft style) - case 'I': - if ((f[1] == '6') && (f[2] == '4')) { - fl |= STBSP__INTMAX; - f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { - f += 3; - } else { - fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); - ++f; - } - break; - default: break; - } - - // handle each replacement - switch (f[0]) { - #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - stbsp__uint32 l, n, cs; - stbsp__uint64 n64; -#ifndef STB_SPRINTF_NOFLOAT - double fv; -#endif - stbsp__int32 dp; - char const *sn; - - case 's': - // get the string - s = va_arg(va, char *); - if (s == 0) - s = (char *)"null"; - // get the length, limited to desired precision - // always limit to ~0u chars since our counts are 32b - l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - // copy the string in - goto scopy; - - case 'S': - { - // string struct - string str = va_arg(va, string); - s = (char *)str.str; - sn = (const char *)(str.str + str.length); - l = (unsigned int)str.length; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - } break; - - case 'c': // char - // get the character - s = num + STBSP__NUMSZ - 1; - *s = (char)va_arg(va, int); - l = 1; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - - case 'n': // weird write-bytes specifier - { - int *d = va_arg(va, int *); - *d = tlen + (int)(bf - buf); - } break; - -#ifdef STB_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va, double); // eat it - s = (char *)"No float"; - l = 8; - lead[0] = 0; - tail[0] = 0; - pr = 0; - cs = 0; - STBSP__NOTUSED(dp); - goto scopy; -#else - case 'A': // hex float - case 'a': // hex float - h = (f[0] == 'A') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) - fl |= STBSP__NEGATIVE; - - s = num + 64; - - stbsp__lead_sign(fl, lead); - - if (dp == -1023) - dp = (n64) ? -1022 : 0; - else - n64 |= (((stbsp__uint64)1) << 52); - n64 <<= (64 - 56); - if (pr < 15) - n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); -// add leading chars - -#ifdef STB_SPRINTF_MSVC_MODE - *s++ = '0'; - *s++ = 'x'; -#else - lead[1 + lead[0]] = '0'; - lead[2 + lead[0]] = 'x'; - lead[0] += 2; -#endif - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - if (pr) - *s++ = stbsp__period; - sn = s; - - // print the bits - n = pr; - if (n > 13) - n = 13; - if (pr > (stbsp__int32)n) - tz = pr - n; - pr = 0; - while (n--) { - *s++ = h[(n64 >> 60) & 15]; - n64 <<= 4; - } - - // print the expo - tail[1] = h[17]; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; - n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - - dp = (int)(s - sn); - l = (int)(s - (num + 64)); - s = num + 64; - cs = 1 + (3 << 24); - goto scopy; - - case 'G': // float - case 'g': // float - h = (f[0] == 'G') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; - else if (pr == 0) - pr = 1; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) - fl |= STBSP__NEGATIVE; - - // clamp the precision and delete extra zeros after clamp - n = pr; - if (l > (stbsp__uint32)pr) - l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) { - --pr; - --l; - } - - // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { - if (pr > (stbsp__int32)l) - pr = l - 1; - else if (pr) - --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g semantics for %f - if (dp > 0) { - pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } else { - pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); - } - goto dofloatfromg; - - case 'E': // float - case 'e': // float - h = (f[0] == 'E') ? hexu : hex; - fv = va_arg(va, double); - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) - fl |= STBSP__NEGATIVE; - doexpfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - // handle leading chars - *s++ = sn[0]; - - if (pr) - *s++ = stbsp__period; - - // handle after decimal - if ((l - 1) > (stbsp__uint32)pr) - l = pr + 1; - for (n = 1; n < l; n++) - *s++ = sn[n]; - // trailing zeros - tz = pr - (l - 1); - pr = 0; - // dump expo - tail[1] = h[0xe]; - dp -= 1; - if (dp < 0) { - tail[2] = '-'; - dp = -dp; - } else - tail[2] = '+'; -#ifdef STB_SPRINTF_MSVC_MODE - n = 5; -#else - n = (dp >= 100) ? 5 : 4; -#endif - tail[0] = (char)n; - for (;;) { - tail[n] = '0' + dp % 10; - if (n <= 3) - break; - --n; - dp /= 10; - } - cs = 1 + (3 << 24); // how many tens - goto flt_lead; - - case 'f': // float - fv = va_arg(va, double); - doafloat: - // do kilos - if (fl & STBSP__METRIC_SUFFIX) { - double divisor; - divisor = 1000.0f; - if (fl & STBSP__METRIC_1024) - divisor = 1024.0; - while (fl < 0x4000000) { - if ((fv < divisor) && (fv > -divisor)) - break; - fv /= divisor; - fl += 0x1000000; - } - } - if (pr == -1) - pr = 6; // default is 6 - // read the double into a string - if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) - fl |= STBSP__NEGATIVE; - dofloatfromg: - tail[0] = 0; - stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { - s = (char *)sn; - cs = 0; - pr = 0; - goto scopy; - } - s = num + 64; - - // handle the three decimal varieties - if (dp <= 0) { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++ = '0'; - if (pr) - *s++ = stbsp__period; - n = -dp; - if ((stbsp__int32)n > pr) - n = pr; - i = n; - while (i) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - i -= 4; - } - while (i) { - *s++ = '0'; - --i; - } - if ((stbsp__int32)(l + n) > pr) - l = pr - n; - i = l; - while (i) { - *s++ = *sn++; - --i; - } - tz = pr - (n + l); - cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } else { - cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { - // handle xxxx000*000.0 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= l) - break; - } - } - if (n < (stbsp__uint32)dp) { - n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { - if ((((stbsp__uintptr)s) & 3) == 0) - break; - *s++ = '0'; - --n; - } - while (n >= 4) { - *(stbsp__uint32 *)s = 0x30303030; - s += 4; - n -= 4; - } - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = '0'; - --n; - } - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) { - *s++ = stbsp__period; - tz = pr; - } - } else { - // handle xxxxx.xxxx000*000 - n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { - cs = 0; - *s++ = stbsp__comma; - } else { - *s++ = sn[n]; - ++n; - if (n >= (stbsp__uint32)dp) - break; - } - } - cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) - *s++ = stbsp__period; - if ((l - dp) > (stbsp__uint32)pr) - l = pr + dp; - while (n < l) { - *s++ = sn[n]; - ++n; - } - tz = pr - (l - dp); - } - } - pr = 0; - - // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) { - char idx; - idx = 1; - if (fl & STBSP__METRIC_NOSPACE) - idx = 0; - tail[0] = idx; - tail[1] = ' '; - { - if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. - if (fl & STBSP__METRIC_1024) - tail[idx + 1] = "_KMGT"[fl >> 24]; - else - tail[idx + 1] = "_kMGT"[fl >> 24]; - idx++; - // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { - tail[idx + 1] = 'i'; - idx++; - } - tail[0] = idx; - } - } - }; - - flt_lead: - // get the length that we copied - l = (stbsp__uint32)(s - (num + 64)); - s = num + 64; - goto scopy; -#endif - - case 'B': // upper binary - case 'b': // lower binary - h = (f[0] == 'B') ? hexu : hex; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[0xb]; - } - l = (8 << 4) | (1 << 8); - goto radixnum; - - case 'o': // octal - h = hexu; - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 1; - lead[1] = '0'; - } - l = (3 << 4) | (3 << 8); - goto radixnum; - - case 'p': // pointer - fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; - pr = sizeof(void *) * 2; - fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // fall through - to X - - case 'X': // upper hex - case 'x': // lower hex - h = (f[0] == 'X') ? hexu : hex; - l = (4 << 4) | (4 << 8); - lead[0] = 0; - if (fl & STBSP__LEADING_0X) { - lead[0] = 2; - lead[1] = '0'; - lead[2] = h[16]; - } - radixnum: - // get the number - if (fl & STBSP__INTMAX) - n64 = va_arg(va, stbsp__uint64); - else - n64 = va_arg(va, stbsp__uint32); - - s = num + STBSP__NUMSZ; - dp = 0; - // clear tail, and clear leading if value is zero - tail[0] = 0; - if (n64 == 0) { - lead[0] = 0; - if (pr == 0) { - l = 0; - cs = 0; - goto scopy; - } - } - // convert to string - for (;;) { - *--s = h[n64 & ((1 << (l >> 8)) - 1)]; - n64 >>= (l >> 8); - if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) - break; - if (fl & STBSP__TRIPLET_COMMA) { - ++l; - if ((l & 15) == ((l >> 4) & 15)) { - l &= ~15; - *--s = stbsp__comma; - } - } - }; - // get the tens and the comma pos - cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - // copy it - goto scopy; - - case 'u': // unsigned - case 'i': - case 'd': // integer - // get the integer and abs it - if (fl & STBSP__INTMAX) { - stbsp__int64 i64 = va_arg(va, stbsp__int64); - n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { - n64 = (stbsp__uint64)-i64; - fl |= STBSP__NEGATIVE; - } - } else { - stbsp__int32 i = va_arg(va, stbsp__int32); - n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { - n64 = (stbsp__uint32)-i; - fl |= STBSP__NEGATIVE; - } - } - -#ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) { - if (n64 < 1024) - pr = 0; - else if (pr == -1) - pr = 1; - fv = (double)(stbsp__int64)n64; - goto doafloat; - } -#endif - - // convert to string - s = num + STBSP__NUMSZ; - l = 0; - - for (;;) { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char *o = s - 8; - if (n64 >= 100000000) { - n = (stbsp__uint32)(n64 % 100000000); - n64 /= 100000000; - } else { - n = (stbsp__uint32)n64; - n64 = 0; - } - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - do { - s -= 2; - *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - } while (n); - } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = (char)(n % 10) + '0'; - n /= 10; - } - } - if (n64 == 0) { - if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) - ++s; - break; - } - while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { - l = 0; - *--s = stbsp__comma; - --o; - } else { - *--s = '0'; - } - } - - tail[0] = 0; - stbsp__lead_sign(fl, lead); - - // get the length that we copied - l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { - *--s = '0'; - l = 1; - } - cs = l + (3 << 24); - if (pr < 0) - pr = 0; - - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr < (stbsp__int32)l) - pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw < (stbsp__int32)n) - fw = n; - fw -= n; - pr -= l; - - // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) { - if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr - { - pr = (fw > pr) ? fw : pr; - fw = 0; - } else { - fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas - } - } - - // copy the spaces and/or zeros - if (fw + pr) { - stbsp__int32 i; - stbsp__uint32 c; - - // copy leading spaces (or when doing %8.4d stuff) - if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) { - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = ' '; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leader - sn = lead + 1; - while (lead[0]) { - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy leading zeros - c = cs >> 24; - cs &= 0xffffff; - cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) { - stbsp__cb_buf_clamp(i, pr); - pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - } - while (i) { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { - cs = 0; - *bf++ = stbsp__comma; - } else - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - } - - // copy leader if there is still one - sn = lead + 1; - while (lead[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, lead[0]); - lead[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy the string - n = l; - while (n) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, n); - n -= i; - STBSP__UNALIGNED(while (i >= 4) { - *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; - bf += 4; - s += 4; - i -= 4; - }) - while (i) { - *bf++ = *s++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy trailing zeros - while (tz) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tz); - tz -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = '0'; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x30303030; - bf += 4; - i -= 4; - } - while (i) { - *bf++ = '0'; - --i; - } - stbsp__chk_cb_buf(1); - } - - // copy tail if there is one - sn = tail + 1; - while (tail[0]) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, tail[0]); - tail[0] -= (char)i; - while (i) { - *bf++ = *sn++; - --i; - } - stbsp__chk_cb_buf(1); - } - - // handle the left justify - if (fl & STBSP__LEFTJUST) - if (fw > 0) { - while (fw) { - stbsp__int32 i; - stbsp__cb_buf_clamp(i, fw); - fw -= i; - while (i) { - if ((((stbsp__uintptr)bf) & 3) == 0) - break; - *bf++ = ' '; - --i; - } - while (i >= 4) { - *(stbsp__uint32 *)bf = 0x20202020; - bf += 4; - i -= 4; - } - while (i--) - *bf++ = ' '; - stbsp__chk_cb_buf(1); - } - } - break; - - default: // unknown, just copy code - s = num + STBSP__NUMSZ - 1; - *s = f[0]; - l = 1; - fw = fl = 0; - lead[0] = 0; - tail[0] = 0; - pr = 0; - dp = 0; - cs = 0; - goto scopy; - } - ++f; - } -endfmt: - - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - -done: - return tlen + (int)(bf - buf); -} - -// cleanup -#undef STBSP__LEFTJUST -#undef STBSP__LEADINGPLUS -#undef STBSP__LEADINGSPACE -#undef STBSP__LEADING_0X -#undef STBSP__LEADINGZERO -#undef STBSP__INTMAX -#undef STBSP__TRIPLET_COMMA -#undef STBSP__NEGATIVE -#undef STBSP__METRIC_SUFFIX -#undef STBSP__NUMSZ -#undef stbsp__chk_cb_bufL -#undef stbsp__chk_cb_buf -#undef stbsp__flush_cb -#undef stbsp__cb_buf_clamp - -// ============================================================================ -// wrapper functions - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); - va_end(va); - return result; -} - -typedef struct stbsp__context { - char *buf; - int count; - int length; - char tmp[STB_SPRINTF_MIN]; -} stbsp__context; - -static char *stbsp__clamp_callback(const char *buf, void *user, int len) -{ - stbsp__context *c = (stbsp__context *)user; - c->length += len; - - if (len > c->count) - len = c->count; - - if (len) { - if (buf != c->buf) { - const char *s, *se; - char *d; - d = c->buf; - s = buf; - se = buf + len; - do { - *d++ = *s++; - } while (s < se); - } - c->buf += len; - c->count -= len; - } - - if (c->count <= 0) - return c->tmp; - return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can -} - -static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) -{ - stbsp__context * c = (stbsp__context*)user; - (void) sizeof(buf); - - c->length += len; - return c->tmp; // go direct into buffer if you can -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) -{ - stbsp__context c; - - if ( (count == 0) && !buf ) - { - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); - } - else - { - int l; - - c.buf = buf; - c.count = count; - c.length = 0; - - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; - } - - return c.length; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) -{ - int result; - va_list va; - va_start(va, fmt); - - result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); - va_end(va); - - return result; -} - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) -{ - return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); -} - -// ======================================================================= -// low level float utility functions - -#ifndef STB_SPRINTF_NOFLOAT - -// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest, src) \ - { \ - int cn; \ - for (cn = 0; cn < 8; cn++) \ - ((char *)&dest)[cn] = ((char *)&src)[cn]; \ - } - -// get float info -static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) -{ - double d; - stbsp__int64 b = 0; - - // load value and round at the frac_digits - d = value; - - STBSP__COPYFP(b, d); - - *bits = b & ((((stbsp__uint64)1) << 52) - 1); - *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - - return (stbsp__int32)((stbsp__uint64) b >> 63); -} - -static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; -static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; -static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; -static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; -static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; -static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; -static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 -}; - -#if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; -#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) -#else -static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; -#define stbsp__tento19th (1000000000000000000ULL) -#endif - -#define stbsp__ddmulthi(oh, ol, xh, yh) \ - { \ - double ahi = 0, alo, bhi = 0, blo; \ - stbsp__int64 bt; \ - oh = xh * yh; \ - STBSP__COPYFP(bt, xh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(ahi, bt); \ - alo = xh - ahi; \ - STBSP__COPYFP(bt, yh); \ - bt &= ((~(stbsp__uint64)0) << 27); \ - STBSP__COPYFP(bhi, bt); \ - blo = yh - bhi; \ - ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ - } - -#define stbsp__ddtoS64(ob, xh, xl) \ - { \ - double ahi = 0, alo, vh, t; \ - ob = (stbsp__int64)xh; \ - vh = (double)ob; \ - ahi = (xh - vh); \ - t = (ahi - xh); \ - alo = (xh - (ahi - t)) - (vh + t); \ - ob += (stbsp__int64)(ahi + alo + xl); \ - } - -#define stbsp__ddrenorm(oh, ol) \ - { \ - double s; \ - s = oh + ol; \ - ol = ol - (s - oh); \ - oh = s; \ - } - -#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); - -#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); - -static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 -{ - double ph, pl; - if ((power >= 0) && (power <= 22)) { - stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { - stbsp__int32 e, et, eb; - double p2h, p2l; - - e = power; - if (power < 0) - e = -e; - et = (e * 0x2c9) >> 14; /* %23 */ - if (et > 13) - et = 13; - eb = e - (et * 23); - - ph = d; - pl = 0.0; - if (power < 0) { - if (eb) { - --eb; - stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); - stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); - ph = p2h; - pl = p2l; - } - } else { - if (eb) { - e = eb; - if (eb > 22) - eb = 22; - e -= eb; - stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { - stbsp__ddrenorm(ph, pl); - stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); - stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); - ph = p2h; - pl = p2l; - } - } - if (et) { - stbsp__ddrenorm(ph, pl); - --et; - stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); - stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); - ph = p2h; - pl = p2l; - } - } - } - stbsp__ddrenorm(ph, pl); - *ohi = ph; - *olo = pl; -} - -// given a float value, returns the significant bits in bits, and the position of the -// decimal point in decimal_pos. +/-INF and NAN are specified by special values -// returned in the decimal_pos parameter. -// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) -{ - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; - - d = value; - STBSP__COPYFP(bits, d); - expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64) bits >> 63); - if (ng) - d = -d; - - if (expo == 2047) // is nan or inf? - { - *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if (expo == 0) // is zero or denormal - { - if (((stbsp__uint64) bits << 1) == 0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; - *len = 1; - return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { - --expo; - v >>= 1; - } - } - } - - // find the decimal exponent as well as the decimal bits of the value - { - double ph, pl; - - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens = expo - 1023; - tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - - // get full as much precision from double-double as possible - stbsp__ddtoS64(bits, ph, pl); - - // check if we undershot - if (((stbsp__uint64)bits) >= stbsp__tento19th) - ++tens; - } - - // now do the rounding in integer land - frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { - stbsp__uint32 dg = 1; - if ((stbsp__uint64)bits >= stbsp__powten[9]) - dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { - ++dg; - if (dg == 20) - goto noround; - } - if (frac_digits < dg) { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ((stbsp__uint32)e >= 24) - goto noround; - r = stbsp__powten[e]; - bits = bits + (r / 2); - if ((stbsp__uint64)bits >= stbsp__powten[dg]) - ++tens; - bits /= r; - } - noround:; - } - - // kill long trailing runs of zeros - if (bits) { - stbsp__uint32 n; - for (;;) { - if (bits <= 0xffffffff) - break; - if (bits % 1000) - goto donez; - bits /= 1000; - } - n = (stbsp__uint32)bits; - while ((n % 1000) == 0) - n /= 1000; - bits = n; - donez:; - } - - // convert to string - out += 64; - e = 0; - for (;;) { - stbsp__uint32 n; - char *o = out - 8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { - n = (stbsp__uint32)(bits % 100000000); - bits /= 100000000; - } else { - n = (stbsp__uint32)bits; - bits = 0; - } - while (n) { - out -= 2; - *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; - n /= 100; - e += 2; - } - if (bits == 0) { - if ((e) && (out[0] == '0')) { - ++out; - --e; - } - break; - } - while (out != o) { - *--out = '0'; - ++e; - } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; -} - -#undef stbsp__ddmulthi -#undef stbsp__ddrenorm -#undef stbsp__ddmultlo -#undef stbsp__ddmultlos -#undef STBSP__SPECIAL -#undef STBSP__COPYFP - -#endif // STB_SPRINTF_NOFLOAT - -// clean up -#undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 -#undef stbsp__uint64 -#undef stbsp__int64 -#undef STBSP__UNALIGNED - -#endif // STB_SPRINTF_IMPLEMENTATION - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/