minishell/libft/ft_printf_parsing.c
2025-02-12 15:12:42 +01:00

132 lines
3.6 KiB
C

/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_printf_parsing.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jguelen <jguelen@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/11/18 10:38:17 by jguelen #+# #+# */
/* Updated: 2025/02/04 10:04:05 by jguelen ### ########.fr */
/* */
/* ************************************************************************** */
#include "ft_printf.h"
static t_printf_flags ft_get_flag(char c)
{
if (c == '0')
return (PRINTF_ZEROFLAG);
if (c == '-')
return (PRINTF_MINUSFLAG);
if (c == '#')
return (PRINTF_HASHTAGFLAG);
if (c == '+')
return (PRINTF_PLUSFLAG);
if (c == ' ')
return (PRINTF_SPACEFLAG);
return (PRINTF_NOFLAG);
}
static t_printf_spec ft_get_spec(char c)
{
if (c == 'c')
return (PRINTF_CHARSPEC);
if (c == 's')
return (PRINTF_STRINGSPEC);
if (c == 'p')
return (PRINTF_POINTERSPEC);
if (c == 'd' || c == 'i')
return (PRINTF_INTSPEC);
if (c == 'u')
return (PRINTF_UINTSPEC);
if (c == 'x')
return (PRINTF_HEXA_LOWSPEC);
if (c == 'X')
return (PRINTF_HEXA_UPSPEC);
if (c == '%')
return (PRINTF_PERCENTSPEC);
return (PRINTF_NOSPEC);
}
static t_printf_var ft_get_var(t_printf_spec specifier,
va_list *arg_list, char c)
{
t_printf_var var;
ft_bzero(&var, sizeof(t_printf_var));
if (specifier == PRINTF_CHARSPEC)
var.c = (char)va_arg(*arg_list, int);
else if (specifier == PRINTF_STRINGSPEC)
var.s = va_arg(*arg_list, char *);
else if (specifier == PRINTF_POINTERSPEC)
var.p = va_arg(*arg_list, void *);
else if (specifier == PRINTF_INTSPEC)
var.i = va_arg(*arg_list, int);
else if (specifier == PRINTF_UINTSPEC || specifier == PRINTF_HEXA_LOWSPEC
|| specifier == PRINTF_HEXA_UPSPEC)
var.u = va_arg(*arg_list, unsigned int);
else
var.c = c;
return (var);
}
/*PRINTF_ZEROFLAG only for numerical conv*/
static void ft_getprintf_format(char **s, t_printf_format *format,
va_list *arg_list)
{
char *tmp;
tmp = (char *)*s;
while (*tmp && ft_strchr(PRINTF_FLAGS, *tmp))
format->flags |= ft_get_flag(*tmp++);
if (*tmp == '*' && tmp++)
format->minwidth = (long)va_arg(*arg_list, int);
else if (ft_isdigit(*tmp))
format->minwidth = ft_printf_atoi(tmp, &tmp);
if (*tmp == '.' && tmp++)
{
format->flags = (format->flags | PRINTF_DOTFLAG) & ~PRINTF_ZEROFLAG;
if (*tmp == '*' && tmp++)
format->precision = (long)va_arg(*arg_list, int);
else if (ft_isdigit(*tmp))
format->precision = ft_printf_atoi(tmp, &tmp);
}
format->specifier = ft_get_spec(*tmp);
if (*tmp)
{
format->var = ft_get_var(format->specifier, arg_list, *tmp);
*s = tmp + 1;
}
format->total_len = var_len(format);
get_prefix_format(format);
}
int ft_printf_parsing(int fd, char *s, t_printf_format *format,
va_list *arg_list)
{
int len;
int i;
len = 0;
while (*s)
{
i = 0;
while (s[i] && s[i] != '%')
i++;
i = write(fd, s, i);
if (i == -1)
return (-1);
s += i;
len += i;
if (*s == '%' && s++)
{
ft_bzero(format, sizeof(t_printf_format));
ft_getprintf_format(&s, format, arg_list);
i = ft_print_printf_format(fd, format);
if (((INT_MAX - len) < format->total_len) || (i == -1))
return (-1);
len += format->total_len;
}
}
return (len);
}