--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* ft_printf.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <marvin@42.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2025/10/29 14:24:47 by agilliar #+# #+# */
+/* Updated: 2025/10/29 18:45:02 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+/*
+ 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);
+}