Made a much better vbprintf()
This commit is contained in:
parent
b009b6b3c6
commit
cd66216847
2
Makefile
2
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
|
$(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}
|
||||||
|
|
||||||
|
|
|
@ -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 :
|
||||||
```
|
```
|
||||||
|
|
|
@ -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,251 +128,255 @@ 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
|
// Deal with all non-'%' characters
|
||||||
loop:
|
if (*fmt != '%') {
|
||||||
|
rc = bputc(buf, *fmt);
|
||||||
// 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 {
|
|
||||||
fmt++;
|
fmt++;
|
||||||
goto loop;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Reset everything
|
//
|
||||||
width = 0;
|
// %[parameter][flags][width|*][.precision|*][length]type
|
||||||
cap = sgn = 0;
|
// We aren't dealing with parameters and floating stuff just yet
|
||||||
l = h = hh = 0;
|
//
|
||||||
plus = minus = space = zero = hash = 0;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
// Skip the '%'
|
||||||
|
fmt++;
|
||||||
|
|
||||||
//
|
// "%%" modifier
|
||||||
// Flags field
|
if (*fmt == '%') {
|
||||||
//
|
rc = bputc(buf, '%');
|
||||||
while (1) {
|
|
||||||
if (*fmt == '#') hash++;
|
fmt++;
|
||||||
else if (*fmt == '0') zero++;
|
continue;
|
||||||
else if (*fmt == '+') plus++;
|
}
|
||||||
else if (*fmt == '-') minus++;
|
|
||||||
else if (*fmt == ' ') space++;
|
|
||||||
else break;
|
|
||||||
fmtnext();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
// Reset everything
|
||||||
|
cap = sgn = 0;
|
||||||
|
l = h = hh = 0;
|
||||||
|
width = prec = 0;
|
||||||
|
plus = minus = space = zero = hash = 0;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Width field
|
// Flags field
|
||||||
// A width field of zero is ignored
|
//
|
||||||
//
|
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 == '*') {
|
// Width & precision fields
|
||||||
fmtnext();
|
// A width field of zero is ignored
|
||||||
tmpwidth = va_arg(ap, int);
|
//
|
||||||
|
|
||||||
|
// 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
|
// 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
|
// Extract precision
|
||||||
while (isdigit(*fmt) && width < sizeof(convbuf)-10) {
|
if (*fmt == '.') {
|
||||||
width = 10 * width + (*fmt - '0');
|
fmt++;
|
||||||
fmtnext();
|
bextractwp(prec);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (width > sizeof(convbuf)) {
|
// Make sure they're not too big
|
||||||
rc = EINVAL;
|
if (width > CONVBUFSIZE || prec > CONVBUFSIZE) {
|
||||||
goto leave;
|
rc = EINVAL;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
//
|
||||||
|
// Length field
|
||||||
|
//
|
||||||
|
|
||||||
//
|
while (*fmt) {
|
||||||
// Precision field
|
if (*fmt == 'l' || *fmt == 'z' || *fmt == 't') {
|
||||||
// Ignored until floats are implemented
|
fmt++;
|
||||||
// TODO before floats: %.XXXs
|
l++;
|
||||||
//
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
else if (*fmt == 'h') {
|
||||||
|
fmt++;
|
||||||
|
h++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
// Consistency check
|
||||||
// Length field
|
assert(!(l > 0 && h > 0));
|
||||||
//
|
assert(!(l > 2 || h > 1));
|
||||||
while (1) {
|
|
||||||
if (*fmt == 'l' || *fmt == 'z') l++;
|
|
||||||
else if (*fmt == 'h') h++;
|
|
||||||
else break;
|
|
||||||
fmtnext();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consistency check
|
//
|
||||||
assert(!(l > 0 && h > 0));
|
// The type field
|
||||||
assert(!(l > 2 || h > 2));
|
//
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
type = *fmt++;
|
||||||
|
|
||||||
//
|
// Characters
|
||||||
// The type field
|
if (type == 'c') {
|
||||||
//
|
uch = (uchar)va_arg(ap, int);
|
||||||
type = *fmt++;
|
bputc(buf, uch);
|
||||||
|
|
||||||
// Characters
|
continue;
|
||||||
if (type == 'c') {
|
}
|
||||||
uch = (uchar)va_arg(ap, int);
|
|
||||||
bputc(buf, uch);
|
|
||||||
|
|
||||||
goto loop;
|
// Strings
|
||||||
}
|
else if (type == 's') {
|
||||||
|
s = va_arg(ap, char *);
|
||||||
|
|
||||||
// Strings
|
if (s == NULL) s = "(null)";
|
||||||
else if (type == 's') {
|
|
||||||
s = va_arg(ap, char *);
|
|
||||||
|
|
||||||
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++) {
|
for (; !rc && *s ; s++) {
|
||||||
rc = bputc(buf, (uchar)*s);
|
rc = bputc(buf, (uchar)*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc > 0) goto leave;
|
// 'minus' padding, only with spaces
|
||||||
goto loop;
|
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
|
return rc;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue