diff options
| -rw-r--r-- | kc/api/lib.h | 4 | ||||
| -rw-r--r-- | kc/core/Makefile | 2 | ||||
| -rw-r--r-- | kc/core/kprint.c | 91 | ||||
| -rw-r--r-- | lib/strtoull.c | 148 |
4 files changed, 239 insertions, 6 deletions
diff --git a/kc/api/lib.h b/kc/api/lib.h index 3bf0eca..c28e17c 100644 --- a/kc/api/lib.h +++ b/kc/api/lib.h @@ -7,4 +7,8 @@ void *memmove(void *dest, const void *src, size_t size); void *memset(void *dest, int val, size_t size); int memcmp(const void *str1, const void *str2, size_t count); size_t strlen(const char *s); +unsigned long long strtoull( + const char *restrict begin, + char **restrict end, + int base); diff --git a/kc/core/Makefile b/kc/core/Makefile index 9b8983a..2c7303e 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -14,7 +14,7 @@ GOBJS := entry_x86_64.o reloc_x86_64.o kprint.o serial.o port.o mmu.o \ kc_main.o memory.o memset.o memcpy.o memmove.o memcmp.o cpu.o \ vm_tree.o exceptions.o panic.o msr.o task.o cpu_task.o irq.o \ kcc_memory.o string.o pic8259.o pic8259_isr.o pit8253.o \ - page_early.o page_stack.o + page_early.o page_stack.o strtoull.o IOBJS := # __attribute__((interrupt)) requires -mgeneral-regs-only diff --git a/kc/core/kprint.c b/kc/core/kprint.c index 762f99f..4acbddd 100644 --- a/kc/core/kprint.c +++ b/kc/core/kprint.c @@ -82,7 +82,6 @@ struct specifier static struct specifier parse_specifier(const char *format, va_list *arguments) { - (void)arguments; struct specifier result = { INVALID_PRINT, @@ -150,6 +149,76 @@ static struct specifier parse_specifier(const char *format, va_list *arguments) * b. if is numeric character, parse field precision via strtoul, add * length of numeric string to begin. */ + bool field_width_parsed = false; + bool field_precision_parsed = false; + + while (!field_width_parsed || !field_precision_parsed) + { + switch (*begin) + { + case '.': + if (!field_width_parsed) + { + result.field_width = 0; + field_width_parsed = true; + begin++; + } + else + { + // the specifier is invalid! + result.type = INVALID_PRINT; + } + break; + case '*': + { + int w = *va_arg(*arguments, int *); + if (!field_width_parsed) + { + result.field_width = w; + field_width_parsed = true; + } + else + { + result.field_precision = w; + field_precision_parsed = true; + } + begin++; + } + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '0': + { + char *next; + unsigned long long w = strtoull(begin, &next, 10); + if (!field_width_parsed) + { + result.field_width = (int)w; + field_width_parsed = true; + } + else if (!field_precision_parsed) + { + result.field_precision = (int)w; + field_precision_parsed = true; + } + if (next > begin) + { + begin = next; + } + } + break; + default: + field_width_parsed = true; + field_precision_parsed = true; + } + } // step 3: check for type width arguments switch (*begin) @@ -245,7 +314,7 @@ static struct specifier parse_specifier(const char *format, va_list *arguments) // TODO: use UINTPTR_T_WIDTH here? // pointer type overrides all flags // i can do what i want it says "implementation-defined" in the spec - result.field_precision = 8; + result.field_precision = 16; result.type = INTEGER_PRINT; result.integer_base = HEX_BASE; result.integer_width = LONG_WIDTH; @@ -277,8 +346,9 @@ static struct specifier parse_specifier(const char *format, va_list *arguments) static char *convert_integer( uint64_t value, - unsigned base, - char *buffer, + unsigned base, + int zpadding, + char *buffer, size_t bufsz) { static const char *stringdigits = "0123456789abcdef"; @@ -304,10 +374,16 @@ static char *convert_integer( do { *--result = stringdigits[value % base]; + zpadding--; value /= base; } while (value > 0 && result >= buffer); + while (zpadding-- > 0 && result >= buffer) + { + *--result = '0'; + } + return result; } @@ -361,6 +437,7 @@ static int print_integer( bool negative = false; uint64_t value = 0; int r = 0; + unsigned zpad = 0; switch (spec->integer_width) { @@ -429,7 +506,11 @@ static int print_integer( break; } - s = convert_integer(value, spec->integer_base, buffer, sizeof(buffer)); + if (spec->flags & ZERO_PAD_FLAG) + { + zpad = spec->field_precision; + } + s = convert_integer(value, spec->integer_base, zpad, buffer, sizeof(buffer)); if (s) { diff --git a/lib/strtoull.c b/lib/strtoull.c new file mode 100644 index 0000000..bb71c24 --- /dev/null +++ b/lib/strtoull.c @@ -0,0 +1,148 @@ +#include <stdbool.h> + +static long long valueof(int c, int base) +{ + long long result = 0; + + if (base < 2 || base > 36) + { + // bases less than 2 or greater than 36 are invalid. + return -1; + } + + // check if value is an ascii numeric character + if (c >= '0' && c <= '9') + { + // simple as + result = (long long)(c ^ 0x30); + } + + // check if value is an uppercase ASCII alphabetical character + else if ( + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z')) + { + // mask in uppercase bit + c |= 0x20; + // value is 10 plus the alphabetical order of the character + result = (long long)(10 + c - 'a'); + } + else + { + // character has no valid interpretation under base 36 + return -1LL; + } + + if (result > (base - 1)) + { + // character is not valid under given base + return -1LL; + } + + return result; +} + +unsigned long long strtoull( + const char *restrict begin, + char **restrict end, + int base) +{ + long result = 0; + const char *current = begin; + + // check for empty string + if (*current == 0) + { + if (end) + { + *end = (char *)begin; + return result; + } + } + + // skip initial whitespace + bool whitespace = true; + while (whitespace) + { + switch (*current) + { + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0x20: + current++; + break; + default: + whitespace = false; + } + } + + bool negative = false; + // detect if negative sign is used + if (*current == '-') + { + negative = true; + current++; + } + + // detect base from input + if (base == 0) + { + // base is non-decimal + if (current[0] == 0) + { + if (current[1] == 'b') + { + base = 2; + current += 2; + } + else if (current[1] == 'x') + { + base = 16; + current += 2; + } + else + { + base = 8; + current++; + } + } + // base is decimal otherwise + else + { + base = 10; + } + } + // do the actual conversion now + while (*current) + { + long long value = valueof(*current, base); + + // we've reached the end of the conversion + if (value == -1) + { + break; + } + + result *= base; + result += value; + current++; + } + + // store the end pointer if needed + if (end) + { + *end = (char *)current; + } + + // flip the result if we're meant to + if (negative) + { + result = -result; + } + + return result; +} + |
