summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-03 21:27:49 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-03 21:27:49 -0400
commitaf6dce3665a403f6ef9e11956db05d3ba3461872 (patch)
tree7dc03ddd6d0fe38c6f321aa2bfdf5089d329c8d6
parentuse GDT.Data (diff)
downloadcomus-af6dce3665a403f6ef9e11956db05d3ba3461872.tar.gz
comus-af6dce3665a403f6ef9e11956db05d3ba3461872.tar.bz2
comus-af6dce3665a403f6ef9e11956db05d3ba3461872.zip
fix printf
-rw-r--r--lib/printf.c162
1 files changed, 108 insertions, 54 deletions
diff --git a/lib/printf.c b/lib/printf.c
index 3da3906..4dbbd4b 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -6,6 +6,13 @@
#define PRINTF_NUMERIC_BUF_LEN 50
+typedef union {
+ unsigned long long int u;
+ signed long long int i;
+ char *str;
+ char c;
+} data_t;
+
/// options that can be set inside a specifier
/// flags, width, precision, length, and data type
typedef struct {
@@ -59,8 +66,6 @@ typedef struct {
/* input */
/// the origonal format string
const char *format;
- /// variable args passed in
- va_list *args;
/// maximum allowed output length
size_t max_len;
/// if a maximum output length is set
@@ -108,6 +113,9 @@ static int parse_flag(const char **res, options_t *opts)
opts->space = 1;
break;
case '#':
+ opts->hash = 1;
+ break;
+ case '0':
opts->zero = 1;
break;
default:
@@ -243,6 +251,19 @@ static int printf_lltoa(char *buf, options_t *opts, bool is_neg,
int precision = 0;
char *start = buf;
+ // get width of number
+ int len = 0;
+ unsigned long long int temp = num;
+ if (temp == 0)
+ len = 1;
+ while (temp) {
+ if (opts->precision_set && precision++ >= opts->precision)
+ break;
+ temp /= opts->radix;
+ len++;
+ }
+ precision = 0;
+
// sign
if (is_neg) {
*(buf++) = '-';
@@ -256,14 +277,21 @@ static int printf_lltoa(char *buf, options_t *opts, bool is_neg,
if (opts->hash) {
if (opts->radix == 8) {
*(buf++) = '0';
- *(buf++) = 'x';
+ *(buf++) = 'o';
}
if (opts->radix == 16) {
*(buf++) = '0';
- *(buf++) = 'o';
+ *(buf++) = 'x';
}
}
+
+ // print zeros if needed
+ if (opts->width_set && len < opts->width && opts->zero) {
+ while(len++ < opts->width)
+ *(buf++) = '0';
+ }
+
// write number
if (num == 0) {
*(buf++) = '0';
@@ -271,7 +299,7 @@ static int printf_lltoa(char *buf, options_t *opts, bool is_neg,
while (num) {
if (opts->precision_set && precision++ >= opts->precision)
break;
- *(buf++) = printf_itoc(opts->is_uppercase, num & opts->radix);
+ *(buf++) = printf_itoc(opts->is_uppercase, num % opts->radix);
num /= opts->radix;
}
*(buf++) = '\0';
@@ -280,36 +308,10 @@ static int printf_lltoa(char *buf, options_t *opts, bool is_neg,
}
static void handle_int_specifier(context_t *ctx, options_t *const opts,
- bool has_sign_bit)
+ bool has_sign_bit, data_t num)
{
- union {
- unsigned long long int u;
- signed long long int i;
- } num;
bool is_neg = false;
- // read number from arg
- switch (opts->len) {
- case PRINTF_LEN_CHAR:
- num.u = va_arg(*ctx->args, unsigned int); // char
- break;
- case PRINTF_LEN_SHORT_INT:
- num.u = va_arg(*ctx->args, unsigned int); // short int
- break;
- case PRINTF_LEN_INT:
- num.u = va_arg(*ctx->args, unsigned int);
- break;
- case PRINTF_LEN_LONG_INT:
- num.u = va_arg(*ctx->args, unsigned long int);
- break;
- case PRINTF_LEN_LONG_LONG_INT:
- num.u = va_arg(*ctx->args, unsigned long long int);
- break;
- case PRINTF_LEN_SIZE_T:
- num.u = va_arg(*ctx->args, size_t);
- break;
- }
-
// get sign if possible neg
if (has_sign_bit) {
if (num.i < 0) {
@@ -343,15 +345,14 @@ static void handle_int_specifier(context_t *ctx, options_t *const opts,
}
}
-static void handle_char_specifier(context_t *ctx)
+static void handle_char_specifier(context_t *ctx, data_t c)
{
- char c = va_arg(*ctx->args, int);
- printf_putc(ctx, c);
+ printf_putc(ctx, c.c);
}
-static void handle_string_specifier(context_t *ctx, options_t *opts)
+static void handle_string_specifier(context_t *ctx, options_t *opts, data_t data)
{
- char *str = va_arg(*ctx->args, char *);
+ char *str = data.str;
int str_len = 0;
// get length of string
@@ -381,12 +382,12 @@ static void handle_string_specifier(context_t *ctx, options_t *opts)
}
}
-static void do_printf(context_t *ctx)
+static void do_printf(context_t *ctx, va_list args)
{
const char *fmt = ctx->format;
- char c = *(fmt++);
- while (c != '\0') {
+ char c;
+ while (c = *fmt++, c != '\0') {
// save start of fmt for current iteration
const char *start = fmt;
@@ -405,47 +406,90 @@ static void do_printf(context_t *ctx)
parse_length(&fmt, &opts);
// read specifier
- char spec = *(fmt++);
+ char spec = *fmt++;
get_radix(spec, &opts);
get_case(spec, &opts);
// read varied width / precision
if (opts.width_varies) {
opts.width_set = 1;
- opts.width = va_arg(*ctx->args, int);
+ opts.width = va_arg(args, int);
}
if (opts.precision_varies) {
opts.precision_set = 1;
- opts.precision = va_arg(*ctx->args, int);
+ opts.precision = va_arg(args, int);
+ }
+ // read data from args
+ data_t data;
+ switch (spec) {
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ // read number from arg
+ switch (opts.len) {
+ case PRINTF_LEN_CHAR:
+ data.u = va_arg(args, unsigned int); // char
+ break;
+ case PRINTF_LEN_SHORT_INT:
+ data.u = va_arg(args, unsigned int); // short int
+ break;
+ case PRINTF_LEN_INT:
+ data.u = va_arg(args, unsigned int);
+ break;
+ case PRINTF_LEN_LONG_INT:
+ data.u = va_arg(args, unsigned long int);
+ break;
+ case PRINTF_LEN_LONG_LONG_INT:
+ data.u = va_arg(args, unsigned long long int);
+ break;
+ case PRINTF_LEN_SIZE_T:
+ data.u = va_arg(args, size_t);
+ break;
+ }
+ break;
+ // end int
+ case 's':
+ // read string
+ data.str = va_arg(args, void*);
+ break;
+ // end string
+ case 'c':
+ // read char
+ data.c = va_arg(args, int);
+ break;
+ // end char
}
switch (spec) {
// signed int
case 'd':
case 'i':
- handle_int_specifier(ctx, &opts, true);
+ handle_int_specifier(ctx, &opts, true, data);
break;
// unsigned int
case 'u':
case 'o':
case 'x':
case 'X':
- handle_int_specifier(ctx, &opts, false);
+ handle_int_specifier(ctx, &opts, false, data);
break;
// character
case 'c':
- handle_char_specifier(ctx);
+ handle_char_specifier(ctx, data);
break;
// string
case 's':
- handle_string_specifier(ctx, &opts);
+ handle_string_specifier(ctx, &opts, data);
break;
// unknown
default:
// print from % to current
for (; start < fmt; start++)
printf_putc(ctx, *start);
- return;
+ break;
}
}
}
@@ -488,12 +532,11 @@ size_t vsprintf(char *restrict s, const char *format, va_list args)
// create context
context_t ctx = { 0 };
ctx.format = format;
- ctx.args = &args;
// sprintf buffer
ctx.out.buf = s;
ctx.to_file = 0;
// print
- do_printf(&ctx);
+ do_printf(&ctx, args);
return ctx.written_len;
}
@@ -503,7 +546,6 @@ size_t vsnprintf(char *restrict s, size_t maxlen, const char *format,
// create context
context_t ctx = { 0 };
ctx.format = format;
- ctx.args = &args;
// sprintf buffer
ctx.out.buf = s;
ctx.to_file = 0;
@@ -511,7 +553,7 @@ size_t vsnprintf(char *restrict s, size_t maxlen, const char *format,
ctx.has_max_len = 1;
ctx.max_len = maxlen;
// print
- do_printf(&ctx);
+ do_printf(&ctx, args);
return ctx.written_len;
}
@@ -528,10 +570,22 @@ void vfprintf(FILE *stream, const char *format, va_list args)
// create context
context_t ctx = { 0 };
ctx.format = format;
- ctx.args = &args;
// fprintf stream
ctx.out.file = stream;
ctx.to_file = 1;
// print
- do_printf(&ctx);
+ do_printf(&ctx, args);
+}
+
+void putc(char c) {
+ fputc(stdout, c);
+}
+
+void puts(const char *str) {
+ fputs(stdout, str);
+}
+
+void fputs(FILE *stream, const char *s) {
+ while (*s)
+ fputc(stream, *s++);
}