ajout de ft_printf a la librairie

This commit is contained in:
hugogogo
2021-05-19 18:06:12 +02:00
parent b7340d9324
commit f1ce5b8b9e
10 changed files with 770 additions and 9 deletions

View File

@@ -4,7 +4,8 @@
NAME = libft.a
CC = gcc
VPATH = srcs/
VPATH = srcs/ \
srcs/ft_printf_files/
IDIR = ./includes
_DEP = libft.h
@@ -94,8 +95,15 @@ SRCS = ft_memset.c \
ft_arraymap.c \
ft_strmultisplit.c \
\
get_next_line.c \
ft_concat_free.c
ft_get_next_line.c \
ft_concat_free.c \
\
ft_printf.c \
ft_next_word.c \
ft_convert.c \
ft_flag_transform.c \
ft_flag_transform_bonus.c
ODIR = ./builds
OBJS = $(SRCS:%.c=$(ODIR)/%.o)

View File

@@ -13,10 +13,6 @@
#ifndef GET_NEXT_LINE_H
# define GET_NEXT_LINE_H
# include <string.h>
# include <unistd.h>
# include <stdlib.h>
# ifndef BUFFER_SIZE
# define BUFFER_SIZE 1
# endif

62
includes/ft_printf.h Normal file
View File

@@ -0,0 +1,62 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_printf.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: hulamy <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2020/02/27 12:07:47 by hulamy #+# #+# */
/* Updated: 2020/03/12 20:35:10 by hulamy ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef FT_PRINTF_H
# define FT_PRINTF_H
# include <stdarg.h> // to use va_arg
/*
** ft_printf.c
*/
char *specifier(char *s);
int ft_expand_star(int nbr, char **string);
int ft_put_word(char *s, char *type, int size);
char *convert_with_flags(char *s, va_list ap, char *type, int *size);
int ft_printf(char *string, ...);
/*
** ft_next_word.c
*/
int width_precision(char *s);
int word_length(char *s);
char *next_word(char **s);
/*
** ft_convert.c
*/
char *conv_i(char c, long int i);
char *conv_u(char c, unsigned long int i);
char *ft_convert(va_list ap, char *type, char **s);
/*
** ft_flag_transform.c
*/
char *precision_int(char *print, int precision);
char *ft_precision(char *s, char *print, char *type);
char *width_flags(char *print, char *s, int width, int zero);
char *ft_width(char *s, char *print, int *size, char *type);
char *ft_flag_transform(char *s, char *print, char *type, int *size);
/*
** ft_flag_transform_bonus.c
*/
char *ft_plus(char *s, char *print, char *type);
char *ft_sharp(char *s, char *print, char *type);
char *ft_sharp_again(char *s, char *print, char *type);
char *ft_space(char *s, char *print, char *type, int *size);
#endif

View File

@@ -15,7 +15,9 @@
# include <string.h>
# include <unistd.h>
# include <stdlib.h>
# include "get_next_line.h"
# include "ft_get_next_line.h"
# include "ft_printf.h"
# include <stdarg.h> // to use va_arg in ft_printf
void *ft_memset(void *b, int c, size_t len);
void ft_bzero(void *s, size_t n);
@@ -103,7 +105,61 @@ int ft_issort(int *tab, int length, int (*f)(int, int));
int *ft_arraymap(int *tab, int length, int(*f)(int));
void ft_putnbrendl(int n);
void ft_putnbrendl_fd(int n, int fd);
int get_next_line(const int fd, char **line);
int ft_get_next_line(const int fd, char **line);
char *ft_concat_free(char *str1, char *str2);
# include <stdarg.h> // to use va_arg
/*
** ft_printf.c
*/
char *specifier(char *s);
int ft_expand_star(int nbr, char **string);
int ft_put_word(char *s, char *type, int size);
char *convert_with_flags(char *s, va_list ap, char *type, int *size);
int ft_printf(char *string, ...);
/*
** ft_next_word.c
*/
int width_precision(char *s);
int word_length(char *s);
char *next_word(char **s);
/*
** ft_convert.c
*/
char *conv_i(char c, long int i);
char *conv_u(char c, unsigned long int i);
char *ft_convert(va_list ap, char *type, char **s);
/*
** ft_flag_transform.c
*/
char *precision_int(char *print, int precision);
char *ft_precision(char *s, char *print, char *type);
char *width_flags(char *print, char *s, int width, int zero);
char *ft_width(char *s, char *print, int *size, char *type);
char *ft_flag_transform(char *s, char *print, char *type, int *size);
/*
** ft_flag_transform_bonus.c
*/
char *ft_plus(char *s, char *print, char *type);
char *ft_sharp(char *s, char *print, char *type);
char *ft_sharp_again(char *s, char *print, char *type);
char *ft_space(char *s, char *print, char *type, int *size);
#endif

View File

@@ -0,0 +1,105 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_convert.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: hulamy <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2020/03/12 22:30:05 by hulamy #+# #+# */
/* Updated: 2020/06/30 00:40:49 by hulamy ### ########.fr */
/* */
/* ************************************************************************** */
#include "libft.h"
/*
** -convert the next argument into a string according to the following
** correspondances for diuxXcspefgn :
** [char] [hhd, hhi, c] [int] [d i c]
** [short] [hd, hi] [int]
** [int] [d, i] [int]
** [long] [ld, li] [long] [ld li]
** [long long] [lld, lli] [long]
** [unsigned char] [hhu, hhx, hhX] [unsigned int] [u x X p s]
** [unsigned short] [hu, hx, hX] [unsigned int]
** [unsigned int] [u, x, X, p] [unsigned int]
** [unsigned long] [lu, lx, lX] [unsigned long] [lu lx lX]
** [unsigned long long][llu, llx, llX] [unsigned long]
** [char *] [s, hhn]
** [double] [e, le, f, lf, g, lg]
** [wint_t] [lc]
** [wchar_t] [ls]
** [short *] [hn]
** [int *] [n]
** [long *] [ln]
** [long long *] [lln]
** -'h' and 'hh', are traited just like regular size because of
** default promotion, that promote smaller type than int into int
*/
char *conv_i(char c, long int i)
{
char *s;
if (c == 'c')
{
s = ft_strdup("0");
s[0] = i;
return (s);
}
if (c == 'd' || c == 'i')
return (ft_itoa(i));
return (NULL);
}
char *conv_u(char c, unsigned long int i)
{
char *s;
if (c == 's')
return (i == 0 ? ft_strdup("(null)") : ft_strdup((char *)i));
s = ft_utoa(i);
if (c == 'u')
return (s);
if (c == 'x' || c == 'p')
return (ft_convertbase_free(s, "0123456789", "0123456789abcdef"));
if (c == 'X')
return (ft_convertbase_free(s, "0123456789", "0123456789ABCDEF"));
return (NULL);
}
/*
** -first a loop to expand all the stars from width and .precision
** they always expand into int type
** it's done first because those are the first next args on the va_list
** -for each kind of specifier there is finally four kinds of conversion :
** int / long int / unsigned int / unsingned long int
** -the conversion 'uxX' associated with 'l' are converted with lu, but
** also are 'p' and 's', without an 'l' flag, that's why there is this little
** trick on line the line for unsigned int :
** -'uxXps' && 'lps' will make it looks for 'uxX' and for 'l'
** (because it will never find a 'p' or a 's' if there are 'uxX' already)
** or for 'p' and again for 'p', or 's' twice similarly
*/
char *ft_convert(va_list ap, char *type, char **s)
{
char *tmp;
while (ft_strchr(*s, '*'))
if (!(ft_expand_star(va_arg(ap, int), s)))
return (NULL);
if ((tmp = ft_strchrset(type, "dic")) && ft_strchr(type, 'l'))
return (conv_i(tmp[0], va_arg(ap, long int)));
if ((tmp = ft_strchrset(type, "dic")))
return (conv_i(tmp[0], va_arg(ap, int)));
if ((tmp = ft_strchrset(type, "uxXps")) && ft_strchrset(type, "lps"))
return (conv_u(tmp[0], va_arg(ap, unsigned long int)));
if ((tmp = ft_strchrset(type, "uxX")))
return (conv_u(tmp[0], va_arg(ap, unsigned int)));
if (ft_strchr(type, '%'))
return (ft_strdup("%"));
if (ft_strchrset(type, "efgn"))
return (NULL);
return (NULL);
}

View File

@@ -0,0 +1,199 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_flag_transform.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: hulamy <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2020/03/12 22:30:28 by hulamy #+# #+# */
/* Updated: 2020/03/12 22:30:41 by hulamy ### ########.fr */
/* */
/* ************************************************************************** */
#include "libft.h"
/*
** -function that modify the string 'print' according to the precision flag :
** if length(s) < precision, add x '0' bfr nbr, but after '-' if negative
*/
char *precision_int(char *print, int precision)
{
int i;
char *tmp;
i = ft_strlen(print);
if (print[0] == '-')
precision++;
if (precision > i)
{
if (!(tmp = (char *)malloc(sizeof(char) * (precision + 1))))
return (NULL);
tmp[precision] = '\0';
if (print[0] == '-')
tmp[0] = '-';
while (i)
tmp[--precision] = print[--i];
if (print[0] == '-')
precision++;
while (precision)
tmp[--precision] = '0';
if (print[0] == '-')
tmp[0] = '-';
free(print);
print = tmp;
}
return (print);
}
/*
** -it first verify if there is a precision point, and if so, it execute a
** serie of action listed below, otherwise return print as it is
** ACTIONS :
** -look for a '.'
** -if followed by numbers, extract an int version of those numbers
** -if the '.' is alone, gives value '0' to the int
** -then removes the '.' and the numbers from the %string
** -if flag '0' is present in %string, removes it (actually turn each occurence
** in a '.')
** -and transform 'print' according to the precision :
** -0 if .precision is 0 && print is "0": print nothing
** -1 if type is s: if length(s) > precision, removes end of 'print' to print
** only x chars, with x = precision
** -2 if type is "diouxX": call fonction 'precision_int' that return :
** if length(s) < precision, add x '0' bfr nbr, but after '-' if negative
** -3 if type is "aAeEfF": not covered
** -4 if type is "gG": not covered
** -5 else: error
*/
char *ft_precision(char *s, char *print, char *type)
{
char *tmp;
int precision;
int i;
if ((tmp = ft_strchr(s, '.')))
{
precision = ft_atoi(tmp + 1);
while (*s && ft_strchr("#- +'0", *(++s)))
if (*s == '0')
*s = '/';
i = 0;
if (precision == 0 && !ft_strcmp(print, "0"))
print[0] = '\0';
else if (ft_strchr(type, 's'))
{
while (i < precision && print[i])
i++;
if (print[i])
print[i] = '\0';
}
else if (ft_strchrset(type, "diouxX"))
print = precision_int(print, precision);
}
return (print);
}
/*
** -if flag '-' is present, put extra width as ' ' to right of 'print'
** -if flag '0' is present, put extra width as '0' to left of 'print'
** -else, put extra width as ' ' to left of 'print'
*/
char *width_flags(char *print, char *s, int width, int zero)
{
char *tmp;
char *minus;
int len;
len = ft_strlen(print) + zero;
if (!(tmp = ft_strnew(width)))
return (NULL);
if (ft_strchr(s, '-'))
{
ft_memmove(tmp, print, len);
ft_memset(tmp + len, ' ', width - len);
}
else
{
ft_memset(tmp, (ft_strchr(s, '0')) ? '0' : ' ', width - len);
ft_memmove(ft_strchr(tmp, '\0') + zero, print, ft_strlen(print));
if (ft_strchr(s, '0') && (minus = ft_strchrset("+-", tmp)))
{
tmp[0] = (minus[0] == '+') ? '+' : '-';
minus[0] = '0';
}
}
free(print);
return (tmp);
}
/*
** -if there is a minimal width field, calculate it and add it to print
** according to the flags '-' and '0' if present
** -in details :
** 0 if print[0] value 0, as it happens for type c with (char)0, save it for
** later in 'zero'
** 1 loop through s, the string starting by '%' and ending by a converter,
** until it has passed all the flags that are not a potentiel width field
** 2 then if it's the end of s, there is no width and print isn't changed,
** otherwise the int 'size' take the value returned by atoi
** in case print isn't changed, 'size' is the length of 'print'
** 3 then if the size of the width shield is bigger than the size of print
** (plus zero in case print is a (char)0), call 'width_flags' that will
** create a new char* to contain the string to print after transformation
** 4 otherwise 'size' is the length of print + zero
*/
char *ft_width(char *s, char *print, int *size, char *type)
{
char *tmp;
int zero;
tmp = s;
zero = 0;
if (print[0] == '\0' && ft_strchr(type, 'c'))
zero = 1;
while (*tmp != '\0' && ft_strchr("%#- +'0/", *tmp))
tmp++;
if (*tmp == '\0' || *tmp == '.')
{
*size = ft_strlen(print) + zero;
return (print);
}
*size = ft_atoi(tmp);
tmp[0] = '\0';
if ((unsigned int)*size > ft_strlen(print) + zero)
print = width_flags(print, s, *size, zero);
else
*size = ft_strlen(print) + zero;
tmp[0] = '1';
return (print);
}
/*
** -go through all the transformation flags needs
** -first the precision
** -then if type is int and nbr is positive, add a + to the left, it's flag '+'
** -third the flag "#"
** -fourth, the width
** -then p
** -the case of 'p' is treated without any subtelness because i don't care
*/
char *ft_flag_transform(char *s, char *print, char *type, int *size)
{
print = ft_precision(s, print, type);
print = ft_plus(s, print, type);
print = ft_sharp(s, print, type);
if (ft_strchr(type, 'p'))
{
print = ft_concat_free(ft_strdup("0x"), print);
*size += 2;
}
print = ft_width(s, print, size, type);
print = ft_sharp_again(s, print, type);
print = ft_space(s, print, type, size);
return (print);
}

View File

@@ -0,0 +1,75 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_flag_transform_bonus.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: hulamy <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2020/03/12 22:30:50 by hulamy #+# #+# */
/* Updated: 2020/03/12 22:30:57 by hulamy ### ########.fr */
/* */
/* ************************************************************************** */
#include "libft.h"
char *ft_plus(char *s, char *print, char *type)
{
if (!ft_strchrset(type, "di"))
return (print);
if (ft_strchr(s, '+') && !ft_strchr(print, '-'))
print = ft_concat_free(ft_strdup("+"), print);
return (print);
}
char *ft_sharp(char *s, char *print, char *type)
{
if (ft_strchr(s, '#'))
{
if (ft_strchr(type, 'x'))
print = ft_concat_free(ft_strdup("0x"), print);
else
print = ft_concat_free(ft_strdup("0X"), print);
}
return (print);
}
char *ft_sharp_again(char *s, char *print, char *type)
{
char *tmp;
if (!ft_strchr(s, '#'))
return (print);
if (print[0] == '0' && print[1] == '0' && ft_strchrset(type, "xX"))
{
tmp = ft_strchrset("xX", print);
print[1] = tmp[0];
tmp[0] = '0';
}
return (print);
}
char *ft_space(char *s, char *print, char *type, int *size)
{
int i;
i = 0;
if (print[0] == ' ' || !ft_strchr(s, ' ') || !ft_strchrset(type, "diuxX"))
return (print);
while (print[i] == ' ')
i++;
if (print[i] == '-' || print[i] == '+')
return (print);
if (ft_strchr(s, '.') || (i == 0 && print[i] != '0'))
{
print = ft_concat_free(ft_strdup(" "), print);
*size += 1;
}
else
print[i] = ' ';
if (ft_strchr(s, '-') && print[*size - 1] == ' ')
{
print[*size] = '\0';
*size -= 1;
}
return (print);
}

View File

@@ -0,0 +1,98 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* next_word.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: hulamy <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2020/02/10 13:58:30 by hulamy #+# #+# */
/* Updated: 2020/02/26 18:24:04 by hulamy ### ########.fr */
/* */
/* ************************************************************************** */
#include "libft.h"
/*
** -placed outside of "word_length" for lake of space
** -check if there is a '*' or a number
** -usefull as such for the 'width', and after a check
** for a '.' for the 'precision' flag
*/
int width_precision(char *s)
{
int i;
i = 0;
if (ft_strchr("*", s[i]) != NULL)
i++;
while (ft_strchr("0123456789", s[i]) != NULL)
i++;
return (i);
}
/*
** -return the length of the next word to print
** -for that it got through the characters expecting
** in the following order :
** [%][flags][width][.precision][length][specifier]
** knowing that 'flags' can repeat themselves
** -a single '%' is treated as a word of length 1
** (unlike the real printf)
** -it's written :
** i += width_precision(s + i + 1) + 1;
** instead of :
** i++;
** i += width_precision(s + i);
** to save a line (3 with the brackets)
*/
int word_length(char *s)
{
int i;
i = 1;
if (s[0] == '\0')
return (0);
if (s[0] != '%')
{
while (s[i] != '%' && s[i] != '\0')
i++;
return (i);
}
while (ft_strchr("#0- +'", s[i]) != NULL)
i++;
i += width_precision(s + i);
if (ft_strchr(".", s[i]) != NULL)
i += width_precision(s + i + 1) + 1;
while (ft_strchr("hl", s[i]) != NULL)
i++;
if (ft_strchr("diuxXcspefgn%", s[i]) != NULL)
i++;
return (i);
}
/*
** -return the next sequence to be print
** (either a string, or a conversion)
** -a single '%' is an error in real printf
** but is treated as a '%' here
*/
char *next_word(char **string)
{
char *s;
char *word;
int i;
s = *string;
if (*s == '\0')
return (NULL);
if ((i = word_length(s)) < 0)
return (NULL);
word = (char *)malloc(sizeof(char) * (i + 1));
word[i] = '\0';
ft_memmove(word, s, i);
*string += i;
return (word);
}

View File

@@ -0,0 +1,162 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_printf.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: hulamy <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2020/03/12 22:31:29 by hulamy #+# #+# */
/* Updated: 2020/06/30 00:41:35 by hulamy ### ########.fr */
/* */
/* ************************************************************************** */
#include "libft.h"
/*
** SPECIFIER :
** receive a word as a string, check if it start by '%', and return the
** specifier (diuxXspefgn) and the length (h hh l ll)
** -if s is a string, or is a single '%'
** return NULL (to print is as a string)
** -if s is a double '%%', remove one '%', and
** return NULL (to print is as a string)
** -then s is a conversion, go to the length and specifier
** -copy them in 'string'
** -and remove them from s
** -return the length and specifier in a string
*/
char *specifier(char *s)
{
char *string;
int i;
if (s[0] != '%' || s[1] == '\0')
return (NULL);
if (s[1] == '%')
{
s[1] = '\0';
return (NULL);
}
i = 1;
while (ft_strchr("#0- +'0123456789.*", s[i]) != NULL)
i++;
string = ft_strdup(s + i);
while (s[i] != '\0')
{
s[i] = '\0';
i++;
}
return (string);
}
/*
** -receive 'i' the number in which '*' will expand
** -turn it into a string
** -calculate the total lentgh of the string '%...' for nbr replacing '*'
** -allocate a new string with this length
** -copy the original str with first '*' expanded into it's corresponding nbr
*/
int ft_expand_star(int nbr, char **string)
{
char *s;
char *n;
int i;
int j;
int k;
n = ft_itoa(nbr);
if (!(s = ft_memalloc(sizeof(char) * (ft_strlen(n) + ft_strlen(*string)))))
return (0);
i = -1;
j = 0;
k = 0;
while ((*string)[++i] != '\0')
{
s[j] = (*string)[i];
if (s[j] == '*')
while (n[k] != '\0')
s[j++] = n[k++];
else
j++;
}
free(n);
free(*string);
*string = s;
return (1);
}
/*
** print the string
** because of lake of space, it also free 'type'
*/
int ft_put_word(char *s, char *type, int size)
{
int i;
i = 0;
while (i < size)
write(1, &(s[i++]), 1);
free(type);
free(s);
return (i);
}
/*
** because of lake of space...
** -1 expand the specifier according to its type and its length
** and put in a string 'print'
** -2 transform 'print' according to the flags
*/
char *convert_with_flags(char *s, va_list ap, char *type, int *size)
{
char *print;
if (!(print = ft_convert(ap, type, &s)))
return (NULL);
if (!(print = ft_flag_transform(s, print, type, size)))
return (NULL);
free(s);
return (print);
}
/*
** -printf receive a string to print with a variadic number of arguments
** -it will go in a loop through each 'words'
** -a word is either a string containing no '%' or a conversion starting by '%'
** -if it's a string it's printed right away
** -if it's a conversion it will call convert_with_flags for some actions :
** -1 expand the specifier according to its type and its length
** and put in a string 'print'
** -2 transform 'print' according to the flags
*/
int ft_printf(char *string, ...)
{
char *s;
char *type;
int length;
int size;
va_list ap;
length = 0;
va_start(ap, string);
while ((s = next_word(&string)) != NULL)
{
if ((type = specifier(s)) == NULL)
length += ft_put_word(s, type, ft_strlen(s));
else
{
size = 0;
if (!(s = convert_with_flags(s, ap, type, &size)))
return (-1);
length += ft_put_word(s, type, size);
}
}
free(s);
va_end(ap);
return (length);
}