From: = <=> Date: Wed, 29 Oct 2025 17:45:34 +0000 (+0100) Subject: Partial printf parsing impl X-Git-Tag: Testable~17 X-Git-Url: https://git.uwuaxy.net/?a=commitdiff_plain;h=9d75ad504e4a5f48b4b06dae338afd967db58302;p=axy%2Fft%2Fft_printf.git Partial printf parsing impl --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4711819 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +NAME=libftprintf.a + +SRCS= + +OBJS=${SRCS:.c=.o} + +CFLAGS=-Wall -Wextra -Werror + +CC=cc + +all : ${NAME} + +%.o : %.c + ${CC} ${CFLAGS} -c -o $@ -- $< + +${NAME} : ${OBJS} + ar -rcs $@ $^ + +clean : + rm -f ${OBJS} ${BONUS_OBJS} + +fclean : clean + rm -f ${NAME} + +re : fclean all + +.PHONY : all clean fclean re diff --git a/ft_printf.c b/ft_printf.c new file mode 100644 index 0000000..3e2d923 --- /dev/null +++ b/ft_printf.c @@ -0,0 +1,218 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_printf.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agilliar +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/10/29 14:24:47 by agilliar #+# #+# */ +/* Updated: 2025/10/29 18:45:02 by agilliar ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include +#include + +/* + Because of variadic argument promotion, we represent an expected char as an int +*/ +typedef enum e_step +{ + STEP_INT, + STEP_UNSIGNED, + STEP_PTR, + STEP_NONE, +} t_step; + +/* + Ditto for t_step +*/ +typedef union u_step_arg +{ + int v_int; + unsigned v_uint; + void *v_ptr; +} t_step_arg; + +typedef enum e_sign_flag +{ + SIGN_NEG_ONLY, + SIGN_FORCED, + SIGN_SPACE, +} t_sign_flag; + +typedef enum e_justify +{ + JUSTIFY_LEFT, + JUSTIFY_RIGHT, +} t_justify; + +typedef enum e_padding_type +{ + PADDING_SPACE, + PADDING_ZEROS, +} t_padding_type; + +typedef enum e_specifier +{ + SPECIFIER_NONE, + SPECIFIER_CHAR, + SPECIFIER_STRING, + SPECIFIER_VOID_PTR, + SPECIFIER_INT, + SPECIFIER_UNSIGNED, + SPECIFIER_INT_HEX_LOWER, + SPECIFIER_INT_HEX_UPPER, + SPECIFIER_PERCENT, +} t_specifier; + +typedef enum e_num_prefix +{ + NUM_PREFIX_NONE, + NUM_PREFIX_FORMAT; +} t_num_prefix; + +typedef struct s_format +{ + t_specifier specifier; + t_sign_flag sign_flag; + t_justify justify; + t_num_prefix num_prefix; + size_t width; + s_padding_type padding_type; + size_t precision; + bool enable_precision; +} t_format; + +int ft_putformat(const t_format *format, t_step_arg arg); + +t_format ft_format_default(void) +{ + t_format res; + + res.specifier = SPECIFIER_NONE; + res.sign_flag = SIGN_NEG_ONLY; + res.justify = JUSTIFY_RIGHT; + res.num_prefix = NUM_PREFIX_NONE; + res.width = 0; + res.padding_type PADDING_SPACE; + res.precision = 0; + res.enable_precision = false; + return (res); +} + +size_t ft_parse_num(const char **s) +{ + size_t res; + + res = 0; + while (**s >= '0' && **s <= '9') + res = res * 10 + '0' - *((*s)++); + return (res); +} + +bool ft_parse_flag(char c, t_format *format) +{ + if (c == '-') + format->justify = JUSTIFY_LEFT; + else if (c == '+') + format->sign_flag = SIGN_FORCED; + else if (c == ' ') + format->sign_flag = SIGN_SPACE; + else if (c == '#') + format->num_prefix = NUM_PREFIX_FORMAT; + else if (c == '0') + format->padding_type = PADDING_ZEROS; +} + +t_specifier ft_parse_specifier(char c) +{ + if (c == 'c') + return (SPECIFIER_CHAR); + if (c == 's') + return (SPECIFIER_STRING); + if (c == 'p') + return (SPECIFIER_VOID_PTR); + if (c == 'd' || c == 'i') + return (SPECIFIER_INT); + if (c == 'u') + return (SPECIFIER_UNSIGNED); + if (c == 'x') + return (SPECIFIER_INT_HEX_LOWER); + if (c == 'X') + return (SPECIFIER_INT_HEX_UPPER); + if (c == '%') + return (SPECIFIER_PERCENT); + return (SPECIFIER_NONE); +} + +t_format ft_parse_format(const char **format) +{ + t_format res; + + res = ft_format_default(); + while (ft_parse_flag(**format, &res)) + format++; + res.specifier = ft_parse_specifier(*((*format)++)); + return (res); +} + +int ft_print_step(const char **format, t_format *step, t_step_arg arg) +{ + int written; + + if (step->specifier == SPECIFIER_NONE && **format != '%') + { + if (write(STDOUT_FILENO, (*format)++, 1) != 1) + return (-1); + return (1); + } + if (step->specifier != SPECIFIER_NONE) + { + written = ft_putformat(step, arg); + *step = ft_format_default(); + return (written); + } + *step = ft_parse_format(format); + return (0); +} + +t_step specifier_to_step(t_specifier spec) +{ + if (spec == SPECIFIER_NONE || spec == SPECIFIER_PERCENT) + return (STEP_NONE); + if (spec == SPECIFIER_STRING || spec == SPECIFIER_VOID_PTR) + return (STEP_PTR); + if (spec == SPECIFIER_UNSIGNED) + return (STEP_UNSIGNED); + return (STEP_INT); +} + +int ft_printf(const char *format, ...) +{ + va_list args; + int count; + int written; + t_format step; + t_step_arg arg; + + va_start(args, format); + count = 0; + step.specifier = SPECIFIER_NONE; + while (*format) + { + written = ft_print_step(&format, &step, arg); + if (written < 0) + return (written); + count += written; + if (specifier_to_step(step.specifier) == STEP_INT) + arg.v_int = va_arg(args, int); + if (specifier_to_step(step.specifier) == STEP_UNSIGNED) + arg.v_uint = va_arg(args, unsigned); + if (specifier_to_step(step.specifier) == STEP_PTR) + arg.v_ptr = va_arg(args, void *); + } + return (count); +} diff --git a/libftprintf.h b/libftprintf.h new file mode 100644 index 0000000..a51f240 --- /dev/null +++ b/libftprintf.h @@ -0,0 +1,18 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* libftprintf.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agilliar +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/10/29 14:21:01 by agilliar #+# #+# */ +/* Updated: 2025/10/29 14:22:40 by agilliar ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef LIBFTPRINTF_H +# define LIBFTPRINTF_H + +int ft_printf(const char *format, ...); + +#endif