Made a much better vbprintf()

This commit is contained in:
Julian Barathieu 2019-04-04 20:17:50 +02:00
parent b009b6b3c6
commit cd66216847
4 changed files with 225 additions and 228 deletions

View File

@ -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 $(KOBJDIR)/kernel/bprint.o: $(KERNELDIR)/kernel/buf/bprint.c $(KERNELDIR)/include/*/*.h
@$(KCC) $< -o $@ @$(KCC) $< -o $@
@echo ${CL2}[$@] ${CL}Compiled.${CL3} @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 $@ @$(KCC) $< -o $@
@echo ${CL2}[$@] ${CL}Compiled.${CL3} @echo ${CL2}[$@] ${CL}Compiled.${CL3}

View File

@ -25,7 +25,7 @@ apt update && apt upgrade
apt install grub-pc dosfstools make nasm qemu 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 : To compile, simply use at the root of this project :
``` ```

View File

@ -87,13 +87,7 @@ static error_t bdopadding(Buffer_t *buf, size_t width, size_t len,
return rc; return rc;
} }
#define bdoconvrt(pref, type, vtype) do { \ #define CONVBUFSIZE 100
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)
// //
// Actually does BPrintOnBuf's job; doesn't lock anything // 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 vbprintf(Buffer_t *buf, const char *fmt, va_list ap)
{ {
error_t rc = EOK; error_t rc = 0;
int tmpwidth;
size_t width; int width, prec, len;
char type; char type;
uchar uch; uchar uch;
char *s; char *s;
// Conversion buffer // Conversion buffer
char convbuf[100]; char convbuf[CONVBUFSIZE];
size_t len;
// Flags // Flags
int plus, minus, space, zero, hash; int plus, minus, space, zero, hash;
@ -135,123 +128,120 @@ error_t vbprintf(Buffer_t *buf, const char *fmt, va_list ap)
return EBADF; return EBADF;
} }
//----------------------------------------------------------------------------// // Progress in format string
while (*fmt && !rc) {
// We come back here after dealing with a modifier
loop:
// Deal with all non-'%' characters // Deal with all non-'%' characters
for (; *fmt && *fmt != '%' ; fmt++) { if (*fmt != '%') {
rc = bputc(buf, *fmt); rc = bputc(buf, *fmt);
fmt++;
continue; continue;
} }
// Job's done / something bad happened
if (rc || !*fmt) goto leave;
//----------------------------------------------------------------------------//
// //
// %[parameter][flags][width|*][.precision][length]type // %[parameter][flags][width|*][.precision|*][length]type
// We aren't dealing with parameters and float stuff just yet // We aren't dealing with parameters and floating stuff just yet
// //
// Skip the '%' // Skip the '%'
fmtnext(); fmt++;
// "%%" modifier // "%%" modifier
if (*fmt == '%') { if (*fmt == '%') {
rc = bputc(buf, '%'); rc = bputc(buf, '%');
if (rc > 0) goto leave;
else {
fmt++; fmt++;
goto loop; continue;
}
} }
// Reset everything // Reset everything
width = 0;
cap = sgn = 0; cap = sgn = 0;
l = h = hh = 0; l = h = hh = 0;
width = prec = 0;
plus = minus = space = zero = hash = 0; plus = minus = space = zero = hash = 0;
//----------------------------------------------------------------------------//
// //
// Flags field // Flags field
// //
while (1) { while (*fmt) {
if (*fmt == '#') hash++; if (*fmt == '#') { fmt++; hash++; }
else if (*fmt == '0') zero++; else if (*fmt == '0') { fmt++; zero++; }
else if (*fmt == '+') plus++; else if (*fmt == '+') { fmt++; plus++; }
else if (*fmt == '-') minus++; else if (*fmt == '-') { fmt++; minus++; }
else if (*fmt == ' ') space++; else if (*fmt == ' ') { fmt++; space++; }
// Next field
else break; else break;
fmtnext();
} }
//----------------------------------------------------------------------------//
// //
// Width field // Width & precision fields
// A width field of zero is ignored // A width field of zero is ignored
// //
// '*' means we should extract it from the argument list // Extracts either width or precision
if (*fmt == '*') { #define bextractwp(name) \
fmtnext(); do { \
tmpwidth = va_arg(ap, int); 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 // A width below 0 activates the "minus" flag
if (tmpwidth < 0) { if (width < 0) {
width = -tmpwidth; width = -width;
minus++; minus++;
} else {
width = tmpwidth;
}
} else {
// Extract width field from fmt
while (isdigit(*fmt) && width < sizeof(convbuf)-10) {
width = 10 * width + (*fmt - '0');
fmtnext();
}
} }
if (width > sizeof(convbuf)) { // Extract precision
if (*fmt == '.') {
fmt++;
bextractwp(prec);
}
// Make sure they're not too big
if (width > CONVBUFSIZE || prec > CONVBUFSIZE) {
rc = EINVAL; rc = EINVAL;
goto leave; break;
} }
//----------------------------------------------------------------------------//
//
// Precision field
// Ignored until floats are implemented
// TODO before floats: %.XXXs
//
//----------------------------------------------------------------------------//
// //
// Length field // Length field
// //
while (1) {
if (*fmt == 'l' || *fmt == 'z') l++; while (*fmt) {
else if (*fmt == 'h') h++; if (*fmt == 'l' || *fmt == 'z' || *fmt == 't') {
fmt++;
l++;
}
else if (*fmt == 'h') {
fmt++;
h++;
}
// Next field
else break; else break;
fmtnext();
} }
// Consistency check // Consistency check
assert(!(l > 0 && h > 0)); assert(!(l > 0 && h > 0));
assert(!(l > 2 || h > 2)); assert(!(l > 2 || h > 1));
//----------------------------------------------------------------------------//
// //
// The type field // The type field
// //
type = *fmt++; type = *fmt++;
// Characters // Characters
@ -259,7 +249,7 @@ loop:
uch = (uchar)va_arg(ap, int); uch = (uchar)va_arg(ap, int);
bputc(buf, uch); bputc(buf, uch);
goto loop; continue;
} }
// Strings // Strings
@ -268,12 +258,16 @@ loop:
if (s == NULL) s = "(null)"; if (s == NULL) s = "(null)";
for (; !rc && *s ; s++) { // 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); rc = bputc(buf, (uchar)*s);
} }
if (rc > 0) goto leave; continue;
goto loop;
} }
// Decimal, unsigned decimal, hexadecimal, octal and binary numbers // Decimal, unsigned decimal, hexadecimal, octal and binary numbers
@ -284,7 +278,7 @@ loop:
else if (type == 'o') { base = 8; } else if (type == 'o') { base = 8; }
else if (type == 'b') { base = 2; } else if (type == 'b') { base = 2; }
// Pointers: %p = %#012x // Pointers: %p = %#012lx
// (48-bit pointers have width 12 at least) // (48-bit pointers have width 12 at least)
else if (type == 'p') { else if (type == 'p') {
type = 'x'; base = 16; zero++; hash++; l++; type = 'x'; base = 16; zero++; hash++; l++;
@ -292,29 +286,33 @@ loop:
} }
// Unknown/unsupported modifier // Unknown/unsupported modifier
// Note: a '\0' after length field falls here
else { else {
rc = EINVAL; rc = EINVAL;
goto leave; break;
} }
//----------------------------------------------------------------------------//
// //
// Numerical conversions // Numerical conversions
// //
// We re-use s to iterate convbuf // We use s to iterate convbuf
s = 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 (!l) {
if (sgn) { if (sgn) {
if (h == 0) bdoconvrt(i, int, int); if (h == 0) bdoconvrt(i, int, int);
if (h == 1) bdoconvrt(i, short, int); if (h == 1) bdoconvrt(i, short, int);
if (h == 2) bdoconvrt(i, char, int);
} else { } else {
if (h == 0) bdoconvrt(u, uint, uint); if (h == 0) bdoconvrt(u, uint, uint);
if (h == 1) bdoconvrt(u, ushort, uint); if (h == 1) bdoconvrt(u, ushort, uint);
if (h == 2) bdoconvrt(u, uchar, uint);
} }
} }
@ -323,8 +321,6 @@ loop:
else bdoconvrt(ul, ulong, ulong); else bdoconvrt(ul, ulong, ulong);
} }
//----------------------------------------------------------------------------//
// //
// Implement flags and %X, and prints // Implement flags and %X, and prints
// //
@ -340,7 +336,10 @@ loop:
// Reset s // Reset s
s = convbuf; s = convbuf;
} }
else len = strlen(s);
// Compute s's length
// It will always fit in an int
else len = (int)strlen(s);
// Adjust width // Adjust width
if (sgn && (plus || space)) width--; if (sgn && (plus || space)) width--;
@ -372,14 +371,12 @@ loop:
if (minus && !zero && width > len) if (minus && !zero && width > len)
bdopadding(buf, width, base, ' '); bdopadding(buf, width, base, ' ');
if (rc > 0) goto leave; // Carry on to next modifier
}
// Continue parsing fmt // Assert rc for debugging purposes
goto loop; assert(!rc);
//----------------------------------------------------------------------------//
leave:
return rc; return rc;
} }