Added printf variants

This commit is contained in:
NeGate 2022-06-05 20:16:44 -04:00
parent 04555ac1db
commit e964f2375d
8 changed files with 313 additions and 46 deletions

View File

@ -4,6 +4,7 @@ setlocal enabledelayedexpansion
set PLATFORM=win32 set PLATFORM=win32
set CIABATTA_OPTIONS=-Iinc -g -gcodeview -nodefaultlibs -D_CRT_SECURE_NO_WARNINGS set CIABATTA_OPTIONS=-Iinc -g -gcodeview -nodefaultlibs -D_CRT_SECURE_NO_WARNINGS
del ciabatta.lib
for /R code %%F in (*.c) do ( for /R code %%F in (*.c) do (
echo %%F echo %%F
clang -c -o build\%%~nF.obj %%F %CIABATTA_OPTIONS% clang -c -o build\%%~nF.obj %%F %CIABATTA_OPTIONS%
@ -15,3 +16,5 @@ for /R platform\%PLATFORM% %%F in (*.c) do (
llvm-ar rc ciabatta.lib build\*.obj llvm-ar rc ciabatta.lib build\*.obj
clang test\test.c ciabatta.lib -lkernel32 -luser32 -lshell32 -nostdlib %CIABATTA_OPTIONS% clang test\test.c ciabatta.lib -lkernel32 -luser32 -lshell32 -nostdlib %CIABATTA_OPTIONS%
del build\*.obj

159
code/printf.h Normal file
View File

@ -0,0 +1,159 @@
// NOTE: this file doesn't exist in a vacuum, it's a template for generating
// the formatted print, you should define FMT_CHAR_TYPE before including it
inline static int FMT_FUNC_NAME (void *ctx, OutputFunc out, const FMT_CHAR_TYPE *fmt, va_list args) {
size_t full_length = 0;
while (*fmt) {
// skip any normal non percent text
const FMT_CHAR_TYPE *start = fmt;
while (*fmt && *fmt != '%') fmt++;
// print all those non percent text
out(ctx, fmt - start, start);
full_length += (fmt - start);
// null terminated
if (*fmt == '\0') break;
fmt += 1;
if (*fmt == '%') {
out(ctx, 1, "%");
fmt++;
continue;
}
unsigned int precision = 0;
if (*fmt == '.') {
// custom precision
fmt++;
if (isdigit(*fmt)) {
// just a small atoi
while (isdigit(*fmt)) {
precision *= 10u;
precision += (*fmt - '0');
fmt++;
}
} else if (*fmt == '*') {
int p = va_arg(args, int);
precision = p >= 0 ? ((unsigned int)p) : 0;
fmt++;
}
}
// integer length specifiers
enum {
CHAR,
SHORT,
INT,
LONG,
LLONG
} int_length = INT;
if (*fmt == 'l') {
fmt++;
if (*fmt == 'l') {
int_length = LLONG;
fmt++;
} else {
int_length = LONG;
}
} else if (*fmt == 'h') {
fmt++;
if (*fmt == 'h') {
int_length = CHAR;
fmt++;
} else {
int_length = SHORT;
}
}
FMT_CHAR_TYPE ch = *fmt++;
switch (ch) {
case 's': {
const FMT_CHAR_TYPE *str = va_arg(args, FMT_CHAR_TYPE*);
size_t len = FMT_STRLEN_S(str, precision ? precision : SIZE_MAX);
out(ctx, len, str);
full_length += len;
break;
}
case 'b':
case 'o':
case 'i':
case 'u':
case 'd':
case 'x':
case 'X': {
int base = 10;
switch (ch) {
case 'X': case 'x': base = 16; break;
case 'o': base = 8; break;
case 'b': base = 2; break;
default: base = 10; break;
}
const char* characters = "0123456789abcdef";
if (ch == 'X') characters = "0123456789ABCDEF";
uintmax_t i;
if (ch == 'd' || ch == 'i') {
intmax_t num = 0;
switch (int_length) {
case CHAR: num = (char) va_arg(args, int); break;
case SHORT: num = (short) va_arg(args, int); break;
case INT: num = va_arg(args, int); break;
case LONG: num = va_arg(args, long); break;
case LLONG: num = va_arg(args, long long); break;
default: break;
}
if (num < 0) {
out(ctx, 1, "-");
i = -num;
full_length += 1;
} else {
i = num;
}
} else {
switch (int_length) {
case CHAR: i = (char) va_arg(args, int); break;
case SHORT: i = (short) va_arg(args, int); break;
case INT: i = va_arg(args, int); break;
case LONG: i = va_arg(args, long); break;
case LLONG: i = va_arg(args, long long); break;
default: i = 0; break;
}
}
if (i == 0) {
out(ctx, 1, "0");
full_length += 1;
} else {
FMT_CHAR_TYPE buffer[20];
size_t len = sizeof(buffer);
// we build the number in reverse
while (i != 0) {
buffer[--len] = characters[i % base];
i /= base;
}
out(ctx, sizeof(buffer) - (len * sizeof(FMT_CHAR_TYPE)), buffer + len);
full_length += (sizeof(buffer) - len);
}
break;
}
default: break;
}
}
return full_length;
}

99
code/stdio.c Normal file
View File

@ -0,0 +1,99 @@
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
// Even if the user doesn't enable LIB_EXT1 we still have it existing
size_t strnlen_s(const char *s, size_t maxsize);
typedef void(*OutputFunc)(void* ctx, size_t n, const char str[]);
///////////////////////////////////////////////
// Instantiate formatted print functions
///////////////////////////////////////////////
// TODO: instantiate wide char variants of print
#define FMT_FUNC_NAME fmt_print_char
#define FMT_CHAR_TYPE char
#define FMT_STRLEN_S(s, maxsize) strnlen_s(s, maxsize)
#include "printf.h"
///////////////////////////////////////////////
// Platform dependent
///////////////////////////////////////////////
#if defined(_os_win)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
// It's just mapped directly to HANDLE
struct FILE {
int unused;
};
static void file_write(void* ctx, size_t n, const char str[]) {
DWORD written = 0;
WriteFile((HANDLE) ctx, str, n, &written, NULL);
}
#else
#error "TODO: Implement this"
#endif
///////////////////////////////////////////////
// Platform indenpendent
///////////////////////////////////////////////
typedef struct {
size_t used, capacity;
char* string;
} StrPrintCtx;
FILE *stdout, *stderr, *stdin;
#define CALL_PRINTF(fmt_func, ctx, out, fmt) \
va_list args; \
va_start(args, fmt); \
int result = fmt_func(ctx, out, fmt, args); \
va_end(args)
static void string_write(void *ctx, size_t n, const char *restrict str) {
StrPrintCtx *c = ctx;
memcpy(c->string + c->used, str, n);
c->used += n;
}
int fprintf(FILE *file, const char *restrict fmt, ...) {
CALL_PRINTF(fmt_print_char, file, file_write, fmt);
return result;
}
int printf(const char *restrict fmt, ...) {
CALL_PRINTF(fmt_print_char, stdout, file_write, fmt);
return result;
}
int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...) {
StrPrintCtx ctx = { 0, n, s };
CALL_PRINTF(fmt_print_char, &ctx, string_write, fmt);
return result;
}
int sprintf(char *restrict s, const char *restrict fmt, ...) {
StrPrintCtx ctx = { 0, SIZE_MAX, s };
CALL_PRINTF(fmt_print_char, &ctx, string_write, fmt);
return result;
}
int vfprintf(FILE *file, const char *restrict fmt, va_list args) {
return fmt_print_char(file, file_write, fmt, args);
}
int vprintf(const char *restrict fmt, va_list args) {
return fmt_print_char(stdout, file_write, fmt, args);
}
int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list args) {
StrPrintCtx ctx = { 0, n, s };
return fmt_print_char(&ctx, string_write, fmt, args);
}
int vsprintf(char *restrict s, const char *restrict fmt, va_list args) {
StrPrintCtx ctx = { 0, SIZE_MAX, s };
return fmt_print_char(&ctx, string_write, fmt, args);
}

View File

@ -49,6 +49,8 @@ size_t strlen(const char *s) {
// __STDC_WANT_LIB_EXT1__ // __STDC_WANT_LIB_EXT1__
size_t strnlen_s(const char *s, size_t maxsize) { size_t strnlen_s(const char *s, size_t maxsize) {
if (s == NULL) return 0;
size_t i = 0; size_t i = 0;
while (s[i] && i < maxsize) { while (s[i] && i < maxsize) {
i++; i++;

View File

@ -14,9 +14,9 @@ typedef int64_t fpos_t;
#define FOPEN_MAX 20 #define FOPEN_MAX 20
#ifdef _os_win #ifdef _os_win
#define FILENAME_MAX 260 #define FILENAME_MAX 260
#else #else
#define FILENAME_MAX 4096 #define FILENAME_MAX 4096
#endif #endif
#define L_tmpnam FILENAME_MAX #define L_tmpnam FILENAME_MAX
@ -27,10 +27,7 @@ typedef int64_t fpos_t;
#define TMP_MAX INT_MAX #define TMP_MAX INT_MAX
// TODO: complete these, they don't need to be macros btw, could be external globals extern FILE *stdout, *stderr, *stdin;
#define stderr ((FILE*)NULL)
#define stdin ((FILE*)NULL)
#define stdout ((FILE*)NULL)
int remove(const char *filename); int remove(const char *filename);
int rename(const char *oldname, const char *newname); int rename(const char *oldname, const char *newname);
@ -79,9 +76,9 @@ int ferror(FILE *stream);
void perror(const char *s); void perror(const char *s);
#ifdef __STDC_WANT_LIB_EXT1__ #ifdef __STDC_WANT_LIB_EXT1__
#define L_tmpnam_s L_tmpnam #define L_tmpnam_s L_tmpnam
#define TMP_MAX_S TMP_MAX #define TMP_MAX_S TMP_MAX
errno_t tmpfile_s(FILE * restrict * restrict streamptr); errno_t tmpfile_s(FILE * restrict * restrict streamptr);
errno_t tmpnam_s(char *s, rsize_t maxsize); errno_t tmpnam_s(char *s, rsize_t maxsize);
#endif #endif

View File

@ -8,7 +8,7 @@ typedef wchar_t wint_t;
#define WCHAR_MAX 0xffff #define WCHAR_MAX 0xffff
#ifndef WEOF #ifndef WEOF
#define WEOF 0 #define WEOF 0
#endif #endif
int fwprintf(FILE * restrict stream, const wchar_t * restrict format, ...); int fwprintf(FILE * restrict stream, const wchar_t * restrict format, ...);
@ -26,8 +26,7 @@ int wscanf(const wchar_t * restrict format, ...);
wint_t fgetwc(FILE *stream); wint_t fgetwc(FILE *stream);
wchar_t *fgetws(wchar_t * restrict s, int n, FILE * restrict stream); wchar_t *fgetws(wchar_t * restrict s, int n, FILE * restrict stream);
wint_t fputwc(wchar_t c, FILE *stream); wint_t fputwc(wchar_t c, FILE *stream);
int fputws(const wchar_t * restrict s, int fputws(const wchar_t * restrict s, FILE * restrict stream);
FILE * restrict stream);
int fwide(FILE *stream, int mode); int fwide(FILE *stream, int mode);
wint_t getwc(FILE *stream); wint_t getwc(FILE *stream);
wint_t getwchar(void); wint_t getwchar(void);
@ -73,32 +72,29 @@ size_t mbsrtowcs(wchar_t * restrict dst, const char ** restrict src, size_t len,
size_t wcsrtombs(char * restrict dst, const wchar_t ** restrict src, size_t len, mbstate_t * restrict ps); size_t wcsrtombs(char * restrict dst, const wchar_t ** restrict src, size_t len, mbstate_t * restrict ps);
#ifdef __STDC_WANT_LIB_EXT1__ #ifdef __STDC_WANT_LIB_EXT1__
int fwprintf_s(FILE * restrict stream, const wchar_t * restrict format, ...); int fwprintf_s(FILE * restrict stream, const wchar_t * restrict format, ...);
int fwscanf_s(FILE * restrict stream, const wchar_t * restrict format, ...); int fwscanf_s(FILE * restrict stream, const wchar_t * restrict format, ...);
int snwprintf_s(wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, ...); int snwprintf_s(wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, ...);
int swprintf_s(wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, ...); int swprintf_s(wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, ...);
int swscanf_s(const wchar_t * restrict s, const wchar_t * restrict format, ...); int swscanf_s(const wchar_t * restrict s, const wchar_t * restrict format, ...);
int vfwprintf_s(FILE * restrict stream, const wchar_t * restrict format, va_list arg); int vfwprintf_s(FILE * restrict stream, const wchar_t * restrict format, va_list arg);
int vfwscanf_s(FILE * restrict stream, const wchar_t * restrict format, va_list arg); int vfwscanf_s(FILE * restrict stream, const wchar_t * restrict format, va_list arg);
int vsnwprintf_s(wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, va_list arg); int vsnwprintf_s(wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, va_list arg);
int vswprintf_s(wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, va_list arg); int vswprintf_s(wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, va_list arg);
int vswscanf_s(const wchar_t * restrict s, const wchar_t * restrict format, va_list arg); int vswscanf_s(const wchar_t * restrict s, const wchar_t * restrict format, va_list arg);
int vwprintf_s(const wchar_t * restrict format, va_list arg); int vwprintf_s(const wchar_t * restrict format, va_list arg);
int vwscanf_s(const wchar_t * restrict format, va_list arg); int vwscanf_s(const wchar_t * restrict format, va_list arg);
int wprintf_s(const wchar_t * restrict format, ...); int wprintf_s(const wchar_t * restrict format, ...);
int wscanf_s(const wchar_t * restrict format, ...); int wscanf_s(const wchar_t * restrict format, ...);
errno_t wcscpy_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2); errno_t wcscpy_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2);
errno_t wcsncpy_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2, rsize_t n); errno_t wcsncpy_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2, rsize_t n);
errno_t wmemcpy_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2, rsize_t n); errno_t wmemcpy_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2, rsize_t n);
errno_t wmemmove_s(wchar_t *s1, rsize_t s1max, const wchar_t *s2, rsize_t n); errno_t wmemmove_s(wchar_t *s1, rsize_t s1max, const wchar_t *s2, rsize_t n);
errno_t wcscat_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2); errno_t wcscat_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2);
errno_t wcsncat_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2, rsize_t n); errno_t wcsncat_s(wchar_t * restrict s1, rsize_t s1max, const wchar_t * restrict s2, rsize_t n);
wchar_t *wcstok_s(wchar_t * restrict s1, rsize_t * restrict s1max, wchar_t *wcstok_s(wchar_t * restrict s1, rsize_t * restrict s1max, const wchar_t * restrict s2, wchar_t ** restrict ptr);
const wchar_t * restrict s2, wchar_t ** restrict ptr); size_t wcsnlen_s(const wchar_t *s, size_t maxsize);
size_t wcsnlen_s(const wchar_t *s, size_t maxsize); errno_t wcrtomb_s(size_t * restrict retval, char * restrict s, rsize_t smax, wchar_t wc, mbstate_t * restrict ps);
errno_t wcrtomb_s(size_t * restrict retval, errno_t mbsrtowcs_s(size_t * restrict retval, wchar_t * restrict dst, rsize_t dstmax, const char ** restrict src, rsize_t len, mbstate_t * restrict ps);
char * restrict s, rsize_t smax, errno_t wcsrtombs_s(size_t * restrict retval, char * restrict dst, rsize_t dstmax, const wchar_t ** restrict src, rsize_t len, mbstate_t * restrict ps);
wchar_t wc, mbstate_t * restrict ps); #endif
errno_t mbsrtowcs_s(size_t * restrict retval, wchar_t * restrict dst, rsize_t dstmax, const char ** restrict src, rsize_t len, mbstate_t * restrict ps);
errno_t wcsrtombs_s(size_t * restrict retval, char * restrict dst, rsize_t dstmax, const wchar_t ** restrict src, rsize_t len, mbstate_t * restrict ps);
#endif

View File

@ -2,6 +2,7 @@
#include <locale.h> #include <locale.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "win32.h" #include "win32.h"
@ -58,6 +59,12 @@ void mainCRTStartup() {
convert_wide_chars_to_ansi(args[i], args_wide[i], wide_len); convert_wide_chars_to_ansi(args[i], args_wide[i], wide_len);
} }
// Initialize terminal
stdout = (FILE*) GetStdHandle(STD_OUTPUT_HANDLE);
stderr = (FILE*) GetStdHandle(STD_ERROR_HANDLE);
stdin = (FILE*) GetStdHandle(STD_INPUT_HANDLE);
// Initialize heap
_os_heap heap_data = { _os_heap heap_data = {
.handle = heap, .handle = heap,
}; };

View File

@ -1,10 +1,14 @@
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <stdio.h>
int main(int argc, char** argv) { int main(int argc, char** argv) {
/*for (int i = 0; i < argv; i++) { for (int i = 0; i < argc; i++) {
printf("[%d] = %s\n", argv[i]); printf("[%d] = %s\n", i, argv[i]);
}*/ }
printf("%d\n", 583875381);
printf("%.*s", (int)3, "Hello");
for (char c = 'a'; c != 'z'; ++c) { for (char c = 'a'; c != 'z'; ++c) {
assert(isupper(toupper(c))); assert(isupper(toupper(c)));