/* By: agilliar <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/10/29 14:24:47 by agilliar #+# #+# */
-/* Updated: 2025/10/31 23:52:32 by agilliar ### ########.fr */
+/* Updated: 2025/11/01 00:21:44 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include <stdarg.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <stdint.h>
-/*
- Because of variadic argument promotion,
- we represent an expected char as an int
-*/
-typedef enum e_step
-{
- STEP_INT,
- STEP_UINT,
- STEP_PTR,
- STEP_NONE,
-} t_step;
-
-/*
- Ditto for t_step
-*/
-typedef union u_step_arg
-{
- int v_int;
- unsigned int 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_specifier
-{
- SPECIFIER_NONE,
- SPECIFIER_CHAR,
- SPECIFIER_STR,
- SPECIFIER_PTR,
- SPECIFIER_INT,
- SPECIFIER_UINT,
- SPECIFIER_UINT_HEX_LOWER,
- SPECIFIER_UINT_HEX_UPPER,
- SPECIFIER_PERCENT,
-} t_specifier;
-
-typedef struct s_format
-{
- t_specifier specifier;
- t_sign_flag sign_flag;
- t_justify justify;
- bool num_prefix;
- int width;
- bool zero_pad;
- int precision;
- bool enable_precision;
-} t_format;
-
-typedef struct s_uint64_format
-{
- bool print_zeros;
- uint64_t base;
- const char *base_s;
-} t_uint64_format;
-
-int ft_putchar_sim(char c, bool sim)
-{
- if (!sim && write(STDOUT_FILENO, &c, 1) != 1)
- return (-1);
- return (1);
-}
-
-int ft_putnchar(char c, int n, bool sim)
-{
- int i;
-
- i = 0;
- while (i++ < n)
- if (ft_putchar_sim(c, sim) == -1)
- return (-1);
- return (n);
-}
-
-uint64_t ft_int_abs(int64_t n)
-{
- if (n < 0)
- return (-n);
- return (n);
-}
-
-t_uint64_format ft_uint64_format_new(const t_format *format)
-{
- t_uint64_format res;
- t_specifier spec;
-
- res.print_zeros = !format->enable_precision;
- spec = format->specifier;
- res.base = 16;
- res.base_s = "0123456789abcdef";
- if (spec == SPECIFIER_INT || spec == SPECIFIER_UINT)
- res.base = 10;
- if (spec == SPECIFIER_UINT_HEX_UPPER)
- res.base_s = "0123456789ABCDEF";
- return (res);
-}
-
-/*
- Prints a uint64_t without prefixes, padding or precision padding
-*/
-int ft_put_uint64(t_uint64_format format, uint64_t n, bool sim)
-{
- int written;
- uint64_t base;
- const char *base_s;
-
- if (!n && !format.print_zeros)
- return (0);
- format.print_zeros = true;
- base = format.base;
- base_s = format.base_s;
- if (n < base)
- written = 0;
- else
- written = ft_put_uint64(format, n / base, sim);
- if (written == -1 || ft_putchar_sim(base_s[n % base], sim) == -1)
- return (-1);
- return (written + 1);
-}
-
-int ft_putprefix(const t_format *format, bool sim, uint64_t n)
-{
- t_specifier spec;
- char c;
-
- if (n == 0)
- return ;
- spec = format->specifier;
- if (!format->num_prefix && spec != SPECIFIER_PTR)
- return (0);
- if (spec == SPECIFIER_PTR || spec == SPECIFIER_UINT_HEX_LOWER)
- c = 'x';
- else if (spec == SPECIFIER_UINT_HEX_UPPER)
- c = 'X';
- else
- return (0);
- if (ft_putchar_sim('0', sim) == -1
- || ft_putchar_sim(c, sim) == -1)
- return (-1);
- return (2);
-}
-
-int ft_precision_pad(const t_format *format, int written, bool sim)
-{
- if (written >= format->precision || !format->enable_precision)
- return (0);
- return (ft_putnchar('0', format->precision - written, sim));
-}
-
-int ft_zero_pad(const t_format *format, int written, bool sim)
-{
- if (written >= format->width || !format->zero_pad)
- return (0);
- return (ft_putnchar('0', format->width - written, sim));
-}
-
-int ft_putformat_char(const t_format *format, t_step_arg arg, bool sim)
-{
- (void) format;
- return (ft_putchar_sim(arg.v_int, sim));
-}
-
-int ft_putformat_str(const t_format *format, t_step_arg arg, bool sim)
-{
- int i;
- const char *s;
-
- i = 0;
- s = arg.v_ptr;
- if (!s)
- s = "(null)";
- while ((!format->enable_precision || format->precision > i) && s[i])
- if (ft_putchar_sim(s[i++], sim) == -1)
- return (-1);
- return (i);
-}
-
-int ft_putformat_ptr(const t_format *format, t_step_arg arg, bool sim)
-{
- int written;
- uint64_t val;
-
- val = (uint64_t) arg.v_ptr;
- if (!arg.v_ptr)
- {
- arg.v_ptr = "(nil)";
- return (ft_putformat_str(format, arg, sim));
- }
- if (ft_putprefix(format, sim, val) == -1)
- return (-1);
- written = ft_put_uint64(ft_uint64_format_new(format), val, sim);
- if (written == -1)
- return (-1);
- return (written + 2);
-}
-
-uint64_t ft_int_arg_abs(const t_format *format, t_step_arg arg)
-{
- if (format->specifier == SPECIFIER_INT)
- return (ft_int_abs(arg.v_int));
- return (arg.v_uint);
-}
-
-int ft_putsign(const t_format *format, t_step_arg arg, bool sim)
-{
- if (format->specifier != SPECIFIER_INT)
- return (0);
- if (arg.v_int < 0)
- return (ft_putchar_sim('-', sim));
- if (format->sign_flag == SIGN_FORCED)
- return (ft_putchar_sim('+', sim));
- if (format->sign_flag == SIGN_SPACE)
- return (ft_putchar_sim(' ', sim));
- return (0);
-}
-
-int ft_putformat_scalar(const t_format *format, t_step_arg arg, bool sim)
-{
- int sign;
- int prefix;
- int core;
- int precision;
- int zero_pad;
-
- sign = ft_putsign(format, arg, sim);
- if (sign == -1)
- return (-1);
- prefix = ft_putprefix(format, sim, ft_int_arg_abs(format, arg));
- if (prefix == -1)
- return (-1);
- core = ft_put_uint64(ft_uint64_format_new(format),
- ft_int_arg_abs(format, arg), true);
- precision = ft_precision_pad(format, core, sim);
- if (precision == -1)
- return (-1);
- zero_pad = ft_zero_pad(format, sign + prefix + precision + core, sim);
- if (zero_pad == -1)
- return (-1);
- if (ft_put_uint64(ft_uint64_format_new(format),
- ft_int_arg_abs(format, arg), sim) == -1)
- return (-1);
- return (sign + prefix + zero_pad + precision + core);
-}
-
-int ft_putformat_percent(const t_format *format, t_step_arg arg, bool sim)
-{
- (void)format;
- (void)arg;
- return (ft_putchar_sim('%', sim));
-}
+#include "ft_printf_shared.h"
int ft_putformat(const t_format *format, t_step_arg arg)
{
return (len + (len < format->width) * (format->width - len));
}
-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 = false;
- res.width = 0;
- res.zero_pad = false;
- res.precision = 0;
- res.enable_precision = false;
- return (res);
-}
-
-int ft_parse_num(const char **s)
-{
- int res;
-
- res = 0;
- while (**s >= '0' && **s <= '9')
- res = res * 10 + '0' - *((*s)++);
- return (res);
-}
-
-/*
- norminette doesn't want switch and case?
- fine then, poor man's switch
-*/
-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 = true;
- else if (c == '0')
- format->zero_pad = true;
- else
- return (false);
- return (true);
-}
-
-void ft_parse_width(const char **s, t_format *format)
-{
- while (**s >= '0' && **s <= '9')
- format->width = format->width * 10 + *((*s)++) - '0';
-}
-
-void ft_parse_precision(const char **s, t_format *format)
-{
- if (**s != '.')
- return ;
- (*s)++;
- format->enable_precision = true;
- while (**s >= '0' && **s <= '9')
- format->precision = format->precision * 10 + *((*s)++) - '0';
-}
-
-/*
- really wish there was a language feature to allow doing that in a neater way,
- but of course no such thing!
-*/
-t_specifier ft_parse_specifier(char c)
-{
- if (c == 'c')
- return (SPECIFIER_CHAR);
- if (c == 's')
- return (SPECIFIER_STR);
- if (c == 'p')
- return (SPECIFIER_PTR);
- if (c == 'd' || c == 'i')
- return (SPECIFIER_INT);
- if (c == 'u')
- return (SPECIFIER_UINT);
- if (c == 'x')
- return (SPECIFIER_UINT_HEX_LOWER);
- if (c == 'X')
- return (SPECIFIER_UINT_HEX_UPPER);
- if (c == '%')
- return (SPECIFIER_PERCENT);
- return (SPECIFIER_NONE);
-}
-
-void ft_format_normalize(t_format *format)
-{
- if (format->enable_precision || format->justify == JUSTIFY_LEFT)
- format->zero_pad = false;
-}
-
t_format ft_parse_format(const char **s)
{
t_format res;
return (res);
}
-int ft_print_step(const char **s, t_format *format, t_step_arg arg)
+int ft_printf_step(const char **s, t_format *format, t_step_arg arg)
{
int written;
return (0);
}
-t_step specifier_to_step(t_specifier spec)
-{
- if (spec == SPECIFIER_NONE || spec == SPECIFIER_PERCENT)
- return (STEP_NONE);
- if (spec == SPECIFIER_STR || spec == SPECIFIER_PTR)
- return (STEP_PTR);
- if (spec == SPECIFIER_UINT)
- return (STEP_UINT);
- return (STEP_INT);
-}
-
int ft_printf(const char *s, ...)
{
va_list args;
format = ft_format_default();
while (*s || format.specifier != SPECIFIER_NONE)
{
- written = ft_print_step(&s, &format, arg);
+ written = ft_printf_step(&s, &format, arg);
if (written == -1)
return (-1);
count += written;
va_end(args);
return (count);
}
-
-/*
-#include <stdio.h>
-#include <limits.h>
-
-#define TEST_PRINTF(...) {int r1 = printf(__VA_ARGS__); fflush(stdout); int r2 = ft_printf(__VA_ARGS__); if (r1 != r2) {fprintf(stderr, "printf failed, r1: %i, r2: %i\n", r1, r2); res = 1;}}
-
-int main(void)
-{
- int res = 0;
- const void *test_ptr = "test";
- TEST_PRINTF("this %corks\n", 'w');
- TEST_PRINTF("this %3corks\n", 'w');
- TEST_PRINTF("this %s\n", "is awesome");
- TEST_PRINTF("this %.5s\n", "is awesome");
- TEST_PRINTF("this %2s\n", "is awesome");
- TEST_PRINTF("this %10.6s\n", "is awesome");
- TEST_PRINTF("this %.6s\n", "is awesome");
- TEST_PRINTF("this %1.6s\n", "is awesome");
- TEST_PRINTF("this %.6s\n", NULL);
- TEST_PRINTF("this %p\n", NULL);
- TEST_PRINTF("this %0p\n", test_ptr);
- TEST_PRINTF("this %-24p a\n", test_ptr);
- TEST_PRINTF("this %24p a\n", test_ptr);
- TEST_PRINTF("this %i a\n", 12);
- TEST_PRINTF("this %d a\n", 12);
- TEST_PRINTF("this %i a\n", INT_MAX);
- TEST_PRINTF("this %d a\n", INT_MIN);
- TEST_PRINTF("this %.0i a\n", 0);
- TEST_PRINTF("this %5.0d a\n", 0);
- TEST_PRINTF("this %#-10i a\n", 12);
- TEST_PRINTF("this %#-10.5d a\n", 12);
- TEST_PRINTF("this % 10.5i a\n", 12);
- TEST_PRINTF("this % 10.5d a\n", -123);
- TEST_PRINTF("this % .5i a\n", 12);
- TEST_PRINTF("this %+10.5d a\n", 12);
- TEST_PRINTF("this %+10.5i a\n", -123);
- TEST_PRINTF("this %010.5d a\n", 12);
- TEST_PRINTF("this %0-10.5i a\n", 12);
- TEST_PRINTF("this %020u a\n", UINT_MAX);
- TEST_PRINTF("this %.0u a\n", 0);
- TEST_PRINTF("this %-10.0u a\n", 15);
- TEST_PRINTF("this %020x a\n", UINT_MAX);
- TEST_PRINTF("this %.0x a\n", 0);
- TEST_PRINTF("this %-10.0x a\n", 15);
- TEST_PRINTF("this %020X a\n", UINT_MAX);
- TEST_PRINTF("this %.0X a\n", 0);
- TEST_PRINTF("this %-10.0X a\n", 15);
- TEST_PRINTF("this %#020u a\n", UINT_MAX);
- TEST_PRINTF("this %#.0u a\n", 0);
- TEST_PRINTF("this %#-10.0u a\n", 15);
- TEST_PRINTF("this %#020x a\n", UINT_MAX);
- TEST_PRINTF("this %#.0x a\n", 0);
- TEST_PRINTF("this %#-10.0x a\n", 15);
- TEST_PRINTF("this %#020X a\n", UINT_MAX);
- TEST_PRINTF("this %#.0X a\n", 0);
- TEST_PRINTF("this %#-10.0X a\n", 15);
- TEST_PRINTF("this %+#020u a\n", UINT_MAX);
- TEST_PRINTF("this %+#.0u a\n", 0);
- TEST_PRINTF("this %+#-10.0u a\n", 15);
- TEST_PRINTF("this %+#020x a\n", UINT_MAX);
- TEST_PRINTF("this %+#.0x a\n", 0);
- TEST_PRINTF("this %+#-10.0x a\n", 15);
- TEST_PRINTF("this %+#020X a\n", UINT_MAX);
- TEST_PRINTF("this %+#.0X a\n", 0);
- TEST_PRINTF("this %+#-10.0X a\n", 15);
- TEST_PRINTF("%% hai %15s%05i\n", "this num is: ", 621);
-
- return res;
-}
-*/
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* ft_printf_shared.h :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2025/11/01 00:07:43 by agilliar #+# #+# */
+/* Updated: 2025/11/01 00:39:45 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#ifndef FT_PRINTF_SHARED_H
+# define FT_PRINTF_SHARED_H
+
+# include <stdbool.h>
+# include <stdint.h>
+
+/*
+ Because of variadic argument promotion,
+ we represent an expected char as an int
+*/
+typedef enum e_step
+{
+ STEP_INT,
+ STEP_UINT,
+ STEP_PTR,
+ STEP_NONE,
+} t_step;
+
+/*
+ Ditto for t_step
+*/
+typedef union u_step_arg
+{
+ int v_int;
+ unsigned int 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_specifier
+{
+ SPECIFIER_NONE,
+ SPECIFIER_CHAR,
+ SPECIFIER_STR,
+ SPECIFIER_PTR,
+ SPECIFIER_INT,
+ SPECIFIER_UINT,
+ SPECIFIER_UINT_HEX_LOWER,
+ SPECIFIER_UINT_HEX_UPPER,
+ SPECIFIER_PERCENT,
+} t_specifier;
+
+typedef struct s_format
+{
+ t_specifier specifier;
+ t_sign_flag sign_flag;
+ t_justify justify;
+ bool num_prefix;
+ int width;
+ bool zero_pad;
+ int precision;
+ bool enable_precision;
+} t_format;
+
+typedef struct s_uint64_format
+{
+ bool print_zeros;
+ uint64_t base;
+ const char *base_s;
+} t_uint64_format;
+
+int ft_putformat_char(const t_format *format,
+ t_step_arg arg, bool sim);
+int ft_putformat_str(const t_format *format,
+ t_step_arg arg, bool sim);
+int ft_putformat_ptr(const t_format *format,
+ t_step_arg arg, bool sim);
+int ft_putformat_scalar(const t_format *format,
+ t_step_arg arg, bool sim);
+int ft_putformat_percent(const t_format *format,
+ t_step_arg arg, bool sim);
+
+int ft_putchar_sim(char c, bool sim);
+int ft_putnchar(char c, int n, bool sim);
+uint64_t ft_int_arg_abs(const t_format *format, t_step_arg arg);
+
+t_format ft_format_default(void);
+t_step specifier_to_step(t_specifier spec);
+void ft_format_normalize(t_format *format);
+t_uint64_format ft_uint64_format_new(const t_format *format);
+
+bool ft_parse_flag(char c, t_format *format);
+void ft_parse_width(const char **s, t_format *format);
+void ft_parse_precision(const char **s, t_format *format);
+t_specifier ft_parse_specifier(char c);
+
+int ft_put_uint64(t_uint64_format format, uint64_t n, bool sim);
+int ft_putprefix(const t_format *format, bool sim, uint64_t n);
+int ft_precision_pad(const t_format *format, int written, bool sim);
+int ft_zero_pad(const t_format *format, int written, bool sim);
+int ft_putsign(const t_format *format, t_step_arg arg, bool sim);
+
+#endif