mirror of
https://git.stationery.faith/corn/corn.git
synced 2024-11-10 02:42:08 +00:00
rework kprintf
This commit is contained in:
parent
ac431b0050
commit
f785bce3cc
3 changed files with 439 additions and 285 deletions
|
@ -633,7 +633,6 @@ int kload_page(void *virt_addr) {
|
||||||
if (page->loaded)
|
if (page->loaded)
|
||||||
return -1;
|
return -1;
|
||||||
void *phys = alloc_phys_page();
|
void *phys = alloc_phys_page();
|
||||||
kprintf("0x%p\n", phys);
|
|
||||||
if (phys == NULL)
|
if (phys == NULL)
|
||||||
return -2;
|
return -2;
|
||||||
page->loaded = 1;
|
page->loaded = 1;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <backtrace.h>
|
||||||
#include <fpu.h>
|
#include <fpu.h>
|
||||||
#include <acpi.h>
|
#include <acpi.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
@ -18,6 +19,8 @@ void kmain(struct boot_info *info) {
|
||||||
char *test = kalloc(5);
|
char *test = kalloc(5);
|
||||||
*test = 1;
|
*test = 1;
|
||||||
|
|
||||||
|
//log_backtrace();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
screen_redraw();
|
screen_redraw();
|
||||||
// loop so we dont halt
|
// loop so we dont halt
|
||||||
|
|
720
src/print.c
720
src/print.c
|
@ -1,6 +1,7 @@
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
#include <serial.h>
|
#include <serial.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
void kputc(char c) {
|
void kputc(char c) {
|
||||||
serial_out(c);
|
serial_out(c);
|
||||||
|
@ -31,54 +32,110 @@ struct format_precision {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum format_modifier {
|
enum format_modifier {
|
||||||
MOD_NONE,
|
MOD_NONE = 0,
|
||||||
MOD_INVALID,
|
MOD_HALF = 1,
|
||||||
MOD_HALF_HALF,
|
MOD_HALF_HALF = 3,
|
||||||
MOD_HALF,
|
MOD_LONG = 3,
|
||||||
MOD_LONG_LONG,
|
MOD_LONG_LONG = 4,
|
||||||
MOD_LONG,
|
MOD_INVALID = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum format_conversion {
|
enum format_conversion {
|
||||||
FMT_INT,
|
// decimal numbers
|
||||||
FMT_UINT,
|
FMT_CHAR = 0,
|
||||||
|
FMT_INT = 4,
|
||||||
|
FMT_UINT = 5,
|
||||||
|
// otehr numbers
|
||||||
FMT_OCT,
|
FMT_OCT,
|
||||||
FMT_HEX,
|
FMT_HEX,
|
||||||
FMT_HEX_UPPER,
|
FMT_HEX_UPPER,
|
||||||
FMT_CHAR,
|
// text
|
||||||
FMT_STR,
|
FMT_STR,
|
||||||
FMT_PTR,
|
FMT_PTR,
|
||||||
FMT_PTR_UPPER,
|
// misc
|
||||||
FMT_PERCENT,
|
|
||||||
FMT_INVALID
|
FMT_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum format_flag read_flag(const char *format, const char **end) {
|
enum format_length {
|
||||||
|
LEN_UCHAR,
|
||||||
|
LEN_CHAR,
|
||||||
|
LEN_USHORT,
|
||||||
|
LEN_SHORT,
|
||||||
|
LEN_UINT,
|
||||||
|
LEN_INT,
|
||||||
|
LEN_ULONG,
|
||||||
|
LEN_LONG,
|
||||||
|
LEN_ULONGLONG,
|
||||||
|
LEN_LONGLONG,
|
||||||
|
LEN_SIZET,
|
||||||
|
LEN_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
enum format_flag flag = FLG_NONE;
|
struct spacing {
|
||||||
|
unsigned left;
|
||||||
|
unsigned length;
|
||||||
|
unsigned right;
|
||||||
|
bool zero;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum charcase {
|
||||||
|
UPPERCASE,
|
||||||
|
LOWERCASE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum printtype {
|
||||||
|
NONE,
|
||||||
|
OCTAL,
|
||||||
|
HEX
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum printtype conversion_to_printtype(enum format_conversion conversion) {
|
||||||
|
switch (conversion) {
|
||||||
|
case FMT_OCT:
|
||||||
|
return OCTAL;
|
||||||
|
case FMT_HEX:
|
||||||
|
case FMT_HEX_UPPER:
|
||||||
|
return HEX;
|
||||||
|
default:
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum charcase conversion_to_charcase(enum format_conversion conversion) {
|
||||||
|
switch (conversion) {
|
||||||
|
case FMT_HEX_UPPER:
|
||||||
|
return UPPERCASE;
|
||||||
|
default:
|
||||||
|
return LOWERCASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum format_flag read_flags(const char *format, const char **end) {
|
||||||
|
|
||||||
|
enum format_flag flags = FLG_NONE;
|
||||||
|
|
||||||
for (; *format != '\0'; format++) {
|
for (; *format != '\0'; format++) {
|
||||||
switch (*format) {
|
switch (*format) {
|
||||||
case '#':
|
case '#':
|
||||||
flag |= FLG_ALTERNATE;
|
flags |= FLG_ALTERNATE;
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
flag |= FLG_ZERO;
|
flags |= FLG_ZERO;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
flag |= FLG_LEFT_ALIGN;
|
flags |= FLG_LEFT_ALIGN;
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
flag |= FLG_ADD_SIGN;
|
flags |= FLG_ADD_SIGN;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*end = format;
|
*end = format;
|
||||||
return flag;
|
return flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*end = format;
|
*end = format;
|
||||||
return flag;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct format_width read_width(const char *format, const char **end) {
|
static struct format_width read_width(const char *format, const char **end) {
|
||||||
|
@ -221,213 +278,344 @@ static enum format_conversion read_conversion(const char *format, const char **e
|
||||||
return FMT_STR;
|
return FMT_STR;
|
||||||
case 'p':
|
case 'p':
|
||||||
return FMT_PTR;
|
return FMT_PTR;
|
||||||
case 'P':
|
|
||||||
return FMT_PTR_UPPER;
|
|
||||||
case '%':
|
|
||||||
return FMT_PERCENT;
|
|
||||||
default:
|
default:
|
||||||
return FMT_INVALID;
|
return FMT_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_string(
|
static char ctoa_print(
|
||||||
const char *str,
|
char c, // the single digit to convert to ascii
|
||||||
enum format_flag flag,
|
enum charcase cc // if this digit should be uppercase or lowercase
|
||||||
struct format_width width,
|
|
||||||
struct format_precision precision
|
|
||||||
) {
|
|
||||||
|
|
||||||
size_t max_len = 0;
|
|
||||||
size_t min_len = 0;
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
if (width.defined)
|
|
||||||
min_len = width.value;
|
|
||||||
|
|
||||||
if (precision.defined) {
|
|
||||||
max_len = precision.value;
|
|
||||||
len = max_len;
|
|
||||||
if (max_len < min_len)
|
|
||||||
min_len = max_len;
|
|
||||||
} else {
|
|
||||||
len = strlen(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(flag & FLG_LEFT_ALIGN) && len < min_len) {
|
|
||||||
for (size_t i = 0; i < (min_len - len); i++) {
|
|
||||||
kputc(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
kputc(str[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flag & FLG_LEFT_ALIGN) && len < min_len) {
|
|
||||||
for (size_t i = 0; i < (min_len - len); i++) {
|
|
||||||
kputc(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static char get_letter(
|
|
||||||
char c,
|
|
||||||
char base
|
|
||||||
) {
|
) {
|
||||||
|
char ascii_base = cc == UPPERCASE ? 'A' : 'a';
|
||||||
if (c >= 0 && c <= 9)
|
if (c >= 0 && c <= 9)
|
||||||
return c + '0';
|
return c + '0';
|
||||||
c -= 10;
|
c -= 10;
|
||||||
return c + base;
|
return c + ascii_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *get_decimal(
|
static char *ulltoa_print(
|
||||||
long long num,
|
unsigned long long num, // the number to convert to ascii
|
||||||
char *buf,
|
unsigned radix, // the divisor for the number (base 10, octal, hex)
|
||||||
char sign,
|
char *buf, // the buffer to write to
|
||||||
int radix,
|
enum charcase cc, // if any a-z ascii should be uppercase or lowercase
|
||||||
char base
|
bool addsign // add a sign even if its positive
|
||||||
) {
|
) {
|
||||||
|
// we are printing the string backwards, add null byte
|
||||||
*buf = '\0';
|
*buf = '\0';
|
||||||
buf--;
|
buf--;
|
||||||
|
|
||||||
|
// if the number is zero, the while loop will never run
|
||||||
|
// so we have to add the zero digit ourselves
|
||||||
if (num == 0) {
|
if (num == 0) {
|
||||||
*buf = '0';
|
*buf = '0';
|
||||||
buf--;
|
buf--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for each digit, convert to ascii and add to buffer
|
||||||
while (num != 0) {
|
while (num != 0) {
|
||||||
char i = num % radix;
|
char i = num % radix;
|
||||||
char c = get_letter(i, base);
|
char c = ctoa_print(i, cc);
|
||||||
*buf = c;
|
*buf = c;
|
||||||
buf--;
|
buf--;
|
||||||
num /= radix;
|
num /= radix;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sign) {
|
// since this is the unsigned function, add a plus sign if
|
||||||
*buf = sign;
|
// requested
|
||||||
|
if (addsign) {
|
||||||
|
*buf = '+';
|
||||||
buf--;
|
buf--;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf++;
|
buf++; // move forward one to be at the start of the string
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_unum(
|
static char *lltoa_print(
|
||||||
unsigned long long num,
|
signed long long num, // the number to convert to ascii
|
||||||
enum format_flag flag,
|
unsigned radix, // the divistor for the number (base 10, octal, hex)
|
||||||
struct format_width width,
|
char *buf, // the buffer to write to
|
||||||
struct format_precision precision,
|
enum charcase cc, // if any a-z ascii should be uppercase or lowercase
|
||||||
bool isneg,
|
bool addsign // add a sign even if its positive
|
||||||
int radix,
|
|
||||||
char base
|
|
||||||
) {
|
) {
|
||||||
|
bool isneg = num < 0;
|
||||||
|
|
||||||
size_t max_len = 0;
|
|
||||||
size_t min_len = 0;
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
char sign = 0;
|
|
||||||
if (isneg)
|
if (isneg)
|
||||||
sign = '-';
|
num = -num;
|
||||||
else if (flag & FLG_ADD_SIGN)
|
|
||||||
sign = '+';
|
|
||||||
|
|
||||||
char buf[1024];
|
buf = ulltoa_print(num, radix, buf, cc, !isneg && addsign);
|
||||||
char *str = get_decimal(
|
|
||||||
num,
|
|
||||||
buf + 1023,
|
|
||||||
sign,
|
|
||||||
radix,
|
|
||||||
base
|
|
||||||
);
|
|
||||||
|
|
||||||
bool space_pre = (flag & FLG_LEFT_ALIGN) || !(flag & FLG_ZERO);
|
if (isneg && num < 0) {
|
||||||
|
buf--;
|
||||||
if (!space_pre && radix == 16 && (flag & FLG_ALTERNATE)) {
|
*buf = '-';
|
||||||
char x = base + ('x' - 'a');
|
|
||||||
serial_out('0');
|
|
||||||
serial_out(x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width.defined)
|
return buf;
|
||||||
min_len = width.value;
|
}
|
||||||
|
|
||||||
if (precision.defined) {
|
|
||||||
max_len = precision.value;
|
static void print_string_buffer(
|
||||||
len = max_len;
|
const char *buf, // buffer containing the text we want to print
|
||||||
if (max_len < min_len)
|
struct spacing spacing // the spacing on the left right and middle
|
||||||
min_len = max_len;
|
) {
|
||||||
} else {
|
for (unsigned i = 0; i < spacing.left; i++) {
|
||||||
len = strlen(str);
|
kputc(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
bool zero_padded = false;
|
for (unsigned i = 0; i < spacing.length; i++) {
|
||||||
|
kputc(*buf++);
|
||||||
if (!(flag & FLG_LEFT_ALIGN) && len < min_len) {
|
|
||||||
for (size_t i = 0; i < (min_len - len); i++) {
|
|
||||||
(flag & FLG_ZERO) ? kputc('0') : kputc(' ');
|
|
||||||
}
|
|
||||||
if (flag & FLG_ZERO)
|
|
||||||
zero_padded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (space_pre && radix == 16 && (flag & FLG_ALTERNATE)) {
|
for (unsigned i = 0; i < spacing.right; i++) {
|
||||||
char x = base + ('x' - 'a');
|
kputc(' ');
|
||||||
serial_out('0');
|
|
||||||
serial_out(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (space_pre && radix == 16 && flag & FLG_ALTERNATE) {
|
|
||||||
char x = base + ('x' - 'a');
|
|
||||||
serial_out('0');
|
|
||||||
serial_out(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
kputs(str);
|
|
||||||
|
|
||||||
if (!zero_padded && (flag & FLG_ALTERNATE) && radix == 8)
|
|
||||||
kputc('0');
|
|
||||||
|
|
||||||
if ((flag & FLG_LEFT_ALIGN) && len < min_len) {
|
|
||||||
for (size_t i = 0; i < (min_len - len); i++) {
|
|
||||||
(flag & FLG_ZERO) ? kputc('0') : kputc(' ');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_num(
|
static void print_number_buffer(
|
||||||
long long num,
|
const char *buf, // buffer containing the text we want to print
|
||||||
enum format_flag flag,
|
struct spacing spacing, // the spacing on the left right and middle
|
||||||
struct format_width width,
|
enum printtype type,
|
||||||
struct format_precision precision,
|
enum charcase cc
|
||||||
int radix,
|
|
||||||
char base
|
|
||||||
) {
|
) {
|
||||||
bool isneg = false;
|
|
||||||
|
|
||||||
if (num < 0) {
|
// put the 0x at the start of the string
|
||||||
num = ~num;
|
if (spacing.left && spacing.zero && type == HEX) {
|
||||||
isneg = true;
|
if (cc == UPPERCASE) {
|
||||||
|
kputs("0X");
|
||||||
|
} else {
|
||||||
|
kputs("0x");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_unum(
|
if ((!spacing.left || !spacing.zero) && type == OCTAL) {
|
||||||
num,
|
kputc('0');
|
||||||
flag,
|
}
|
||||||
width,
|
|
||||||
precision,
|
for (unsigned i = 0; i < spacing.left; i++) {
|
||||||
isneg,
|
spacing.zero ? kputc('0') : kputc(' ');
|
||||||
radix,
|
}
|
||||||
base
|
|
||||||
);
|
if ((!spacing.left || !spacing.zero) && type == HEX) {
|
||||||
|
if (cc == UPPERCASE) {
|
||||||
|
kputs("0X");
|
||||||
|
} else {
|
||||||
|
kputs("0x");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < spacing.length; i++) {
|
||||||
|
kputc(*buf++);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < spacing.right; i++) {
|
||||||
|
kputc(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned get_string_len(
|
||||||
|
const char *str,
|
||||||
|
struct format_precision precision
|
||||||
|
) {
|
||||||
|
if (!precision.defined)
|
||||||
|
return strlen(str);
|
||||||
|
unsigned max = precision.value;
|
||||||
|
for (unsigned i = 0; i < max; i++) {
|
||||||
|
if (str[i] == '\0') {
|
||||||
|
// we broke early
|
||||||
|
// precision is greater then strlen
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct spacing get_spacing(
|
||||||
|
struct format_width width,
|
||||||
|
struct format_precision precision,
|
||||||
|
enum format_flag flags,
|
||||||
|
unsigned length
|
||||||
|
) {
|
||||||
|
struct spacing spacing;
|
||||||
|
|
||||||
|
unsigned min = 0,
|
||||||
|
max = 0;
|
||||||
|
|
||||||
|
if (width.defined) {
|
||||||
|
min = width.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (precision.defined) {
|
||||||
|
max = precision.value;
|
||||||
|
if (length > max) {
|
||||||
|
length = max;
|
||||||
|
}
|
||||||
|
if (min > max) {
|
||||||
|
min = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned gap = 0;
|
||||||
|
if (max > length) {
|
||||||
|
gap = max - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
spacing.length = length;
|
||||||
|
|
||||||
|
if (flags & FLG_LEFT_ALIGN) {
|
||||||
|
spacing.left = gap;
|
||||||
|
spacing.right = 0;
|
||||||
|
} else {
|
||||||
|
spacing.left = 0;
|
||||||
|
spacing.right = gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
spacing.zero = (flags & FLG_ZERO);
|
||||||
|
|
||||||
|
return spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct spacing get_string_spacing(
|
||||||
|
const char *str,
|
||||||
|
struct format_width width,
|
||||||
|
struct format_precision precision,
|
||||||
|
enum format_flag flags
|
||||||
|
) {
|
||||||
|
unsigned length = get_string_len(str, precision);
|
||||||
|
return get_spacing(width, precision, flags, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_string(
|
||||||
|
const char *str,
|
||||||
|
enum format_flag flags,
|
||||||
|
struct format_width width,
|
||||||
|
struct format_precision precision
|
||||||
|
) {
|
||||||
|
struct spacing spacing =
|
||||||
|
get_string_spacing(str, width, precision, flags);
|
||||||
|
print_string_buffer(str, spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum format_length apply_modifier(
|
||||||
|
enum format_conversion conversion,
|
||||||
|
enum format_modifier modifier
|
||||||
|
) {
|
||||||
|
switch (conversion) {
|
||||||
|
case FMT_CHAR:
|
||||||
|
if (modifier == MOD_NONE)
|
||||||
|
return LEN_CHAR;
|
||||||
|
else
|
||||||
|
return LEN_INVALID;
|
||||||
|
|
||||||
|
case FMT_PTR:
|
||||||
|
if (modifier == MOD_NONE)
|
||||||
|
return LEN_SIZET;
|
||||||
|
else
|
||||||
|
return LEN_INVALID;
|
||||||
|
|
||||||
|
case FMT_INT:
|
||||||
|
if (modifier == MOD_LONG)
|
||||||
|
return LEN_LONG;
|
||||||
|
else if (modifier == MOD_LONG_LONG)
|
||||||
|
return LEN_LONGLONG;
|
||||||
|
else if (modifier == MOD_HALF)
|
||||||
|
return LEN_SHORT;
|
||||||
|
else if (modifier == MOD_HALF_HALF)
|
||||||
|
return LEN_CHAR;
|
||||||
|
else
|
||||||
|
return LEN_INT;
|
||||||
|
|
||||||
|
case FMT_UINT:
|
||||||
|
case FMT_OCT:
|
||||||
|
case FMT_HEX:
|
||||||
|
case FMT_HEX_UPPER:
|
||||||
|
if (modifier == MOD_LONG)
|
||||||
|
return LEN_ULONG;
|
||||||
|
else if (modifier == MOD_LONG_LONG)
|
||||||
|
return LEN_ULONGLONG;
|
||||||
|
else if (modifier == MOD_HALF)
|
||||||
|
return LEN_USHORT;
|
||||||
|
else if (modifier == MOD_HALF_HALF)
|
||||||
|
return LEN_UCHAR;
|
||||||
|
else
|
||||||
|
return LEN_UINT;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return LEN_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned printtype_to_radix(
|
||||||
|
enum printtype type
|
||||||
|
) {
|
||||||
|
switch (type) {
|
||||||
|
case OCTAL:
|
||||||
|
return 8;
|
||||||
|
case HEX:
|
||||||
|
return 16;
|
||||||
|
case NONE:
|
||||||
|
default:
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_signed_number(
|
||||||
|
signed long long num,
|
||||||
|
enum format_flag flags,
|
||||||
|
struct format_width width,
|
||||||
|
struct format_precision precision,
|
||||||
|
enum printtype type,
|
||||||
|
enum charcase cc
|
||||||
|
) {
|
||||||
|
unsigned radix = printtype_to_radix(type);
|
||||||
|
char buf[256];
|
||||||
|
char *ptr = lltoa_print(num, radix, buf + 255, cc, flags & FLG_ADD_SIGN);
|
||||||
|
unsigned length = strlen(ptr);
|
||||||
|
struct spacing spacing =
|
||||||
|
get_spacing(width, precision, flags, length);
|
||||||
|
print_number_buffer(ptr, spacing, type, cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_unsigned_number(
|
||||||
|
unsigned long long num,
|
||||||
|
enum format_flag flags,
|
||||||
|
struct format_width width,
|
||||||
|
struct format_precision precision,
|
||||||
|
enum printtype type,
|
||||||
|
enum charcase cc
|
||||||
|
) {
|
||||||
|
unsigned radix = printtype_to_radix(type);
|
||||||
|
char buf[256];
|
||||||
|
char *ptr = ulltoa_print(num, radix, buf + 255, cc, flags & FLG_ADD_SIGN);
|
||||||
|
unsigned length = strlen(ptr);
|
||||||
|
struct spacing spacing =
|
||||||
|
get_spacing(width, precision, flags, length);
|
||||||
|
print_number_buffer(ptr, spacing, type, cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_conversion_number(enum format_conversion conversion) {
|
||||||
|
switch (conversion) {
|
||||||
|
case FMT_INT:
|
||||||
|
case FMT_UINT:
|
||||||
|
case FMT_OCT:
|
||||||
|
case FMT_HEX:
|
||||||
|
case FMT_HEX_UPPER:
|
||||||
|
case FMT_PTR:
|
||||||
|
return true;
|
||||||
|
case FMT_CHAR:
|
||||||
|
case FMT_STR:
|
||||||
|
case FMT_INVALID:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvprintf(const char *format, va_list args) {
|
void kvprintf(const char *format, va_list args) {
|
||||||
for (; *format != '\0'; format++) {
|
for (; *format != '\0'; format++) {
|
||||||
char c = *format;
|
char c = *format;
|
||||||
if (c == '%') {
|
if (c == '%') {
|
||||||
enum format_flag flag;
|
enum format_flag flags;
|
||||||
struct format_width width;
|
struct format_width width;
|
||||||
struct format_precision precision;
|
struct format_precision precision;
|
||||||
enum format_modifier modifier;
|
enum format_modifier modifier;
|
||||||
|
@ -435,34 +623,24 @@ void kvprintf(const char *format, va_list args) {
|
||||||
|
|
||||||
const char *ptr = format + 1;
|
const char *ptr = format + 1;
|
||||||
|
|
||||||
flag = read_flag(ptr, &ptr);
|
if (*(format + 1) == '%') {
|
||||||
|
kputc('%');
|
||||||
|
format++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = read_flags(ptr, &ptr);
|
||||||
width = read_width(ptr, &ptr);
|
width = read_width(ptr, &ptr);
|
||||||
precision = read_precision(ptr, &ptr);
|
precision = read_precision(ptr, &ptr);
|
||||||
|
|
||||||
modifier = read_modifier(ptr, &ptr);
|
modifier = read_modifier(ptr, &ptr);
|
||||||
|
|
||||||
if (modifier == MOD_INVALID) {
|
if (modifier == MOD_INVALID) {
|
||||||
kputc('%');
|
goto error;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conversion = read_conversion(ptr, &ptr);
|
conversion = read_conversion(ptr, &ptr);
|
||||||
|
|
||||||
if (conversion == FMT_INVALID) {
|
|
||||||
kputc('%');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
union {
|
|
||||||
unsigned long long u;
|
|
||||||
long long l;
|
|
||||||
char c;
|
|
||||||
const char *str;
|
|
||||||
void *ptr;
|
|
||||||
} data = {0};
|
|
||||||
|
|
||||||
int radix = 0;
|
|
||||||
char base = 0;
|
|
||||||
|
|
||||||
if (width.varys) {
|
if (width.varys) {
|
||||||
int len = va_arg(args, int);
|
int len = va_arg(args, int);
|
||||||
width.value = len;
|
width.value = len;
|
||||||
|
@ -473,106 +651,80 @@ void kvprintf(const char *format, va_list args) {
|
||||||
precision.value = len;
|
precision.value = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (conversion) {
|
if (conversion == FMT_INVALID) {
|
||||||
case FMT_INT:
|
goto error;
|
||||||
if (modifier == MOD_NONE)
|
|
||||||
data.l = va_arg(args, int);
|
|
||||||
else if (modifier == MOD_HALF)
|
|
||||||
data.l = (short) va_arg(args, int);
|
|
||||||
else if (modifier == MOD_HALF_HALF)
|
|
||||||
data.l = (char) va_arg(args, int);
|
|
||||||
else if (modifier == MOD_LONG)
|
|
||||||
data.l = va_arg(args, long);
|
|
||||||
else if (modifier == MOD_LONG_LONG)
|
|
||||||
data.l = va_arg(args, long long);
|
|
||||||
radix = 10;
|
|
||||||
print_num(
|
|
||||||
data.l,
|
|
||||||
flag,
|
|
||||||
width,
|
|
||||||
precision,
|
|
||||||
radix,
|
|
||||||
base
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case FMT_UINT:
|
|
||||||
case FMT_OCT:
|
|
||||||
case FMT_HEX_UPPER:
|
|
||||||
case FMT_HEX:
|
|
||||||
if (modifier == MOD_NONE)
|
|
||||||
data.u = va_arg(args, unsigned int);
|
|
||||||
else if (modifier == MOD_HALF)
|
|
||||||
data.u = (unsigned short) va_arg(args, unsigned int);
|
|
||||||
else if (modifier == MOD_HALF_HALF)
|
|
||||||
data.u = (unsigned char) va_arg(args, unsigned int);
|
|
||||||
else if (modifier == MOD_LONG)
|
|
||||||
data.u = va_arg(args, unsigned long);
|
|
||||||
else if (modifier == MOD_LONG_LONG)
|
|
||||||
data.u = va_arg(args, unsigned long long);
|
|
||||||
|
|
||||||
if (conversion == FMT_UINT) {
|
|
||||||
radix = 10;
|
|
||||||
} else if (conversion == FMT_OCT) {
|
|
||||||
radix = 8;
|
|
||||||
} else if (conversion == FMT_HEX) {
|
|
||||||
radix = 16;
|
|
||||||
base = 'a';
|
|
||||||
} else if (conversion == FMT_HEX_UPPER) {
|
|
||||||
radix = 16;
|
|
||||||
base = 'A';
|
|
||||||
}
|
|
||||||
goto printunum;
|
|
||||||
break;
|
|
||||||
case FMT_PTR:
|
|
||||||
case FMT_PTR_UPPER:
|
|
||||||
flag |= FLG_ZERO;
|
|
||||||
data.u = va_arg(args, size_t);
|
|
||||||
radix = 16;
|
|
||||||
if (conversion == FMT_PTR)
|
|
||||||
base = 'a';
|
|
||||||
else
|
|
||||||
base = 'A';
|
|
||||||
goto printunum;
|
|
||||||
break;
|
|
||||||
printunum:
|
|
||||||
print_unum(
|
|
||||||
data.u,
|
|
||||||
flag,
|
|
||||||
width,
|
|
||||||
precision,
|
|
||||||
false,
|
|
||||||
radix,
|
|
||||||
base
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case FMT_CHAR: {
|
|
||||||
char buf[2];
|
|
||||||
buf[0] = (char) va_arg(args, int);
|
|
||||||
buf[1] = '\0';
|
|
||||||
print_string(
|
|
||||||
buf,
|
|
||||||
flag,
|
|
||||||
width,
|
|
||||||
precision
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FMT_STR:
|
|
||||||
data.str = va_arg(args, const char*);
|
|
||||||
print_string(
|
|
||||||
data.str,
|
|
||||||
flag,
|
|
||||||
width,
|
|
||||||
precision
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case FMT_PERCENT:
|
|
||||||
kputc('%');
|
|
||||||
break;
|
|
||||||
case FMT_INVALID:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conversion == FMT_INT) {
|
||||||
|
enum format_length length =
|
||||||
|
apply_modifier(conversion, modifier);
|
||||||
|
enum printtype type = NONE;
|
||||||
|
enum charcase cc = LOWERCASE;
|
||||||
|
|
||||||
|
signed long long num = 0;
|
||||||
|
switch (length) {
|
||||||
|
case LEN_CHAR:
|
||||||
|
case LEN_SHORT:
|
||||||
|
case LEN_INT:
|
||||||
|
num = va_arg(args, signed int);
|
||||||
|
break;
|
||||||
|
case LEN_LONG:
|
||||||
|
num = va_arg(args, signed long);
|
||||||
|
break;
|
||||||
|
case LEN_LONGLONG:
|
||||||
|
num = va_arg(args, signed long long);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_signed_number(num, flags, width, precision, type, cc);
|
||||||
|
} else if (is_conversion_number(conversion)) {
|
||||||
|
enum format_length length =
|
||||||
|
apply_modifier(conversion, modifier);
|
||||||
|
enum printtype type =
|
||||||
|
conversion_to_printtype(conversion);
|
||||||
|
enum charcase cc =
|
||||||
|
conversion_to_charcase(conversion);
|
||||||
|
|
||||||
|
unsigned long long num = 0;
|
||||||
|
switch (length) {
|
||||||
|
case LEN_UCHAR:
|
||||||
|
case LEN_USHORT:
|
||||||
|
case LEN_UINT:
|
||||||
|
num = va_arg(args, unsigned int);
|
||||||
|
break;
|
||||||
|
case LEN_ULONG:
|
||||||
|
num = va_arg(args, unsigned long);
|
||||||
|
break;
|
||||||
|
case LEN_ULONGLONG:
|
||||||
|
num = va_arg(args, unsigned long long);
|
||||||
|
break;
|
||||||
|
case LEN_SIZET:
|
||||||
|
num = va_arg(args, size_t);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_unsigned_number(num, flags, width, precision, type, cc);
|
||||||
|
} else if (conversion == FMT_STR) {
|
||||||
|
char *str = va_arg(args, char *);
|
||||||
|
print_string(str, flags, width, precision);
|
||||||
|
} else if (conversion == FMT_CHAR) {
|
||||||
|
char temp[2];
|
||||||
|
temp[0] = va_arg(args, int);
|
||||||
|
temp[1] = '\0';
|
||||||
|
print_string(temp, flags, width, precision);
|
||||||
|
}
|
||||||
|
|
||||||
format = ptr - 1;
|
format = ptr - 1;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
error:
|
||||||
|
kputc('%');
|
||||||
|
format++;
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
kputc(c);
|
kputc(c);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue