diff options
author | Jakob Kaivo <jkk@ung.org> | 2024-06-06 17:44:42 -0400 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2024-06-06 17:44:42 -0400 |
commit | 5195e91c57e8209bc0b54b470213497def444ea7 (patch) | |
tree | 000ac605742e81d99947196de2719e22876e3f8c | |
parent | d8353afab7c754968ebbaa8fa1cd3f6f4b83d86e (diff) |
more efficient output, especially padding
-rw-r--r-- | src/stdio/__printf.c | 72 |
1 files changed, 41 insertions, 31 deletions
diff --git a/src/stdio/__printf.c b/src/stdio/__printf.c index 34904d30..15b172f2 100644 --- a/src/stdio/__printf.c +++ b/src/stdio/__printf.c @@ -1,8 +1,6 @@ -#include <ctype.h> #include <limits.h> #include <stdio.h> #include <stddef.h> -#include <stdlib.h> #include <string.h> #include <wchar.h> @@ -18,78 +16,90 @@ #define NUMBUFLEN 64 -static int __output(struct io_options *opt, struct io_conversion *conv, const char *str, size_t len) +static void __output(struct io_options *opt, struct io_conversion *conv, const char *str, size_t len) { + static char pad[BUFSIZ] = ""; size_t olen = strlen(str); if (len == 0) { len = olen; } - if (conv && olen < conv->width && (conv->flags & F_WIDTH) && !(conv->flags & F_LEFT)) { - for (size_t i = 0; i < conv->width - olen; i++) { - __output(opt, NULL, " ", 1); - } + if (pad[0] == '\0') { + memset(pad, ' ', sizeof(pad)); } - - for (size_t i = 0; i < len && str[i] != '\0'; i++) { - if (opt->ret == INT_MAX) { - UNDEFINED("In call to %s(): Attempting to output more than INT_MAX characters", opt->fnname); - } - if (opt->stream) { - fputc(str[i], opt->stream); - } else if (opt->string) { - if ((size_t)opt->ret < opt->maxlen) { - opt->string[opt->ret] = str[i]; - } + + if (conv && (conv->flags & F_WIDTH)) { + if (conv->width < olen) { + conv->width = 0; } else { - /* file descriptor */ + conv->width -= olen; } - opt->ret++; } - if (conv && olen < conv->width && (conv->flags & F_WIDTH) && (conv->flags & F_LEFT)) { - for (size_t i = 0; i < conv->width - olen; i++) { - __output(opt, NULL, " ", 1); + if (conv && (conv->flags & F_WIDTH) && !(conv->flags & F_LEFT)) { + while (conv->width > 0) { + __output(opt, NULL, pad, conv->width % BUFSIZ); + conv->width -= conv->width % BUFSIZ; } } - return 0; + if (len > INT_MAX || opt->ret > INT_MAX - (int)len) { + UNDEFINED("In call to %s(): Attempting to output more than INT_MAX characters", opt->fnname); + } + + /* TODO: check for errors */ + if (opt->stream) { + opt->ret += fwrite(str, 1, len, opt->stream); + } else if (opt->string) { + memcpy(opt->string + opt->ret, str, len); + opt->ret += len; + } else { + /* opt->ret += write(opt->fd, str, len); */ + } + + if (conv && (conv->flags & F_WIDTH) && (conv->flags & F_LEFT)) { + while (conv->width > 0) { + __output(opt, NULL, pad, conv->width % BUFSIZ); + conv->width -= conv->width % BUFSIZ; + } + } } static void __utos(char *s, uintmax_t n, enum conversion_flags flags, int precision, int base) { - char digits[] = "0123456789abcdef"; + char lower[] = "0123456789abcdef"; + char upper[] = "0123456789ABCDEF"; + char *digits = (flags & F_UPPER ? upper : lower); char sign = '+'; char buf[NUMBUFLEN + 1]; char *out = buf + NUMBUFLEN; - if (flags & F_UPPER && base > 10) { - size_t i; - for (i = 0; i < sizeof(digits); i++) { - digits[i] = (char)toupper(digits[i]); - } - } + *out = '\0'; out--; if (n == 0) { *out = '0'; out--; } + while (n > 0) { precision--; *out = digits[n % base]; n /= base; out--; } + /* TODO: this has a risk of overflowing */ while (precision > 0 && (flags & (F_ZERO | F_PRECISION))) { *out = '0'; precision--; out--; } + if (flags & F_SIGN) { *out = sign; out--; } + out++; while ((*s++ = *out++) != 0) { continue; |