diff --git a/include/brados/string.h b/include/brados/string.h index 4c1e6c0..7d33d5d 100644 --- a/include/brados/string.h +++ b/include/brados/string.h @@ -3,7 +3,6 @@ #include -int strindexof(char c, const char *str); size_t strlen(const char *str); #endif diff --git a/kernel/brados.c b/kernel/brados.c index 898583f..dfdb6ee 100644 --- a/kernel/brados.c +++ b/kernel/brados.c @@ -40,11 +40,11 @@ void brados_main(uint32_t multiMagic, uint32_t multiAddr) uint64_t lastAddr = 0; for (int i = 0; i < numEntries; i++) { if (memmap[i].base_addr != lastAddr) { - printk(&term, "%llx - %llx: Unknown\n", lastAddr, memmap[i].base_addr - 1); + printk(&term, "%#llx - %#llx: Unknown\n", lastAddr, memmap[i].base_addr - 1); lastAddr = memmap[i].base_addr; } - printk(&term, "%llx - %llx: ", memmap[i].base_addr, memmap[i].base_addr + memmap[i].length - 1); + printk(&term, "%#llx - %#llx: ", memmap[i].base_addr, memmap[i].base_addr + memmap[i].length - 1); if (memmap[i].type == 1) printk(&term, "Available\n"); else @@ -55,5 +55,5 @@ void brados_main(uint32_t multiMagic, uint32_t multiAddr) // Done - term_writeStr(&term, "\nDone."); + printk(&term, "\nDone."); } diff --git a/kernel/printk.c b/kernel/printk.c index 1d51780..4403df4 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -9,7 +10,7 @@ const char *BASE16 = "0123456789ABCDEF"; const char *BASE16L = "0123456789abcdef"; // Print an unsigned number as a string; return the number of characters printed -static int printNum(struct vgastate *term, unsigned long long num, unsigned int base, const char *digits) +static int printNum(struct vgastate *term, uintmax_t num, unsigned int base, const char *digits) { if (base > strlen(digits)) return 0; @@ -23,6 +24,18 @@ static int printNum(struct vgastate *term, unsigned long long num, unsigned int return numPrinted; } +// Determines the printed length of a number +static unsigned int numLen(uintmax_t num, unsigned int base) +{ + unsigned int len = 1; + while (num >= base) { + len++; + num /= base; + } + + return len; +} + // Print a formatted string to the given terminal int printk(struct vgastate *term, const char *fmt, ...) { @@ -30,189 +43,551 @@ int printk(struct vgastate *term, const char *fmt, ...) va_list args; va_start(args, fmt); - size_t i = 0; - while (i < strlen(fmt)) { - if (fmt[i] == '%') { - i++; - int end = 0, lng = 0; + // The bits of 'mode' explained: + // 0: Whether we are printing characters normally or parsing the format + // 1: Whether we are still parsing flags + // 2: Whether we are looking at width or precision (have we seen a .) + // 3: + flag + // 4: space flag + // 5: - flag + // 6: # flag + // 7: 0 flag + uint8_t mode = 0; + int length = 0; + unsigned int width = 0, precision = 0; + + for (size_t i = 0; i < strlen(fmt); i++) { + if (mode % 2 == 0) { + // Begin parsing format if we reach a '%' + if (fmt[i] == '%') { + mode |= 0x01; + // Or just print the character if we're not parsing + } else { + term_putChar(term, fmt[i]); + numPrinted++; + } - while (end == 0) { - switch (fmt[i]) { - // Print a percent sign - case '%': - term_putChar(term, '%'); - numPrinted++; - end = 1; + continue; + } + + switch (fmt[i]) { + case '%': + // Print a percent sign + term_putChar(term, '%'); + numPrinted++; + mode = 0; + break; + case '+': + // Set the plus flag + if ((mode >> 1) % 2 == 0) + mode |= 0x08; + + break; + case ' ': + // Set the space flag + if ((mode >> 1) % 2 == 0) + mode |= 0x10; + + break; + case '-': + // Set the left-align flag + if ((mode >> 1) % 2 == 0) + mode |= 0x20; + + break; + case '#': + // Set the alternate flag + if ((mode >> 1) % 2 == 0) + mode |= 0x40; + + break; + case '0': + // Set the zero-pad flag + if ((mode >> 1) % 2 == 0) + mode |= 0x80; + // Next digit in width specifier + else if ((mode >> 2) % 2 == 0) + width *= 10; + // Next digit in precision specifier + else + precision *= 10; + + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + // Next digit in width specifier + if ((mode >> 2) % 2 == 0) { + mode |= 0x02; + width *= 10; + width += (fmt[i] - 48); // 0 = ascii 48 + // Next digit in precision specifier + } else { + precision *= 10; + precision += (fmt[i] - 48); + } + + break; + case '.': + // Delimit width and precision + if ((mode >> 2) % 2 == 0) + mode |= 0x06; + + break; + case 'h': + // Denotes a short or char argument + mode |= 0x06; + length--; + break; + case 'l': + // Denotes a long or long long argument + mode |= 0x06; + length++; + break; + case 'z': + // Denotes a size_t argument + mode |= 0x06; + length = 3; + break; + case 'j': + // Denotes a intmax_t argument + mode |= 0x06; + length = 4; + break; + case 't': + // Denotes a ptrdiff_t argument + mode |= 0x06; + length = 5; + break; + case 'd': + // Print a signed integer + case 'i': { + intmax_t num; + uintmax_t unum; + + // Pull the argument from the list + switch (length) { + case 1: + num = va_arg(args, long); break; - // Print a single character - case 'c': - term_putChar(term, (char) va_arg(args, int)); - numPrinted++; - end = 1; + case 2: + num = va_arg(args, long long); break; - // Print an integer number - case 'd': - case 'i': - switch (lng) { - case 0: { - int d; - d = va_arg(args, int); - if (d < 0) { - term_putChar(term, '-'); - numPrinted++; - d *= -1; - } - numPrinted += printNum(term, (unsigned int) d, 10, BASE16); - break; - } case 1: { - long ld; - ld = va_arg(args, long); - if (ld < 0) { - term_putChar(term, '-'); - numPrinted++; - ld *= -1; - } - numPrinted += printNum(term, (unsigned long) ld, 10, BASE16); - break; - } default: { - long long lld; - lld = va_arg(args, long long); - if (lld < 0) { - term_putChar(term, '-'); - numPrinted++; - lld *= -1; - } - numPrinted += printNum(term, (unsigned long long) lld, 10, BASE16); - break; - }} - end = 1; + case 3: + num = va_arg(args, size_t); break; - // Expect a long (long) value - case 'l': - lng++; + case 4: + num = va_arg(args, intmax_t); break; - // Store the number of printed characters - case 'n': { - int *n; - n = va_arg(args, int *); - *n = numPrinted; - end = 1; + case 5: + num = va_arg(args, ptrdiff_t); break; - // Print an unsigned integer in octal form - } case 'o': + default: + num = va_arg(args, int); + break; + } + + // Get unsigned version + if (num < 0) + unum = num * -1; + else + unum = num; + + // Get the length of the printed number + unsigned int len = numLen(unum, 10); + + // Get the length of the printed number with formatting + unsigned int flen = len; + if (precision > len) + flen += (precision - len); + if (num < 0) + flen++; + if (num >= 0 && ((mode >> 3) % 2 == 1 || (mode >> 4) % 2 == 1)) + flen++; + + // If specified, print preceding space padding + if ((mode >> 5) % 2 == 0) { + if (precision > 0 || (mode >> 7) % 2 == 0) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + } + + // If specified print the sign + if (num < 0) { + term_putChar(term, '-'); + numPrinted++; + } else if ((mode >> 3) % 2 == 1) { + term_putChar(term, '+'); + numPrinted++; + } else if ((mode >> 4) % 2 == 1) { + term_putChar(term, ' '); + numPrinted++; + } + + // If specified, print the precision 0s + if (precision > 0) { + for (int j = precision - len; j > 0; j--) { + term_putChar(term, '0'); + numPrinted++; + } + } else if ((mode >> 7) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { term_putChar(term, '0'); numPrinted++; - switch (lng) { - case 0: { - unsigned int o; - o = va_arg(args, unsigned int); - numPrinted += printNum(term, o, 8, BASE16); - break; - } case 1: { - unsigned long lo; - lo = va_arg(args, unsigned long); - numPrinted += printNum(term, lo, 8, BASE16); - break; - } default: { - unsigned long long llo; - llo = va_arg(args, unsigned long long); - numPrinted += printNum(term, llo, 8, BASE16); - break; - }} - end = 1; - break; - // Print a null-terminated string - case 's': { - char *s; - s = va_arg(args, char *); - term_writeStr(term, s); - numPrinted += strlen(s); - end = 1; - break; - // Print an unsigned integer value - } case 'u': - switch (lng) { - case 0: { - unsigned int u; - u = va_arg(args, unsigned int); - numPrinted += printNum(term, u, 10, BASE16); - break; - } case 1: { - unsigned long lu; - lu = va_arg(args, unsigned long); - numPrinted += printNum(term, lu, 10, BASE16); - break; - } default: { - unsigned long long llu; - llu = va_arg(args, unsigned long long); - numPrinted += printNum(term, llu, 10, BASE16); - break; - }} - end = 1; - break; - // Print an unsigned integer in lower hex form - case 'x': - term_writeStr(term, "0x"); - numPrinted += 2; - switch (lng) { - case 0: { - unsigned int x; - x = va_arg(args, unsigned int); - numPrinted += printNum(term, x, 16, BASE16L); - break; - } case 1: { - unsigned long lx; - lx = va_arg(args, unsigned long); - numPrinted += printNum(term, lx, 16, BASE16L); - break; - } default: { - unsigned long long llx; - llx = va_arg(args, unsigned long long); - numPrinted += printNum(term, llx, 16, BASE16L); - break; - }} - end = 1; - break; - // Print an unsigned integer in upper hex form - case 'X': - term_writeStr(term, "0X"); - numPrinted += 2; - switch (lng) { - case 0: { - unsigned int x; - x = va_arg(args, unsigned int); - numPrinted += printNum(term, x, 16, BASE16); - break; - } case 1: { - unsigned long lx; - lx = va_arg(args, unsigned long); - numPrinted += printNum(term, lx, 16, BASE16); - break; - } default: { - unsigned long long llx; - llx = va_arg(args, unsigned long long); - numPrinted += printNum(term, llx, 16, BASE16); - break; - }} - end = 1; - break; - // Exit if we reach the end of the string - case '\0': - end = 1; - break; - // Unknown character; just print the character - default: - term_putChar(term, fmt[i]); - numPrinted++; - end = 1; - break; } - i++; } - } else { + + // Print the number + numPrinted += printNum(term, unum, 10, BASE16); + + // If specified, print succeeding spaces + if ((mode >> 5) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + + mode = 0; + break; + // Print an unsigned integer + } case 'u': { + uintmax_t num; + + // Pull the argument from the list + switch (length) { + case 1: + num = va_arg(args, unsigned long); + break; + case 2: + num = va_arg(args, unsigned long long); + break; + case 3: + num = va_arg(args, size_t); + break; + case 4: + num = va_arg(args, intmax_t); + break; + case 5: + num = va_arg(args, ptrdiff_t); + break; + default: + num = va_arg(args, unsigned int); + break; + } + + // Get the length of the printed number + unsigned int len = numLen(num, 10); + + // Get the length of the printed number with formatting + unsigned int flen = len; + if (precision > len) + flen += (precision - len); + if ((mode >> 3) % 2 == 1 || (mode >> 4) % 2 == 1) + flen++; + + // If specified, print preceding space padding + if ((mode >> 5) % 2 == 0) { + if (precision > 0 || (mode >> 7) % 2 == 0) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + } + + // If specified print the sign + if ((mode >> 3) % 2 == 1) { + term_putChar(term, '+'); + numPrinted++; + } else if ((mode >> 4) % 2 == 1) { + term_putChar(term, ' '); + numPrinted++; + } + + // If specified, print the precision 0s + if (precision > 0) { + for (int j = precision - len; j > 0; j--) { + term_putChar(term, '0'); + numPrinted++; + } + } else if ((mode >> 7) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, '0'); + numPrinted++; + } + } + + // Print the number + numPrinted += printNum(term, num, 10, BASE16); + + // If specified, print succeeding spaces + if ((mode >> 5) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + + mode = 0; + break; + // Print an unsigned integer in hexadecimal + } case 'x': + case 'X': { + uintmax_t num; + + // Pull the argument from the list + switch (length) { + case 1: + num = va_arg(args, unsigned long); + break; + case 2: + num = va_arg(args, unsigned long long); + break; + case 3: + num = va_arg(args, size_t); + break; + case 4: + num = va_arg(args, intmax_t); + break; + case 5: + num = va_arg(args, ptrdiff_t); + break; + default: + num = va_arg(args, unsigned int); + break; + } + + // Get the length of the printed number + unsigned int len = numLen(num, 10); + + // Get the length of the printed number with formatting + unsigned int flen = len; + if (precision > len) + flen += (precision - len); + if ((mode >> 3) % 2 == 1 || (mode >> 4) % 2 == 1) + flen++; + if ((mode >> 6) % 2 == 1) + flen += 2; + + // If specified, print preceding space padding + if ((mode >> 5) % 2 == 0) { + if (precision > 0 || (mode >> 7) % 2 == 0) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + } + + // If specified print the sign + if ((mode >> 3) % 2 == 1) { + term_putChar(term, '+'); + numPrinted++; + } else if ((mode >> 4) % 2 == 1) { + term_putChar(term, ' '); + numPrinted++; + } + + // If specified, print the 0x + if ((mode >> 6) % 2 == 1) { + term_putChar(term, '0'); + if (fmt[i] == 'x') + term_putChar(term, 'x'); + else + term_putChar(term, 'X'); + numPrinted += 2; + } + + // If specified, print the precision 0s + if (precision > 0) { + for (int j = precision - len; j > 0; j--) { + term_putChar(term, '0'); + numPrinted++; + } + } else if ((mode >> 7) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, '0'); + numPrinted++; + } + } + + // Print the number + if (fmt[i] == 'x') + numPrinted += printNum(term, num, 16, BASE16L); + else + numPrinted += printNum(term, num, 16, BASE16); + + // If specified, print succeeding spaces + if ((mode >> 5) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + + mode = 0; + break; + // Print an unsigned integer in octal + } case 'o': { + uintmax_t num; + + // Pull the argument from the list + switch (length) { + case 1: + num = va_arg(args, unsigned long); + break; + case 2: + num = va_arg(args, unsigned long long); + break; + case 3: + num = va_arg(args, size_t); + break; + case 4: + num = va_arg(args, intmax_t); + break; + case 5: + num = va_arg(args, ptrdiff_t); + break; + default: + num = va_arg(args, unsigned int); + break; + } + + // Get the length of the printed number + unsigned int len = numLen(num, 10); + + // Get the length of the printed number with formatting + unsigned int flen = len; + if (precision > len) + flen += (precision - len); + if ((mode >> 3) % 2 == 1 || (mode >> 4) % 2 == 1) + flen++; + if ((mode >> 6) % 2 == 1) + flen++; + + // If specified, print preceding space padding + if ((mode >> 5) % 2 == 0) { + if (precision > 0 || (mode >> 7) % 2 == 0) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + } + + // If specified print the sign + if ((mode >> 3) % 2 == 1) { + term_putChar(term, '+'); + numPrinted++; + } else if ((mode >> 4) % 2 == 1) { + term_putChar(term, ' '); + numPrinted++; + } + + // If specified, print the 0x + if ((mode >> 6) % 2 == 1) { + term_putChar(term, '0'); + numPrinted++; + } + + // If specified, print the precision 0s + if (precision > 0) { + for (int j = precision - len; j > 0; j--) { + term_putChar(term, '0'); + numPrinted++; + } + } else if ((mode >> 7) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, '0'); + numPrinted++; + } + } + + // Print the number + numPrinted += printNum(term, num, 8, BASE16); + + // If specified, print succeeding spaces + if ((mode >> 5) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + + mode = 0; + break; + // Print a string + } case 's': { + char *s = va_arg(args, char *); + term_writeStr(term, s); + numPrinted += strlen(s); + mode = 0; + break; + // Print a character + } case 'c': + if (mode % 2 == 0) + term_putChar(term, 'c'); + else + term_putChar(term, (char) va_arg(args, int)); + + numPrinted++; + mode = 0; + break; + // Print a pointer + case 'p': { + uintmax_t num = va_arg(args, void *); + + // Get the length of the printed number + unsigned int len = numLen(num, 16); + unsigned int flen = len + 2; + precision = sizeof(void *) * 2; // A byte is 2 hex chars + + // If specified, print preceding space padding + if ((mode >> 5) % 2 == 0) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + + term_putChar(term, '0'); + term_putChar(term, 'x'); + numPrinted += 2; + + // If specified, print the precision 0s + for (int j = precision - len; j > 0; j--) { + term_putChar(term, '0'); + numPrinted++; + } + + // Print the number + numPrinted += printNum(term, num, 16, BASE16); + + // If specified, print succeeding spaces + if ((mode >> 5) % 2 == 1) { + for (int j = width - flen; j > 0; j--) { + term_putChar(term, ' '); + numPrinted++; + } + } + + mode = 0; + break; + } default: term_putChar(term, fmt[i]); numPrinted++; - i++; + mode = 0; + break; } } diff --git a/lib/string.c b/lib/string.c index 8287a2b..6bee2d4 100644 --- a/lib/string.c +++ b/lib/string.c @@ -2,18 +2,6 @@ #include -// Find the first instance of c in str -// Returns -1 if c is not found -int strindexof(char c, const char *str) -{ - for (size_t i = 0; i < strlen(str); i++) { - if (str[i] == c) - return i; - } - - return -1; -} - // Find the length of a string size_t strlen(const char *str) {