From fb078770d109c456eef93a623f14aca3e734dc43 Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Fri, 7 Apr 2023 22:23:03 +0200 Subject: [PATCH] bonus pass all tests --- .gitignore | 3 ++ .gitmodules | 2 +- Makefile | 8 ++-- ft_printf.c | 101 +++++++++++++++++++++++++++++++++++++++----------- ft_printf.h | 43 ++++++++++++++++----- ft_putchars.c | 53 +++++++++++++++++--------- ft_putnbrs.c | 38 +++++++++++-------- ft_putptr.c | 29 ++++++++++----- ft_putx.c | 52 ++++++++++++++++++-------- libft | 2 +- main.c | 8 ++++ opts.c | 87 +++++++++++++++++++++++++++++++++++++++++++ utils.c | 57 ++++++++++++++++++++++++++++ 13 files changed, 387 insertions(+), 96 deletions(-) create mode 100644 main.c create mode 100644 opts.c create mode 100644 utils.c diff --git a/.gitignore b/.gitignore index cd531cf..c2ca3cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +ft_printf_tester + + # ---> C # Prerequisites *.d diff --git a/.gitmodules b/.gitmodules index 83b9355..409b820 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "libft"] path = libft - url = git@45.76.46.66:narnaud/libft.git + url = git@narnaud.net:nicolas-arnaud/libft.git diff --git a/Makefile b/Makefile index 30c0e10..a9a8b0a 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,7 @@ NAME = libftprintf.a -SRCS = ft_printf.c ft_putchars.c ft_putnbrs.c ft_putptr.c ft_putx.c +SRCS = ft_printf.c ft_putchars.c ft_putnbrs.c ft_putptr.c ft_putx.c utils.c opts.c OBJS = ${SRCS:.c=.o} -MAIN = main.c -MAIN_O = ${MAIN:.c=.o} RM = rm -rf CC = gcc @@ -11,10 +9,12 @@ CFLAGS = -Werror -Wall -Wextra AR = ar -rcs .c.o: - ${CC} ${CFLAGS} -c $< -o ${<:.c=.o} + ${CC} ${CFLAGS} -c $< -o ${<:.c=.o} -g all: $(NAME) +bonus: + $(NAME): $(OBJS) ${MAKE} -C ./libft cp ./libft/libft.a libftprintf.a diff --git a/ft_printf.c b/ft_printf.c index cff61af..7c0ad08 100644 --- a/ft_printf.c +++ b/ft_printf.c @@ -10,30 +10,87 @@ /* */ /* ************************************************************************** */ -#include "./libft/libft.h" #include "ft_printf.h" -int ft_printf(const char *str, ...) +#include "./libft/libft.h" + +int handle_options(va_list args, const char *str, t_opts *opts) +{ + while (*str && !ft_strchr("cspdiuxX%", *str)) { + if (*str == '-') opts->minus = 1; + else if (*str == '0') opts->zero = 1; + else if (*str == '#') opts->hash = 1; + else if (*str == ' ') opts->space = 1; + else if (*str == '+') opts->plus = 1; + else if (*str == '.') opts->dot = 1; + else if (ft_isdigit(*str)) + { + if (opts->dot) opts->precision = ft_atoi(str); + else opts->width = ft_atoi(str); + while (ft_isdigit(*str)) { + str++; + opts->len++; + } + continue; + } else if (*str == '*') + { + if (opts->dot) opts->precision = va_arg(args, int); + else opts->width = va_arg(args, int); + } else return (0); + str++; + opts->len++; + } + return (1); +} + +int handle_functions(va_list args, const char *str, t_opts *opts) +{ + size_t n = 0; + size_t ret = 0; + const char *g_types = {"cspdiuxX%"}; + static int (*g_printf_fcts[9])(va_list arg, const char *str, t_opts *opts) = { + va_print_char, va_print_str, va_print_ptr, va_print_nbr, va_print_nbr, + va_print_unsign, va_print_x, va_print_x_cap, va_print_perc}; + while (g_types[n] && g_types[n] != *str) + n++; + if (g_types[n]) { + if (opts->minus) opts->zero = 0; + if (opts->precision > 0) opts->zero = 0; + if (opts->width < 0) + { + opts->minus = 1; + opts->width *= -1; + } + if (opts->precision < 0) + opts->dot = 0; + ret += (g_printf_fcts[n])(args, str, opts); + } + return ret; +} + +int ft_printf(const char *str, ...) { - va_list args; - size_t n; - size_t i; - const char *g_types = {"cspdiuxX%"}; - static int (*g_printf_fcts[9])(va_list arg, const char *str) = {\ - va_putchar, va_putstr, va_putptr, va_putnbr, va_putnbr, va_putunsign, \ - va_putx, va_putx_cap, va_putperc}; + va_list args; + size_t i; + t_opts opts; - i = 0; - va_start (args, str); - while (*str) - { - n = -1; - if ((*str == '%' && str++) || !(++i && ft_putchar((int)*str))) - while (++n < 9) - if (g_types[n] == *str) - i += (g_printf_fcts[n])(args, str); - str++; - } - va_end(args); - return (i); + i = 0; + va_start(args, str); + while (*str) + { + if (*str == '%' && str++) + { + opts = (t_opts){0}; + if (handle_options(args, str, &opts)) + { + str += opts.len; + i += handle_functions(args, str, &opts); + } + } + else if (++i) + ft_putchar_fd(*str, 1); + str++; + } + va_end(args); + return (i); } diff --git a/ft_printf.h b/ft_printf.h index 1987d43..c32a226 100644 --- a/ft_printf.h +++ b/ft_printf.h @@ -18,16 +18,39 @@ # include "./libft/libft.h" # include -int ft_putchar(int ch); -int ft_putstr(char *str); -int va_putchar(va_list va_ch, const char *str); -int va_putstr(va_list va_str, const char *str); -int va_putptr(va_list va_ptr, const char *str); -int va_putnbr(va_list va_int, const char *str); -int va_putunsign(va_list va_uint, const char *str); -int va_putx(va_list va_uint, const char *str); -int va_putx_cap(va_list va_uint, const char *str); -int va_putperc(va_list va, const char *str); + +typedef struct s_opts { + int len; + int width; + int precision; + int zero; + int minus; + int dot; + int hash; + int space; + int plus; +} t_opts; + +char *int_opts_transform(int n, char *nbr, t_opts *opts); +char *uint_opts_transform(unsigned int n, char *nbr, t_opts *opts); +char *ptr_opts_transform(char *ptr, t_opts *opts); +char *str_opts_transform(char *str, t_opts *opts); +char *ft_append(char *s1, char *s2); +char *ft_zero_fill(char *nbr, char c, t_opts *opts); +char *ft_strnew(int n, char c); + +int ft_putnstr(char *str, int n); + +int ft_print_char(int ch, t_opts *opts); +int ft_print_str(char *str, t_opts *opts); +int va_print_char(va_list va_ch, const char *str, t_opts *opts); +int va_print_str(va_list va_str, const char *str, t_opts *opts); +int va_print_ptr(va_list va_ptr, const char *str, t_opts *opts); +int va_print_nbr(va_list va_int, const char *str, t_opts *opts); +int va_print_unsign(va_list va_uint, const char *str, t_opts *opts); +int va_print_x(va_list va_uint, const char *str, t_opts *opts); +int va_print_x_cap(va_list va_uint, const char *str, t_opts *opts); +int va_print_perc(va_list va, const char *str, t_opts *opts); int ft_printf(const char *str, ...); #endif diff --git a/ft_putchars.c b/ft_putchars.c index 7845979..a132153 100644 --- a/ft_putchars.c +++ b/ft_putchars.c @@ -12,47 +12,64 @@ #include "ft_printf.h" -int ft_putchar(int ch) +int ft_print_char(int ch, t_opts *opts) { char c; + int ret; c = (char)ch; - write(1, &c, 1); - return (1); + ret = 1; + if (opts->minus) + { + ft_putchar_fd(c, 1); + while (opts->width-- > 1 && ++ret) + ft_putchar_fd(' ', 1); + } + else + { + while (opts->width-- > 1 && ++ret) + ft_putchar_fd(' ', 1); + ft_putchar_fd(c, 1); + } + return (ret); } -int ft_putstr(char *str) +int ft_print_str(char *str, t_opts *opts) { int i; + char *formated; i = 0; - if (!str) - { - ft_putstr("(null)"); - return (6); - } - while (str[i]) - ft_putchar(str[i++]); + if (!str) + { + if (!opts->dot || opts->precision >= 6) + str = "(null)"; + else + str = ""; + } + formated = str_opts_transform(str, opts); + while (formated[i]) + ft_putchar_fd(formated[i++], 1); + free(formated); return (i); } -int va_putchar(va_list va_ch, const char *str) +int va_print_char(va_list va_ch, const char *str, t_opts *opts) { (void)*str; - ft_putchar(va_arg(va_ch, int)); - return (1); + return (ft_print_char(va_arg(va_ch, int), opts)); } -int va_putstr(va_list va_str, const char *str) +int va_print_str(va_list va_str, const char *str, t_opts *opts) { (void)*str; - return (ft_putstr(va_arg(va_str, char *))); + return (ft_print_str(va_arg(va_str, char *), opts)); } -int va_putperc(va_list va, const char *str) +int va_print_perc(va_list va, const char *str, t_opts *opts) { (void)*str; (void)va; - ft_putchar('%'); + ft_print_char('%', opts); return (1); } diff --git a/ft_putnbrs.c b/ft_putnbrs.c index 8e4dfe6..30c06fd 100644 --- a/ft_putnbrs.c +++ b/ft_putnbrs.c @@ -1,7 +1,7 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* ft_putnbrs.c :+: :+: :+: */ +/* ft_print_nbrs.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: narnaud +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ @@ -12,36 +12,44 @@ #include "ft_printf.h" -int ft_putnbr(int n, const char *str) +int ft_print_nbr(int n, const char *str, t_opts *opts) { - char *n_str; + char *nbr; + char *raw; int ret; (void)*str; - n_str = ft_itoa(n); - ret = ft_putstr(n_str); - free(n_str); + raw = ft_itoa(n); + nbr = int_opts_transform(n, raw, opts); + opts->dot = 0; + ret = ft_print_str(nbr, opts); + free(raw); + free(nbr); return (ret); } -int ft_putunsign(unsigned int n, const char *str) +int ft_print_unsign(unsigned int n, const char *str, t_opts *opts) { - char *n_str; + char *raw; + char *nbr; int ret; (void)*str; - n_str = ft_utoa(n); - ret = ft_putstr(n_str); - free(n_str); + raw = ft_utoa(n); + nbr = uint_opts_transform(n, raw, opts); + opts->dot = 0; + ret = ft_print_str(nbr, opts); + free(raw); + free(nbr); return (ret); } -int va_putnbr(va_list va, const char *str) +int va_print_nbr(va_list va, const char *str, t_opts *opts) { - return (ft_putnbr(va_arg(va, int), str)); + return (ft_print_nbr(va_arg(va, int), str, opts)); } -int va_putunsign(va_list va, const char *str) +int va_print_unsign(va_list va, const char *str, t_opts *opts) { - return (ft_putunsign(va_arg(va, unsigned int), str)); + return (ft_print_unsign(va_arg(va, unsigned int), str, opts)); } diff --git a/ft_putptr.c b/ft_putptr.c index d4d3386..65d9eea 100644 --- a/ft_putptr.c +++ b/ft_putptr.c @@ -1,7 +1,7 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* ft_putptr.c :+: :+: :+: */ +/* ft_print_ptr.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: narnaud +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ @@ -12,20 +12,29 @@ #include "ft_printf.h" -int ft_putptr(void *ptr) +int ft_print_ptr(void *ptr, t_opts *opts) { - char *str; + char *raw; + char *nbr; int ret; - str = ft_itox((unsigned long long int)ptr, "0123456789abcdef"); - ft_putstr("0x"); - ret = ft_putstr(str); - free(str); - return (ret + 2); + if (ptr == NULL) + raw = ft_strdup("(nil)"); + else + { + raw = ft_itox((unsigned long long int)ptr, "0123456789abcdef"); + raw = ft_append(ft_strdup("0x"), raw); + } + nbr = ptr_opts_transform(raw, opts); + opts->dot = 0; + ret = ft_print_str(nbr, opts); + free(raw); + free(nbr); + return (ret); } -int va_putptr(va_list va_ptr, const char *str) +int va_print_ptr(va_list va_ptr, const char *str, t_opts *opts) { (void)*str; - return (ft_putptr(va_arg(va_ptr, void *))); + return (ft_print_ptr(va_arg(va_ptr, void *), opts)); } diff --git a/ft_putx.c b/ft_putx.c index 7652079..381137b 100644 --- a/ft_putx.c +++ b/ft_putx.c @@ -1,7 +1,7 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* ft_putx.c :+: :+: :+: */ +/* ft_print_x.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: narnaud +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ @@ -12,36 +12,58 @@ #include "ft_printf.h" -int ft_putx(unsigned int n) +int ft_print_x(unsigned int n, t_opts *opts) { - char *str; + char *raw; + char *nbr; + char *tmp; int ret; - str = ft_itox((unsigned long int)n, "0123456789abcdef"); - ret = ft_putstr(str); - free(str); + raw = ft_itox((unsigned long int)n, "0123456789abcdef"); + if (opts->hash && n != 0) + { + tmp = raw; + raw = ft_strjoin("0x", raw); + free(tmp); + } + nbr = uint_opts_transform(n, raw, opts); + opts->dot = 0; + ret = ft_print_str(nbr, opts); + free(raw); + free(nbr); return (ret); } -int ft_putx_cap(unsigned int n) +int ft_print_x_cap(unsigned int n, t_opts *opts) { - char *str; + char *raw; + char *tmp; + char *nbr; int ret; - str = ft_itox((unsigned long int)n, "0123456789ABCDEF"); - ret = ft_putstr(str); - free(str); + raw = ft_itox((unsigned long int)n, "0123456789ABCDEF"); + if (opts->hash && n != 0) + { + tmp = raw; + raw = ft_strjoin("0X", raw); + free(tmp); + } + nbr = uint_opts_transform(n, raw, opts); + opts->dot = 0; + ret = ft_print_str(nbr, opts); + free(raw); + free(nbr); return (ret); } -int va_putx(va_list va_uint, const char *str) +int va_print_x(va_list va_uint, const char *str, t_opts *opts) { (void)*str; - return (ft_putx(va_arg(va_uint, unsigned int))); + return (ft_print_x(va_arg(va_uint, unsigned int), opts)); } -int va_putx_cap(va_list va_uint, const char *str) +int va_print_x_cap(va_list va_uint, const char *str, t_opts *opts) { (void)*str; - return (ft_putx_cap(va_arg(va_uint, unsigned int))); + return (ft_print_x_cap(va_arg(va_uint, unsigned int), opts)); } diff --git a/libft b/libft index 0ba7ffd..840a269 160000 --- a/libft +++ b/libft @@ -1 +1 @@ -Subproject commit 0ba7ffd7c6a28b0f02cc937d32773fb9d4095eca +Subproject commit 840a26935181c35cd8416853f1aad9a0bf99621f diff --git a/main.c b/main.c new file mode 100644 index 0000000..ce0e077 --- /dev/null +++ b/main.c @@ -0,0 +1,8 @@ +#include "ft_printf.h" + + +int main(void) +{ + ft_printf("%.4s\n", "Hello world!\n"); + return 0; +} diff --git a/opts.c b/opts.c new file mode 100644 index 0000000..432cbf7 --- /dev/null +++ b/opts.c @@ -0,0 +1,87 @@ +#include "ft_printf.h" + +char *int_opts_transform(int n, char *nbr, t_opts *opts) +{ + if (opts->plus && n>=0) + nbr = ft_strjoin("+", nbr); + else if (opts->space && n>=0) + nbr = ft_strjoin(" ", nbr); + else if (opts->precision == 0 && opts->dot && n == 0 && + opts->len) + nbr = ft_strdup(""); + else + nbr = ft_strdup(nbr); + + if (opts->precision > 0) + nbr = ft_append(ft_zero_fill(nbr, '0', opts), nbr); + else if (opts->zero && !opts->dot) + nbr = ft_append(ft_zero_fill(nbr, '0', opts), nbr); + + return (nbr); +} + +char *uint_opts_transform(unsigned int n, char *nbr, t_opts *opts) +{ + if (opts->plus) + nbr = ft_strjoin("+", nbr); + else if (opts->space) + nbr = ft_strjoin(" ", nbr); + else if (opts->precision == 0 && opts->dot && n == 0 && + opts->len) + nbr = ft_strdup(""); + else + nbr = ft_strdup(nbr); + + if (opts->precision > 0) + nbr = ft_append(ft_zero_fill(nbr, '0', opts), nbr); + else if (opts->zero && !opts->dot) + nbr = ft_append(ft_zero_fill(nbr, '0', opts), nbr); + + return (nbr); +} + +char *ptr_opts_transform(char *nbr, t_opts *opts) +{ + if (opts->plus) + nbr = ft_strjoin("+", nbr); + else if (opts->space) + nbr = ft_strjoin(" ", nbr); + else if (opts->precision == 0 && opts->dot && + opts->len) + nbr = ft_strdup(""); + else + nbr = ft_strdup(nbr); + + if (opts->precision > 0) + nbr = ft_append(ft_zero_fill(nbr, '0', opts), nbr); + else if (opts->zero && !opts->dot) + nbr = ft_append(ft_zero_fill(nbr, '0', opts), nbr); + + return (nbr); +} + +char *str_opts_transform(char *str, t_opts *opts) +{ + int len; + char *tmp = NULL; + char *sub = NULL; + + if (opts->dot) + sub = ft_substr(str, 0, opts->precision); + if (sub) + str = sub; + len = opts->width - (int)ft_strlen(str); + tmp = ft_strnew(len, ' '); + if (!opts->minus && len > 0) + str = ft_strjoin(tmp, str); + else if (opts->minus && len > 0) + str = ft_strjoin(str, tmp); + else + str = ft_strdup(str); + if (tmp) + free(tmp); + if (sub) + free(sub); + + return (str); +} diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..8c8d0a3 --- /dev/null +++ b/utils.c @@ -0,0 +1,57 @@ +#include "ft_printf.h" + +char *ft_strnew(int n, char c) +{ + char *str = NULL; + + if (n < 0) + return (NULL); + str = malloc(n + 1); + if (!str) + return (NULL); + str[n] = '\0'; + while (--n >= 0) + str[n] = c; + return (str); +} + +char *ft_zero_fill(char *nbr, char c, t_opts *opts) +{ + int len; + char *fill = NULL; + + if (opts->zero) + len = opts->width - ft_strlen(nbr); + else if (opts->dot) + len = opts->precision - ft_strlen(nbr); + else + return (NULL); + + if (len < 0 || (opts->zero && len == 0)) + return (NULL); + + if ((nbr[0] == '-' || nbr[0] == '+' || nbr[0] == ' ') && opts->dot) + fill = ft_strnew(len + 1, c); + else + fill = ft_strnew(len , c); + + if (nbr[0] == '-' || nbr[0] == '+' || nbr[0] == ' ') + { + fill[0] = nbr[0]; + nbr[0] = '0'; + } + + return (fill); +} + +char *ft_append(char *s1, char *s2) { + char *ret = NULL; + if (!s1) + return (s2); + if (!s2) + return (s1); + ret = ft_strjoin(s1, s2); + free(s1); + free(s2); + return (ret); +}