diff --git a/global.mk b/global.mk index 27d6fa8..c33ce8b 100644 --- a/global.mk +++ b/global.mk @@ -13,7 +13,7 @@ CFLAGS := -Werror -Wall -W -Wextra -std=c18 -m3 -mb -mrenesas \ -ffreestanding -nostdlib -fstrict-volatile-bitfields \ -Wno-unused-const-variable -Wno-unused-function \ -Wno-unused-variable -Wno-unused-but-set-variable \ - -Wno-unused-parameter + -Wno-unused-parameter -Wno-pointer-to-int-cast # Colors red := \033[1;31m diff --git a/include/lib/stdio.h b/include/lib/stdio.h index d07a568..89d1440 100644 --- a/include/lib/stdio.h +++ b/include/lib/stdio.h @@ -5,17 +5,73 @@ #include #include -/* vsprintf(), sprintf() - formatted output conversion. */ -extern int vsprintf(char *str, char const *format, va_list ap); -extern int sprintf(char *str, char const *format, ...); +/* *printf() familly - formatted output conversion. */ +extern int printf(const char *restrict format, ...); +extern int sprintf(char *restrict str, const char *restrict format, ...); +extern int snprintf(char *restrict str, size_t size, const char *restrict format, ...); -/* dprintf(), printf() - display formatted output */ -extern int printf(const char *format, ...); -extern int dprintf(int fd, const char *format, ...); -extern int vdprintf(int fd, const char *format, va_list ap); +extern int vdprintf(int fd, const char *restrict format, va_list ap); +extern int vsprintf(char *restrict str, const char *restrict format, va_list ap); +extern int vsnprintf(char *restrict str, size_t size, const char *restrict format, va_list ap); /* putx() - display char / string */ extern int putchar(int c); extern int puts(const char *s); + + + +//--- +// Internal part +// TODO: move me ? +//--- +#define PRINTF_INTERNAL_BUFFER_SIZE 32 + +struct printf_opt +{ + // Internal buffer to avoid syscall flux + char buffer[PRINTF_INTERNAL_BUFFER_SIZE]; + size_t buffer_cursor; + + // Common part + int counter; + va_list ap; + + // *dprintf part + int fd; + + // *sprintf part + char *str; + size_t str_size; + + // For string / fd common support + void (*disp_char)(struct printf_opt *opt, char n); + void (*disp_fflush)(struct printf_opt *opt); + + // Printf-options + struct { + uint8_t diez : 1; + uint8_t zero : 1; + uint8_t minus : 1; + uint8_t space : 1; + uint8_t plus : 1; + uint8_t const : 3; + } flags; + int width; + int precision; + int uppercase; + int lenght; + + // Internal format management. + char sign; + char base[2]; + char format[32]; + int digits; +}; + +// Internal symbols used to define all actions possibility +extern void (*action[26])(struct printf_opt *opt, char n); + + + #endif /*__LIB_STDIO_H__*/ diff --git a/src/kernel/Makefile b/src/kernel/Makefile index a73fd8b..1298851 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -20,7 +20,7 @@ NAME := vhex EXEC := $(OUTPUT)/$(NAME).g1a LDFLAG := -T $(NAME).ld MEMORY_MAP := $(DEBUG)/$(NAME).map -LIBS := -L../lib -lgcc -lstring -ldisplay +LIBS := -L../lib -lgcc -llibc -ldisplay ICON := icon.bmp diff --git a/src/lib/libc/stdio/dprintf.c b/src/lib/libc/stdio/dprintf.c new file mode 100644 index 0000000..1b12e49 --- /dev/null +++ b/src/lib/libc/stdio/dprintf.c @@ -0,0 +1,12 @@ +#include + +int dprintf(int fd, const char *restrict format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = vdprintf(fd, format, ap); + va_end(ap); + return (ret); +} diff --git a/src/lib/libc/stdio/internal/printf_actions.c b/src/lib/libc/stdio/internal/printf_actions.c new file mode 100644 index 0000000..8d959ae --- /dev/null +++ b/src/lib/libc/stdio/internal/printf_actions.c @@ -0,0 +1,188 @@ +#include + +// Define all actions +static void action_str(struct printf_opt *op, char n); +static void action_ptr(struct printf_opt *op, char n); +static void action_int(struct printf_opt *op, char n); +static void action_uint(struct printf_opt *op, char n); +static void action_char(struct printf_opt *op, char n); + +// Define all actions which can be used +void (*action[26])(struct printf_opt *opt, char n) = { + NULL, NULL, action_char, action_int, + NULL, NULL, NULL, NULL, + action_int, NULL, NULL, NULL, + NULL, NULL, action_uint, action_ptr, + NULL, NULL, action_str, NULL, + action_uint, NULL, NULL, action_uint, + NULL, NULL, +}; + + +//--- +// Disp part +//--- +static void base_to_str(struct printf_opt *opt, uint64_t num, int base, int digits) +{ + char *hexa = (opt->uppercase == 1) ? "0123456789ABCDEF" : "0123456789abcdef"; + + opt->digits = 0; + while (num != 0 || opt->digits < digits) + { + opt->format[opt->digits++] = hexa[num % base]; + num = num / base; + } +} + +static void disp_format(struct printf_opt *opt) +{ + // display pre symbols + if (opt->sign != '\0') + (*opt->disp_char)(opt, opt->sign); + if (opt->base[0] != '\0') + (*opt->disp_char)(opt, opt->base[0]); + if (opt->base[1] != '\0') + (*opt->disp_char)(opt, opt->base[1]); + + // padding + if (opt->flags.minus == 1 && opt->width > opt->digits) + { + int total = opt->digits + (opt->sign != '\0') + + (opt->base[0] != '\0') + (opt->base[1] != '\0'); + total = opt->width - total; + while (--total >= 0) + (*opt->disp_char)(opt, (opt->flags.zero == 1) ? '0' : ' '); + + } + + // Display number + int saved_digits = opt->digits; + while (--opt->digits >= 0) + (*opt->disp_char)(opt, opt->format[opt->digits]); + + // padding + if (opt->flags.minus == 0 && opt->width > saved_digits) + { + int total = saved_digits + (opt->sign != '\0') + + (opt->base[0] != '\0') + (opt->base[1] != '\0'); + total = opt->width - total; + while (--total >= 0) + (*opt->disp_char)(opt, ' '); + } +} + + +//--- +// Args part +//--- +static uint64_t get_arg_i(struct printf_opt *opt) +{ + switch (opt->lenght) + { + case 0: return ((signed char)va_arg(opt->ap, int)); + case 1: return ((short int)va_arg(opt->ap, int)); + case 2: return (va_arg(opt->ap, long int)); + case 3: return (va_arg(opt->ap, long long int)); + case 4: return (va_arg(opt->ap, intmax_t)); + case 5: return (va_arg(opt->ap, size_t)); + case 6: return (va_arg(opt->ap, ptrdiff_t)); + } + return (va_arg(opt->ap, int)); +} + +static uint64_t get_arg_u(struct printf_opt *opt) +{ + switch (opt->lenght) + { + case 0: return ((unsigned char)va_arg(opt->ap, int)); + case 1: return ((unsigned short int)va_arg(opt->ap, int)); + case 2: return (va_arg(opt->ap, unsigned long int)); + case 3: return (va_arg(opt->ap, unsigned long long int)); + case 4: return (va_arg(opt->ap, intmax_t)); + case 5: return (va_arg(opt->ap, size_t)); + case 6: return (va_arg(opt->ap, ptrdiff_t)); + } + return (va_arg(opt->ap, unsigned int)); +} + + +//--- +// Actions part. +//--- +static void action_str(struct printf_opt *opt, char n) +{ + const char *str; + + (void)n; + str = va_arg(opt->ap, const char *); + while (*str != '\0') + (*opt->disp_char)(opt, *(str++)); +} + +static void action_char(struct printf_opt *opt, char n) +{ + n = (char)va_arg(opt->ap, int); + (*opt->disp_char)(opt, n); +} + +static void action_ptr(struct printf_opt *opt, char n) +{ + (void)n; + opt->sign = '@'; + opt->base[0] = '0'; + opt->base[1] = 'x'; + base_to_str(opt, (uint64_t)va_arg(opt->ap, void*), 16, 8); + disp_format(opt); +} + +static void action_int(struct printf_opt *opt, char n) +{ + int64_t num; + + // Get data and check negative value + // FIXME: max negative value can not be reversed + (void)n; + num = get_arg_i(opt); + if (num < 0) { + opt->sign = '-'; + num = -num; + } else if (opt->flags.space == 1 || opt->flags.plus == 1) { + opt->sign = (opt->flags.plus == 1) ? '+' : ' '; + } + + // Generate / display number + base_to_str(opt, num, 10, 1); + disp_format(opt); +} + +static void action_uint(struct printf_opt *opt, char n) +{ + uint64_t num; + int base; + + // Get appropriate base + switch (n) + { + case 'o': base = 8; break; + case 'x': base = 16; break; + default: base = 10; break; + } + + // Display extra symbols if needed + if (opt->flags.diez == 1) + { + if (n == 'o') { + opt->base[0] = '0'; + } else if (n == 'x') { + opt->base[0] = '0'; + opt->base[1] = (opt->uppercase == 1) ? 'X' : 'x'; + } + } + + // Get number + num = get_arg_u(opt); + + // Generate / display number + base_to_str(opt, num, base, 1); + disp_format(opt); +} diff --git a/src/lib/libc/stdio/internal/printf_common.c b/src/lib/libc/stdio/internal/printf_common.c new file mode 100644 index 0000000..5be23fa --- /dev/null +++ b/src/lib/libc/stdio/internal/printf_common.c @@ -0,0 +1,40 @@ +#include + +//TODO: precision handling +int printf_common(struct printf_opt *opt, const char *restrict format) +{ + extern int printf_get_options(struct printf_opt *opt, const char *restrict format); + int saved_p; + int p; + + p = -1; + opt->counter = 0; + opt->buffer_cursor = 0; + while (format[++p] != '\0') + { + // Check printable char + if (format[p] != '%' || format[p + 1] == '%') { + (*opt->disp_char)(opt, (format[p] != '%') ? format[p] : format[++p]); + continue; + } + + // Get options + saved_p = p; + p = p + printf_get_options(opt, &format[p + 1]); + + // Check arg validity + if (((format[p + 1] >= 'a' && format[p + 1] <= 'z') || + (format[p + 1] >= 'A' && format[p + 1] <= 'Z')) && + action[(format[p + 1] | 0x20) - 'a'] != NULL) { + (*action[(format[p + 1] | 0x20) - 'a'])(opt, format[p + 1] | 0x20); + p = p + 1; + continue; + } + + // Default, print the % + (*opt->disp_char)(opt, '%'); + p = saved_p; + } + (*opt->disp_fflush)(opt); + return (opt->counter); +} diff --git a/src/lib/libc/stdio/internal/printf_options.c b/src/lib/libc/stdio/internal/printf_options.c new file mode 100644 index 0000000..29d71a1 --- /dev/null +++ b/src/lib/libc/stdio/internal/printf_options.c @@ -0,0 +1,105 @@ +#include + +static int get_flags(struct printf_opt *opt, const char *restrict format) +{ + int i; + + i = -1; + opt->flags.diez = 0; + opt->flags.zero = 0; + opt->flags.minus = 0; + opt->flags.space = 0; + opt->flags.plus = 0; + while (format[++i] != '\0') + { + switch (format[i]) + { + case '#': opt->flags.diez = 1; break; + case '0': opt->flags.zero = 1; break; + case '-': opt->flags.minus = 1; break; + case ' ': opt->flags.space = 1; break; + case '+': opt->flags.plus = 1; break; + default: return (i); + } + } + return (i); +} + +static int get_width(struct printf_opt *opt, const char *restrict format) +{ + // Check dynamic width + if (format[0] == '*') { + opt->width = va_arg(opt->ap, int); + return (1); + } + + // Check error + int i = -1; + opt->width = 0; + if (format[0] == '0') + return (0); + + // Get static width + while (format[++i] >= '0' && format[i] <= '9') + opt->width = (opt->width * 10) + (format[i] - '0'); + return (i); +} + +static int get_precision(struct printf_opt *opt, const char *restrict format) +{ + // Check if precision is specified + if (format[0] != '.') + return (0); + + // Check dynamic precision + if (format[1] == '*') { + opt->precision = va_arg(opt->ap, int); + return (2); + } + + // Get static precision + int i = 0; + opt->precision = 0; + while (format[++i] >= '0' && format[i] <= '9') + opt->precision = (opt->precision * 10) + (format[i] - '0'); + + // Check default precision + if (i == 0) + opt->precision = 1; + return (i); +} + +static int get_lenght(struct printf_opt *opt, const char *restrict format) +{ + opt->lenght = -1; + switch (format[0]) + { + case 'h': opt->lenght = (format[1] == 'h') ? 1 : 0; break; + case 'l': opt->lenght = (format[1] == 'l') ? 3 : 2; break; + case 'j': opt->lenght = 4; break; + case 'z': opt->lenght = 5; break; + case 't': opt->lenght = 6; break; + default: return (0); + } + return ((opt->lenght == 1 || opt->lenght == 3) ? 2 : 1); +} + +int printf_get_options(struct printf_opt *opt, const char *restrict format) +{ + int i; + + // Wipe internal format infos + opt->sign = '\0'; + opt->base[0] = '\0'; + opt->base[1] = '\0'; + + // Get generals opetions + i = get_flags(opt, &format[0]); + i += get_width(opt, &format[i]); + i += get_precision(opt, &format[i]); + i += get_lenght(opt, &format[i]); + + // Check upper case actions + opt->uppercase = (format[i] == 'X') ? 1 : 0; + return (i); +} diff --git a/src/lib/libc/stdio/printf.c b/src/lib/libc/stdio/printf.c index 563d7c2..33b601e 100644 --- a/src/lib/libc/stdio/printf.c +++ b/src/lib/libc/stdio/printf.c @@ -1,7 +1,7 @@ #include #include -int printf(const char *format, ...) +int printf(const char *restrict format, ...) { va_list ap; int ret; diff --git a/src/lib/libc/stdio/snprintf.c b/src/lib/libc/stdio/snprintf.c new file mode 100644 index 0000000..8f8f38e --- /dev/null +++ b/src/lib/libc/stdio/snprintf.c @@ -0,0 +1,11 @@ +#include + +int snprintf(char *restrict str, size_t size, const char *restrict format, ...) +{ + va_list ap; + + va_start(ap, format); + size = vsnprintf(str, size, format, ap); + va_end(ap); + return (size); +} diff --git a/src/lib/libc/stdio/sprintf.c b/src/lib/libc/stdio/sprintf.c index a2327d7..5e2c810 100644 --- a/src/lib/libc/stdio/sprintf.c +++ b/src/lib/libc/stdio/sprintf.c @@ -1,12 +1,12 @@ #include -int sprintf(char *str, char const *format, ...) +int sprintf(char *restrict str, const char *restrict format, ...) { va_list ap; - int ret; + int size; va_start(ap, format); - ret = vsprintf(str, format, ap); + size = vsnprintf(str, 65535, format, ap); va_end(ap); - return (ret); + return (size); } diff --git a/src/lib/libc/stdio/vdprintf.c b/src/lib/libc/stdio/vdprintf.c index 5993f76..0826072 100644 --- a/src/lib/libc/stdio/vdprintf.c +++ b/src/lib/libc/stdio/vdprintf.c @@ -1,8 +1,35 @@ #include #include -//TODO x_x -int vdprintf(int fd, const char *format, va_list ap) +// FIXME: +// if the writte syscall do not return the same +// number of bytes that requested, stop the function ! +static void disp_fflush(struct printf_opt *opt) { - return (-1); + if (opt->buffer_cursor != 0) { + opt->counter += write(opt->fd, opt->buffer, opt->buffer_cursor); + opt->buffer_cursor = 0; + } +} + +static void disp_char(struct printf_opt *opt, char n) +{ + // Check if we should force flush the internal buffer + if (opt->buffer_cursor >= PRINTF_INTERNAL_BUFFER_SIZE) + disp_fflush(opt); + + // Save char + opt->buffer[opt->buffer_cursor++] = n; +} + +int vdprintf(int fd, const char *restrict format, va_list ap) +{ + extern int printf_common(struct printf_opt *opt, const char *restrict format); + struct printf_opt opt; + + opt.fd = fd; + opt.disp_char = &disp_char; + opt.disp_fflush = &disp_fflush; + va_copy(opt.ap, ap); + return (printf_common(&opt, format)); } diff --git a/src/lib/libc/stdio/vsnprintf.c b/src/lib/libc/stdio/vsnprintf.c new file mode 100644 index 0000000..ff6f42c --- /dev/null +++ b/src/lib/libc/stdio/vsnprintf.c @@ -0,0 +1,29 @@ +#include + +static void disp_char(struct printf_opt *opt, char n) +{ + // Check write possibility + if (opt->buffer_cursor < opt->str_size - 1) { + opt->str[opt->buffer_cursor] = n; + opt->buffer_cursor = opt->buffer_cursor + 1; + } +} + +static void disp_fflush(struct printf_opt *opt) +{ + opt->str[opt->buffer_cursor] = '\0'; +} + +int vsnprintf(char *restrict str, size_t size, const char *restrict format, va_list ap) +{ + extern int printf_common(struct printf_opt *opt, const char *restrict format); + struct printf_opt opt; + + opt.str = str; + opt.str_size = size; + opt.disp_char = &disp_char; + opt.disp_fflush = &disp_fflush; + va_copy(opt.ap, ap); + return (printf_common(&opt, format) + 1); +} + diff --git a/src/lib/libc/stdio/vsprintf.c b/src/lib/libc/stdio/vsprintf.c index 380198f..76819cb 100644 --- a/src/lib/libc/stdio/vsprintf.c +++ b/src/lib/libc/stdio/vsprintf.c @@ -1,115 +1,6 @@ #include -#include -static size_t strbase(char *dest, uint32_t nb, size_t size, int base) +int vsprintf(char *restrict str, const char *restrict format, va_list ap) { - uint32_t tmp; - uint8_t neg; - - neg = 0; - if (base == 10 && (int32_t)nb < 0){ - *dest = '-'; - nb = -nb; - neg = 1; - } - if (size == 0){ - tmp = nb; - while (tmp != 0){ - tmp /= base; - size += 1; - } - if (size == 0) - size = 1; - } - tmp = size + neg; - while ((int)(--size) >= neg){ - *(dest + size) = ((nb % base) + '0') + (39 * ((nb % base) > 9)); - nb /= base; - } - *(dest + tmp) = '\0'; - return (tmp); - -} - -static size_t strndump(char *dest, char const *src, size_t size) -{ - size_t i; - - if (src == NULL) - return (0); - i = -1; - while (++i < size && src[i] != '\0') - dest[i] = src[i]; - dest[i] = '\0'; - return (i); -} - -//TODO: update me !! -int vsprintf(char *str, char const *format, va_list ap) -{ - const char *tmp; - void *sstr; - size_t size; - size_t len; - int nb; - - if (format == NULL || str == NULL) - return (-1); - sstr = str; - while (*format != '\0'){ - if (*format != '%'){ - *(str++) = *(format++); - continue; - } - /* get size informations */ - size = 0; - len = -1; - format += 1; - while (format[++len] >= '0' && format[len] <= '9') - size = size * 10 + format[len] - '0'; - if (format[len] == '*'){ - size = va_arg(ap, size_t); - format = format + 1; - } - if (format[len] == '%'){ - *(str++) = '%'; - format += 1; - continue; - } - if (format[len] == 'c'){ - *(str++) = (char)va_arg(ap, int); - format += len + 1; - continue; - } - if (format[len] == 's'){ - tmp = va_arg(ap, const char *); - /* TODO: find better way to do the job */ - str += strndump(str, tmp, (size == 0) ? 1024 : size); - format += len + 1; - continue; - } - if (format[len] == 'd'){ - nb = va_arg(ap, int); - str += strbase(str, nb, size, 10); - format += len + 1; - continue; - } - if (format[len] == 'x'){ - nb = va_arg(ap, int); - str += strbase(str, nb, size, 16); - format += len + 1; - continue; - } - if (format[len] == 'p' || (format[len] == '#' && format[len + 1] == 'x')){ - nb = va_arg(ap, int); - *(str++) = '0'; - *(str++) = 'x'; - str += strbase(str, nb, 8, 16); - format += (format[len] == 'p') ? len + 1 : len + 2; - continue; - } - *(str++) = '%'; - } - *str = '\0'; - return ((int)((void *)str - (void *)sstr)); + return (vsnprintf(str, 65535, format, ap)); } diff --git a/src/user/shell/Makefile b/src/user/shell/Makefile index cff9614..230b457 100644 --- a/src/user/shell/Makefile +++ b/src/user/shell/Makefile @@ -17,7 +17,7 @@ NAME := shell EXEC := $(OUTPUT)/$(NAME).elf LDFLAG := -T $(NAME).ld MEMORY_MAP := $(DEBUG)/$(NAME).map -LIBS := -L../../lib -lstring -ldisplay -lunistd -lgcc +LIBS := -L../../lib -llibc -lgcc diff --git a/src/user/shell/builtin/proc.c b/src/user/shell/builtin/proc.c index c6a5ff7..0893c39 100644 --- a/src/user/shell/builtin/proc.c +++ b/src/user/shell/builtin/proc.c @@ -9,9 +9,14 @@ int builtin_proc(void) int wstatus; puts("proc test entry :)\n"); + printf("printf test:\n"); + printf("0#10x: %0#10x\n", 0xabcdef); + printf("str: %s\n", "Oui le test oui ! :D"); + printf("interger: %d\n", 12345); + printf("interger: %lld\n", 999999999999999999); // Try to create first child - child = fexecve("/mnt/casio/VHEX/test.elf"); + /*child = fexecve("/mnt/casio/VHEX/test.elf"); if (child == -1) { puts("fexecve fail :(\n"); @@ -20,5 +25,5 @@ int builtin_proc(void) // Wait child death waitpid(child, &wstatus, WUNTRACED); - return (0); +*/ return (0); }