From cd662168471538c13f1f9abc5491c783328886e1 Mon Sep 17 00:00:00 2001 From: Julian Barathieu Date: Thu, 4 Apr 2019 20:17:50 +0200 Subject: [PATCH] Made a much better vbprintf() --- Makefile | 2 +- README.md | 2 +- kaleid/kernel/buf/bprint.c | 449 ++++++++++++++--------------- kaleid/kernel/{proc => ps}/sched.c | 0 4 files changed, 225 insertions(+), 228 deletions(-) rename kaleid/kernel/{proc => ps}/sched.c (100%) diff --git a/Makefile b/Makefile index b3653f9..e8d5967 100644 --- a/Makefile +++ b/Makefile @@ -178,7 +178,7 @@ $(KOBJDIR)/kernel/bput.o: $(KERNELDIR)/kernel/buf/bput.c $(KERNELDIR)/include/*/ $(KOBJDIR)/kernel/bprint.o: $(KERNELDIR)/kernel/buf/bprint.c $(KERNELDIR)/include/*/*.h @$(KCC) $< -o $@ @echo ${CL2}[$@] ${CL}Compiled.${CL3} -$(KOBJDIR)/kernel/sched.o: $(KERNELDIR)/kernel/proc/sched.c $(KERNELDIR)/include/*/*.h +$(KOBJDIR)/kernel/sched.o: $(KERNELDIR)/kernel/ps/sched.c $(KERNELDIR)/include/*/*.h @$(KCC) $< -o $@ @echo ${CL2}[$@] ${CL}Compiled.${CL3} diff --git a/README.md b/README.md index 5c486a0..e6f8557 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ apt update && apt upgrade apt install grub-pc dosfstools make nasm qemu ``` -You also need to have the [x86-64 ELF gcc cross-compiler](https://www.os-k.eu/build-tools/cross-cc.tar.xz) in `/opt/cross-cc`. +You also need to have the [x86-64 ELF gcc cross-compiler](https://www.os-k.eu/build-tools/cross-cc.tar.xz) and its "bin" repertory in your PATH. To compile, simply use at the root of this project : ``` diff --git a/kaleid/kernel/buf/bprint.c b/kaleid/kernel/buf/bprint.c index 1c49fd3..2118a5f 100644 --- a/kaleid/kernel/buf/bprint.c +++ b/kaleid/kernel/buf/bprint.c @@ -87,13 +87,7 @@ static error_t bdopadding(Buffer_t *buf, size_t width, size_t len, return rc; } -#define bdoconvrt(pref, type, vtype) do { \ - type i_##type = (type)va_arg(ap, vtype); \ - pref##toa(i_##type, s, base); \ -} while (0) - -// Increase fmt while parsing a modifier -#define fmtnext() do{fmt++;if(*fmt==0){rc=EINVAL;goto leave;}}while(0) +#define CONVBUFSIZE 100 // // Actually does BPrintOnBuf's job; doesn't lock anything @@ -101,17 +95,16 @@ static error_t bdopadding(Buffer_t *buf, size_t width, size_t len, // error_t vbprintf(Buffer_t *buf, const char *fmt, va_list ap) { - error_t rc = EOK; - int tmpwidth; - size_t width; + error_t rc = 0; + + int width, prec, len; char type; uchar uch; char *s; // Conversion buffer - char convbuf[100]; - size_t len; + char convbuf[CONVBUFSIZE]; // Flags int plus, minus, space, zero, hash; @@ -135,251 +128,255 @@ error_t vbprintf(Buffer_t *buf, const char *fmt, va_list ap) return EBADF; } -//----------------------------------------------------------------------------// + // Progress in format string + while (*fmt && !rc) { - // We come back here after dealing with a modifier -loop: - - // Deal with all non-'%' characters - for (; *fmt && *fmt != '%' ; fmt++) { - rc = bputc(buf, *fmt); - continue; - } - - // Job's done / something bad happened - if (rc || !*fmt) goto leave; - -//----------------------------------------------------------------------------// - - // - // %[parameter][flags][width|*][.precision][length]type - // We aren't dealing with parameters and float stuff just yet - // - - // Skip the '%' - fmtnext(); - - // "%%" modifier - if (*fmt == '%') { - rc = bputc(buf, '%'); - - if (rc > 0) goto leave; - else { + // Deal with all non-'%' characters + if (*fmt != '%') { + rc = bputc(buf, *fmt); + fmt++; - goto loop; + continue; } - } - // Reset everything - width = 0; - cap = sgn = 0; - l = h = hh = 0; - plus = minus = space = zero = hash = 0; + // + // %[parameter][flags][width|*][.precision|*][length]type + // We aren't dealing with parameters and floating stuff just yet + // -//----------------------------------------------------------------------------// + // Skip the '%' + fmt++; - // - // Flags field - // - while (1) { - if (*fmt == '#') hash++; - else if (*fmt == '0') zero++; - else if (*fmt == '+') plus++; - else if (*fmt == '-') minus++; - else if (*fmt == ' ') space++; - else break; - fmtnext(); - } + // "%%" modifier + if (*fmt == '%') { + rc = bputc(buf, '%'); + + fmt++; + continue; + } -//----------------------------------------------------------------------------// + // Reset everything + cap = sgn = 0; + l = h = hh = 0; + width = prec = 0; + plus = minus = space = zero = hash = 0; - // - // Width field - // A width field of zero is ignored - // + // + // Flags field + // + while (*fmt) { + if (*fmt == '#') { fmt++; hash++; } + else if (*fmt == '0') { fmt++; zero++; } + else if (*fmt == '+') { fmt++; plus++; } + else if (*fmt == '-') { fmt++; minus++; } + else if (*fmt == ' ') { fmt++; space++; } + + // Next field + else break; + } - // '*' means we should extract it from the argument list - if (*fmt == '*') { - fmtnext(); - tmpwidth = va_arg(ap, int); + // + // Width & precision fields + // A width field of zero is ignored + // + + // Extracts either width or precision + #define bextractwp(name) \ + do { \ + if (*fmt == '*') { \ + fmt++; \ + name = va_arg(ap, int); \ + } else { \ + while (isdigit(*fmt) && name < CONVBUFSIZE) { \ + name = 10 * name + (*fmt - '0'); \ + fmt++; \ + } \ + } \ + } while (0) + + // Extract width + bextractwp(width); // A width below 0 activates the "minus" flag - if (tmpwidth < 0) { - width = -tmpwidth; + if (width < 0) { + width = -width; minus++; - } else { - width = tmpwidth; } - } else { - // Extract width field from fmt - while (isdigit(*fmt) && width < sizeof(convbuf)-10) { - width = 10 * width + (*fmt - '0'); - fmtnext(); + + // Extract precision + if (*fmt == '.') { + fmt++; + bextractwp(prec); } - } - if (width > sizeof(convbuf)) { - rc = EINVAL; - goto leave; - } + // Make sure they're not too big + if (width > CONVBUFSIZE || prec > CONVBUFSIZE) { + rc = EINVAL; + break; + } -//----------------------------------------------------------------------------// + // + // Length field + // - // - // Precision field - // Ignored until floats are implemented - // TODO before floats: %.XXXs - // + while (*fmt) { + if (*fmt == 'l' || *fmt == 'z' || *fmt == 't') { + fmt++; + l++; + } -//----------------------------------------------------------------------------// + else if (*fmt == 'h') { + fmt++; + h++; + } + + // Next field + else break; + } - // - // Length field - // - while (1) { - if (*fmt == 'l' || *fmt == 'z') l++; - else if (*fmt == 'h') h++; - else break; - fmtnext(); - } + // Consistency check + assert(!(l > 0 && h > 0)); + assert(!(l > 2 || h > 1)); - // Consistency check - assert(!(l > 0 && h > 0)); - assert(!(l > 2 || h > 2)); + // + // The type field + // -//----------------------------------------------------------------------------// + type = *fmt++; - // - // The type field - // - type = *fmt++; + // Characters + if (type == 'c') { + uch = (uchar)va_arg(ap, int); + bputc(buf, uch); - // Characters - if (type == 'c') { - uch = (uchar)va_arg(ap, int); - bputc(buf, uch); + continue; + } - goto loop; - } + // Strings + else if (type == 's') { + s = va_arg(ap, char *); - // Strings - else if (type == 's') { - s = va_arg(ap, char *); + if (s == NULL) s = "(null)"; - if (s == NULL) s = "(null)"; + // For strings, the precision field gives the maximum + // amount of characters to be read from the stream + // Zero/nonspecified precision means unlimited amount + if (prec == 0) prec = INT_MAX; + + for (; *s && prec-- ; s++) { + rc = bputc(buf, (uchar)*s); + } + continue; + } + + // Decimal, unsigned decimal, hexadecimal, octal and binary numbers + else if (type == 'd' || type == 'i') { base = 10; sgn = 1; } + else if (type == 'X') { base = 16; cap = 1; } + else if (type == 'x') { base = 16; } + else if (type == 'u') { base = 10; } + else if (type == 'o') { base = 8; } + else if (type == 'b') { base = 2; } + + // Pointers: %p = %#012lx + // (48-bit pointers have width 12 at least) + else if (type == 'p') { + type = 'x'; base = 16; zero++; hash++; l++; + if (width < 12) width = 12; + } + + // Unknown/unsupported modifier + // Note: a '\0' after length field falls here + else { + rc = EINVAL; + break; + } + + // + // Numerical conversions + // + + // We use s to iterate convbuf + s = convbuf; + + // FIXME: this works, but is ugly as hell + #define bdoconvrt(pref, type, vtype) \ + do { \ + type i_##type = (type)va_arg(ap, vtype); \ + pref##toa(i_##type, s, base); \ + } while (0) + + if (!l) { + if (sgn) { + if (h == 0) bdoconvrt(i, int, int); + if (h == 1) bdoconvrt(i, short, int); + } else { + if (h == 0) bdoconvrt(u, uint, uint); + if (h == 1) bdoconvrt(u, ushort, uint); + } + } + + else { + if (sgn) bdoconvrt(l, long, long); + else bdoconvrt(ul, ulong, ulong); + } + + // + // Implement flags and %X, and prints + // + + // Capital letter digits + if (base > 10 && cap) { + for (; *s ; s++) + if (islower(*s)) *s = toupper(*s); + + // We use this "opportunity" to compute the length of s + len = s - convbuf; + + // Reset s + s = convbuf; + } + + // Compute s's length + // It will always fit in an int + else len = (int)strlen(s); + + // Adjust width + if (sgn && (plus || space)) width--; + else if (hash) width -= (base==8 ? 1 : ((base==2||base==16) ? 2 : 0)); + + // When padding with spaces, we pad before +/-'s etc + if (!minus && !zero && width > len) + bdopadding(buf, width, len, ' '); + + // Deal with signs and the hash flag + if (*s == '-') { rc = bputc(buf, '-'); s++, len--; } + else if (sgn && plus) rc = bputc(buf, '+'); + else if (sgn && space) rc = bputc(buf, ' '); + else bprinthash(buf, base, cap); + + // Deal with padding by zeroes + // The 'minus' flag makes no sense with the 'zero' one + if (zero && width > len) + bdopadding(buf, width, len, '0'); + + // + // Output the actual number + // for (; !rc && *s ; s++) { rc = bputc(buf, (uchar)*s); } - if (rc > 0) goto leave; - goto loop; - } + // 'minus' padding, only with spaces + if (minus && !zero && width > len) + bdopadding(buf, width, base, ' '); + + // Carry on to next modifier + } + + // Assert rc for debugging purposes + assert(!rc); - // Decimal, unsigned decimal, hexadecimal, octal and binary numbers - else if (type == 'd' || type == 'i') { base = 10; sgn = 1; } - else if (type == 'X') { base = 16; cap = 1; } - else if (type == 'x') { base = 16; } - else if (type == 'u') { base = 10; } - else if (type == 'o') { base = 8; } - else if (type == 'b') { base = 2; } - - // Pointers: %p = %#012x - // (48-bit pointers have width 12 at least) - else if (type == 'p') { - type = 'x'; base = 16; zero++; hash++; l++; - if (width < 12) width = 12; - } - - // Unknown/unsupported modifier - else { - rc = EINVAL; - goto leave; - } - -//----------------------------------------------------------------------------// - - // - // Numerical conversions - // - - // We re-use s to iterate convbuf - s = convbuf; - - if (!l) { - if (sgn) { - if (h == 0) bdoconvrt(i, int, int); - if (h == 1) bdoconvrt(i, short, int); - if (h == 2) bdoconvrt(i, char, int); - } else { - if (h == 0) bdoconvrt(u, uint, uint); - if (h == 1) bdoconvrt(u, ushort, uint); - if (h == 2) bdoconvrt(u, uchar, uint); - } - } - - else { - if (sgn) bdoconvrt(l, long, long); - else bdoconvrt(ul, ulong, ulong); - } - -//----------------------------------------------------------------------------// - - // - // Implement flags and %X, and prints - // - - // Capital letter digits - if (base > 10 && cap) { - for (; *s ; s++) - if (islower(*s)) *s = toupper(*s); - - // We use this "opportunity" to compute the length of s - len = s - convbuf; - - // Reset s - s = convbuf; - } - else len = strlen(s); - - // Adjust width - if (sgn && (plus || space)) width--; - else if (hash) width -= (base==8 ? 1 : ((base==2||base==16) ? 2 : 0)); - - // When padding with spaces, we pad before +/-'s etc - if (!minus && !zero && width > len) - bdopadding(buf, width, len, ' '); - - // Deal with signs and the hash flag - if (*s == '-') { rc = bputc(buf, '-'); s++, len--; } - else if (sgn && plus) rc = bputc(buf, '+'); - else if (sgn && space) rc = bputc(buf, ' '); - else bprinthash(buf, base, cap); - - // Deal with padding by zeroes - // The 'minus' flag makes no sense with the 'zero' one - if (zero && width > len) - bdopadding(buf, width, len, '0'); - - // - // Output the actual number - // - for (; !rc && *s ; s++) { - rc = bputc(buf, (uchar)*s); - } - - // 'minus' padding, only with spaces - if (minus && !zero && width > len) - bdopadding(buf, width, base, ' '); - - if (rc > 0) goto leave; - - // Continue parsing fmt - goto loop; - -//----------------------------------------------------------------------------// - -leave: - return rc; + return rc; } diff --git a/kaleid/kernel/proc/sched.c b/kaleid/kernel/ps/sched.c similarity index 100% rename from kaleid/kernel/proc/sched.c rename to kaleid/kernel/ps/sched.c