Update printf-familly + fix compilation error

This commit is contained in:
Yann MAGNIN 2020-03-21 20:02:27 +01:00
parent f02487d856
commit 2f34cf4d48
15 changed files with 495 additions and 131 deletions

View File

@ -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

View File

@ -5,17 +5,73 @@
#include <stdint.h>
#include <stdarg.h>
/* 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__*/

View File

@ -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

View File

@ -0,0 +1,12 @@
#include <lib/stdio.h>
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);
}

View File

@ -0,0 +1,188 @@
#include <lib/stdio.h>
// 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);
}

View File

@ -0,0 +1,40 @@
#include <lib/stdio.h>
//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);
}

View File

@ -0,0 +1,105 @@
#include <lib/stdio.h>
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);
}

View File

@ -1,7 +1,7 @@
#include <lib/stdio.h>
#include <lib/unistd.h>
int printf(const char *format, ...)
int printf(const char *restrict format, ...)
{
va_list ap;
int ret;

View File

@ -0,0 +1,11 @@
#include <lib/stdio.h>
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);
}

View File

@ -1,12 +1,12 @@
#include <lib/stdio.h>
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);
}

View File

@ -1,8 +1,35 @@
#include <lib/stdio.h>
#include <lib/unistd.h>
//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));
}

View File

@ -0,0 +1,29 @@
#include <lib/stdio.h>
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);
}

View File

@ -1,115 +1,6 @@
#include <lib/stdio.h>
#include <stdarg.h>
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));
}

View File

@ -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

View File

@ -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);
}