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
|
||||
@$(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}
|
||||
|
||||
|
|
|
@ -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 :
|
||||
```
|
||||
|
|
|
@ -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,123 +128,120 @@ error_t vbprintf(Buffer_t *buf, const char *fmt, va_list ap)
|
|||
return EBADF;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// We come back here after dealing with a modifier
|
||||
loop:
|
||||
// Progress in format string
|
||||
while (*fmt && !rc) {
|
||||
|
||||
// Deal with all non-'%' characters
|
||||
for (; *fmt && *fmt != '%' ; fmt++) {
|
||||
if (*fmt != '%') {
|
||||
rc = bputc(buf, *fmt);
|
||||
|
||||
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
|
||||
// %[parameter][flags][width|*][.precision|*][length]type
|
||||
// We aren't dealing with parameters and floating stuff just yet
|
||||
//
|
||||
|
||||
// Skip the '%'
|
||||
fmtnext();
|
||||
fmt++;
|
||||
|
||||
// "%%" modifier
|
||||
if (*fmt == '%') {
|
||||
rc = bputc(buf, '%');
|
||||
|
||||
if (rc > 0) goto leave;
|
||||
else {
|
||||
fmt++;
|
||||
goto loop;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reset everything
|
||||
width = 0;
|
||||
cap = sgn = 0;
|
||||
l = h = hh = 0;
|
||||
width = prec = 0;
|
||||
plus = minus = space = zero = hash = 0;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
//
|
||||
// Flags field
|
||||
//
|
||||
while (1) {
|
||||
if (*fmt == '#') hash++;
|
||||
else if (*fmt == '0') zero++;
|
||||
else if (*fmt == '+') plus++;
|
||||
else if (*fmt == '-') minus++;
|
||||
else if (*fmt == ' ') space++;
|
||||
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;
|
||||
fmtnext();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
//
|
||||
// Width field
|
||||
// Width & precision fields
|
||||
// A width field of zero is ignored
|
||||
//
|
||||
|
||||
// '*' means we should extract it from the argument list
|
||||
if (*fmt == '*') {
|
||||
fmtnext();
|
||||
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
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
goto leave;
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
//
|
||||
// Precision field
|
||||
// Ignored until floats are implemented
|
||||
// TODO before floats: %.XXXs
|
||||
//
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
//
|
||||
// Length field
|
||||
//
|
||||
while (1) {
|
||||
if (*fmt == 'l' || *fmt == 'z') l++;
|
||||
else if (*fmt == 'h') h++;
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt == 'l' || *fmt == 'z' || *fmt == 't') {
|
||||
fmt++;
|
||||
l++;
|
||||
}
|
||||
|
||||
else if (*fmt == 'h') {
|
||||
fmt++;
|
||||
h++;
|
||||
}
|
||||
|
||||
// Next field
|
||||
else break;
|
||||
fmtnext();
|
||||
}
|
||||
|
||||
// Consistency check
|
||||
assert(!(l > 0 && h > 0));
|
||||
assert(!(l > 2 || h > 2));
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
assert(!(l > 2 || h > 1));
|
||||
|
||||
//
|
||||
// The type field
|
||||
//
|
||||
|
||||
type = *fmt++;
|
||||
|
||||
// Characters
|
||||
|
@ -259,7 +249,7 @@ loop:
|
|||
uch = (uchar)va_arg(ap, int);
|
||||
bputc(buf, uch);
|
||||
|
||||
goto loop;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Strings
|
||||
|
@ -268,12 +258,16 @@ loop:
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
if (rc > 0) goto leave;
|
||||
goto loop;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Decimal, unsigned decimal, hexadecimal, octal and binary numbers
|
||||
|
@ -284,7 +278,7 @@ loop:
|
|||
else if (type == 'o') { base = 8; }
|
||||
else if (type == 'b') { base = 2; }
|
||||
|
||||
// Pointers: %p = %#012x
|
||||
// Pointers: %p = %#012lx
|
||||
// (48-bit pointers have width 12 at least)
|
||||
else if (type == 'p') {
|
||||
type = 'x'; base = 16; zero++; hash++; l++;
|
||||
|
@ -292,29 +286,33 @@ loop:
|
|||
}
|
||||
|
||||
// Unknown/unsupported modifier
|
||||
// Note: a '\0' after length field falls here
|
||||
else {
|
||||
rc = EINVAL;
|
||||
goto leave;
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
//
|
||||
// Numerical conversions
|
||||
//
|
||||
|
||||
// We re-use s to iterate convbuf
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,8 +321,6 @@ loop:
|
|||
else bdoconvrt(ul, ulong, ulong);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
//
|
||||
// Implement flags and %X, and prints
|
||||
//
|
||||
|
@ -340,7 +336,10 @@ loop:
|
|||
// Reset s
|
||||
s = convbuf;
|
||||
}
|
||||
else len = strlen(s);
|
||||
|
||||
// Compute s's length
|
||||
// It will always fit in an int
|
||||
else len = (int)strlen(s);
|
||||
|
||||
// Adjust width
|
||||
if (sgn && (plus || space)) width--;
|
||||
|
@ -372,14 +371,12 @@ loop:
|
|||
if (minus && !zero && width > len)
|
||||
bdopadding(buf, width, base, ' ');
|
||||
|
||||
if (rc > 0) goto leave;
|
||||
// Carry on to next modifier
|
||||
}
|
||||
|
||||
// Continue parsing fmt
|
||||
goto loop;
|
||||
// Assert rc for debugging purposes
|
||||
assert(!rc);
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
leave:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue