From d4fb94642887fa63e8f65395bc745495d4b76053 Mon Sep 17 00:00:00 2001 From: gbaconni Date: Sun, 24 Apr 2022 00:40:01 +0200 Subject: [PATCH] Improve main by implementing fmtsplit to split format into chunks and pass function pointer to compare ft_printf with printf --- Makefile | 6 +- libftprintf/Makefile | 3 +- libftprintf/ft_printf.c | 2 +- libftprintf/ft_putchar.c | 3 +- libftprintf/ft_skipchars.c | 35 ++++ libftprintf/ft_vprintf.c | 21 +- libftprintf/ft_vprintf_escape.c | 83 ++++++-- libftprintf/ft_vprintf_other.c | 8 +- libftprintf/ft_vprintf_percent.c | 25 ++- libftprintf/libftprintf.h | 4 +- main.c | 317 +++++++++---------------------- 11 files changed, 236 insertions(+), 271 deletions(-) create mode 100644 libftprintf/ft_skipchars.c diff --git a/Makefile b/Makefile index 9774990..5c9d0dd 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2022/01/18 15:11:16 by gbaconni #+# #+# # -# Updated: 2022/04/18 09:07:48 by gbaconni ### lausanne.ch # +# Updated: 2022/04/23 21:57:08 by gbaconni ### lausanne.ch # # # # **************************************************************************** # # @@ -100,6 +100,7 @@ test: clean $(NAME) @$(PREFIX) ./$(NAME) "%p" "\n" || true @$(PREFIX) ./$(NAME) "Forty Two" "" || true @$(PREFIX) ./$(NAME) "\t\r\n" "" || true + @$(PREFIX) ./$(NAME) "%1d" 42 || true test2: leak @$(MAKE) test LEAK=1 @@ -110,6 +111,9 @@ test3: debug test4: fast @$(MAKE) test FAST=1 +test42: clean $(NAME) + @$(PREFIX) ./$(NAME) "Hello World %% %44s %d %c %x %p" "Lausanne" 42 C 66 "C" || true + doc: @curl -s -L -z fr.subject.pdf -o fr.subject.pdf $(PDF_FR) @curl -s -L -z en.subject.pdf -o en.subject.pdf $(PDF_EN) diff --git a/libftprintf/Makefile b/libftprintf/Makefile index 831109a..e580144 100644 --- a/libftprintf/Makefile +++ b/libftprintf/Makefile @@ -6,7 +6,7 @@ # By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2022/01/18 15:11:16 by gbaconni #+# #+# # -# Updated: 2022/04/18 00:28:09 by gbaconni ### lausanne.ch # +# Updated: 2022/04/23 23:52:03 by gbaconni ### lausanne.ch # # # # **************************************************************************** # # @@ -30,6 +30,7 @@ SRC = \ $(LIBFT)/ft_calloc.c \ $(LIBFT)/ft_strlen.c \ $(LIBFT)/ft_itoa.c \ + ft_skipchars.c \ ft_strrev.c \ ft_ltoa_base.c \ ft_putchar.c \ diff --git a/libftprintf/ft_printf.c b/libftprintf/ft_printf.c index ba853d0..8c39a9b 100644 --- a/libftprintf/ft_printf.c +++ b/libftprintf/ft_printf.c @@ -6,7 +6,7 @@ /* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/01/18 16:17:58 by gbaconni #+# #+# */ -/* Updated: 2022/04/16 03:07:52 by gbaconni ### lausanne.ch */ +/* Updated: 2022/04/24 00:23:02 by gbaconni ### lausanne.ch */ /* */ /* ************************************************************************** */ diff --git a/libftprintf/ft_putchar.c b/libftprintf/ft_putchar.c index beedaf3..dae1f8f 100644 --- a/libftprintf/ft_putchar.c +++ b/libftprintf/ft_putchar.c @@ -6,7 +6,7 @@ /* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/04/16 00:05:56 by gbaconni #+# #+# */ -/* Updated: 2022/04/16 00:27:53 by gbaconni ### lausanne.ch */ +/* Updated: 2022/04/24 00:08:55 by gbaconni ### lausanne.ch */ /* */ /* ************************************************************************** */ @@ -16,7 +16,6 @@ int ft_putchar(int c) { int ret; - ret = 0; ret = write(1, &c, 1); return (ret); } diff --git a/libftprintf/ft_skipchars.c b/libftprintf/ft_skipchars.c new file mode 100644 index 0000000..ff4120a --- /dev/null +++ b/libftprintf/ft_skipchars.c @@ -0,0 +1,35 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* ft_skipchars.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2022/04/23 23:49:26 by gbaconni #+# #+# */ +/* Updated: 2022/04/24 00:00:43 by gbaconni ### lausanne.ch */ +/* */ +/* ************************************************************************** */ + +#include "libftprintf.h" + +int ft_skipchars(const char *s, char *chars) +{ + int ret; + int i; + int hits; + + ret = 0; + while (*s != '\0') + { + i = 0; + hits = 0; + while (chars[i] != '\0') + hits += (chars[i++] == *s); + if (hits > 0) + ret++; + else + break ; + s++; + } + return (ret); +} diff --git a/libftprintf/ft_vprintf.c b/libftprintf/ft_vprintf.c index d4b084e..ba052ee 100644 --- a/libftprintf/ft_vprintf.c +++ b/libftprintf/ft_vprintf.c @@ -6,7 +6,7 @@ /* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/01/20 11:43:52 by gbaconni #+# #+# */ -/* Updated: 2022/04/18 09:01:19 by gbaconni ### lausanne.ch */ +/* Updated: 2022/04/24 00:36:07 by gbaconni ### lausanne.ch */ /* */ /* ************************************************************************** */ @@ -14,18 +14,21 @@ int ft_vprintf(char const *format, va_list ap) { - int ret; + int ret; + const char *fmt; ret = 0; - while (*format != 0) + fmt = format; + while (*fmt != 0) { - if (*format == '%') - ret += ft_vprintf_percent(++format, ap); - else if (*format == '\\') - ret += ft_vprintf_escape(++format, ap); + if (*fmt == '%') + { + fmt++; + ret += ft_vprintf_percent(fmt, ap); + } else - ret += ft_vprintf_other(format, ap); - format++; + ret += ft_vprintf_other(fmt, ap); + fmt++; } return (ret); } diff --git a/libftprintf/ft_vprintf_escape.c b/libftprintf/ft_vprintf_escape.c index 1551e0d..62fd13a 100644 --- a/libftprintf/ft_vprintf_escape.c +++ b/libftprintf/ft_vprintf_escape.c @@ -6,34 +6,79 @@ /* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/04/17 22:35:03 by gbaconni #+# #+# */ -/* Updated: 2022/04/17 23:08:35 by gbaconni ### lausanne.ch */ +/* Updated: 2022/04/23 23:37:55 by gbaconni ### lausanne.ch */ /* */ /* ************************************************************************** */ #include "libftprintf.h" +static char ft_unescape_char(const char c); +static size_t ft_unescape_len(const char *str); + int ft_vprintf_escape(const char *format, va_list ap) { int ret; (void) ap; - if (*format == '0') - ret = ft_putchar('\0'); - if (*format == 'a') - ret = ft_putchar('\a'); - else if (*format == 'b') - ret = ft_putchar('\b'); - else if (*format == 't') - ret = ft_putchar('\t'); - else if (*format == 'n') - ret = ft_putchar('\n'); - else if (*format == 'v') - ret = ft_putchar('\v'); - else if (*format == 'f') - ret = ft_putchar('\f'); - else if (*format == 'r') - ret = ft_putchar('\r'); - else if (*format == 'e') - ret = ft_putchar('\033'); + ret = ft_putchar(ft_unescape_char(*format)); return (ret); } + +char *ft_unescape(const char *str) +{ + char *s; + void *ptr; + + s = (char *) ft_calloc(ft_unescape_len(str) + 1, sizeof(char)); + if (s == NULL) + return (NULL); + ptr = s; + while (*str != '\0') + { + if (*str == '\\') + *s++ = ft_unescape_char(*++str); + else + *s++ = *str; + str++; + } + *s = '\0'; + s = ptr; + return (s); +} + +static char ft_unescape_char(const char c) +{ + if (c == 'a') + return ('\a'); + else if (c == 'b') + return ('\b'); + else if (c == 't') + return ('\t'); + else if (c == 'n') + return ('\n'); + else if (c == 'v') + return ('\v'); + else if (c == 'f') + return ('\f'); + else if (c == 'r') + return ('\r'); + else if (c == 'e') + return ('\033'); + else + return (c); +} + +static size_t ft_unescape_len(const char *str) +{ + size_t len; + + len = 0; + while (*str != '\0') + { + if (*str == '\\') + str++; + len++; + str++; + } + return (len); +} diff --git a/libftprintf/ft_vprintf_other.c b/libftprintf/ft_vprintf_other.c index d87ebab..69c8715 100644 --- a/libftprintf/ft_vprintf_other.c +++ b/libftprintf/ft_vprintf_other.c @@ -6,7 +6,7 @@ /* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/01/20 12:58:03 by gbaconni #+# #+# */ -/* Updated: 2022/04/17 22:39:45 by gbaconni ### lausanne.ch */ +/* Updated: 2022/04/24 00:34:40 by gbaconni ### lausanne.ch */ /* */ /* ************************************************************************** */ @@ -14,9 +14,11 @@ int ft_vprintf_other(const char *format, va_list ap) { - int ret; + int ret; + char c; (void) ap; - ret = ft_putchar(*format); + c = *format; + ret = ft_putchar(c); return (ret); } diff --git a/libftprintf/ft_vprintf_percent.c b/libftprintf/ft_vprintf_percent.c index b395a04..a16ef92 100644 --- a/libftprintf/ft_vprintf_percent.c +++ b/libftprintf/ft_vprintf_percent.c @@ -6,7 +6,7 @@ /* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/01/20 11:55:58 by gbaconni #+# #+# */ -/* Updated: 2022/04/17 22:40:01 by gbaconni ### lausanne.ch */ +/* Updated: 2022/04/24 00:29:57 by gbaconni ### lausanne.ch */ /* */ /* ************************************************************************** */ @@ -14,19 +14,24 @@ int ft_vprintf_percent(const char *format, va_list ap) { - int ret; + const char *fmt; + int ret; + char c; - if (*format == '%') - ret = ft_vprintf_other(format, ap); - else if (*format == 'c') + ret = 0; + fmt = format + 1; + c = *(fmt + ft_skipchars(fmt, "0123456789# +")); + if (c == 'c') ret = ft_vprintf_char(format, ap); - else if (*format == 's') + else if (c == 's') ret = ft_vprintf_string(format, ap); - else if (*format == 'p') + else if (c == 'p') ret = ft_vprintf_pointer(format, ap); - else if (*format == 'd' || *format == 'i' || *format == 'u') - ret = ft_vprintf_decimal(format, ap); - else if (*format == 'x' || *format == 'X') + else if (c == 'x' || c == 'X') ret = ft_vprintf_hexadecimal(format, ap); + else if (c == 'd' || c == 'i' || c == 'u') + ret = ft_vprintf_decimal(format, ap); + else + ret = ft_vprintf_other(format, ap); return (ret); } diff --git a/libftprintf/libftprintf.h b/libftprintf/libftprintf.h index 545bc5c..29e2d3d 100644 --- a/libftprintf/libftprintf.h +++ b/libftprintf/libftprintf.h @@ -6,7 +6,7 @@ /* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/01/18 15:26:06 by gbaconni #+# #+# */ -/* Updated: 2022/04/18 00:26:16 by gbaconni ### lausanne.ch */ +/* Updated: 2022/04/24 00:00:59 by gbaconni ### lausanne.ch */ /* */ /* ************************************************************************** */ @@ -25,10 +25,12 @@ /* Helper */ +int ft_skipchars(const char *s, char *chars); char *ft_strrev(char *s); char *ft_ltoa_base(long n, char *base); int ft_putchar(int c); int ft_puts(const char *s); +char *ft_unescape(const char *str); /* Mandatory */ diff --git a/main.c b/main.c index 4809a6e..47d3323 100644 --- a/main.c +++ b/main.c @@ -3,39 +3,85 @@ /* ::: :::::::: */ /* main.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: baco +#+ +:+ +#+ */ +/* By: gbaconni@student.42lausanne.ch +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/04/13 06:58:46 by gbaconni #+# #+# */ -/* Updated: 2022/04/18 09:12:07 by gbaconni ### lausanne.ch */ +/* Updated: 2022/04/24 00:21:23 by gbaconni ### lausanne.ch */ /* */ /* ************************************************************************** */ #include // printf -#include // va_list, va_start, va_end -#include // write #include // strlen -#include // malloc, free #include // isdigit #include // assert -#include -#include -#include -#include -#include // wait #include "libftprintf/libftprintf.h" -void ft_begin(int *fd) +char *ft_fmtsplit(char **fmt) { + char *format; + char *start; + char *end; + int len; + + format = NULL; + start = *fmt; + end = *fmt; + if (start == NULL) + return (NULL); + if (*end == '%') + if (*end++ == '%') + end++; + while (*end != '\0' && *end != '%') + end++; + len = end - start; + format = (char *) calloc(len + 1, sizeof(char)); + if (format == NULL) + return (NULL); + strncpy(format, start, len); + if (*end == '\0') + *fmt = NULL; + else + *fmt += len; + return (format); +} + +int _printf(int (*f)(const char *restrict, ...), \ + char *format, char *arg) +{ + int ret; + char c; + + ret = 0; + c = *(format + 1 + ft_skipchars(format + 1, "0123456789# +")); + if (c == 'c') + ret = (*f)(format, *arg); + else if (c == 's') + ret = (*f)(format, arg); + else if (c == 'p') + ret = (*f)(format, &arg); + else if (c == 'x' || c == 'X') + ret = (*f)(format, atol(arg)); + else if (c == 'd' || c == 'i' || c == 'u') + ret = (*f)(format, atoi(arg)); + else + ret = (*f)(format); + return (ret); +} + +int _sprintf(int (*f)(const char *restrict, ...), \ + char *str, char *format, char *arg) +{ + int ret; + char c; + int fd[3]; + + ret = 0; + setbuf(stdout, NULL); pipe(fd); fd[2] = dup(STDOUT_FILENO); dup2(fd[1], STDOUT_FILENO); -} - -void ft_end(int *fd, char *str) -{ - char c; - + ret = _printf((*f), format, arg); dup2(fd[2], STDOUT_FILENO); fflush(stdout); close(fd[1]); @@ -43,222 +89,45 @@ void ft_end(int *fd, char *str) *str++ = c; *str = '\0'; close(fd[0]); + return (ret); } -void ft_begin2(char *out) +int assert_printf(char *format, char *arg) { - freopen("/dev/null", "a", stdout); - setbuf(stdout, out); -} - -void ft_end2(void) -{ - freopen("/dev/tty", "a", stdout); -} - -int ft_sprintf(char *str, const char *format, ...) -{ - va_list ap; - int ret; - int state; - char c; - pid_t cpid; - int pipefd[3]; - const int piperead = 0; - const int pipewrite = 1; - const int pipestdout = 2; - - ret = 0; - pipe(pipefd); - cpid = fork(); - if (cpid == 0) - { - close(pipefd[piperead]); - pipefd[pipestdout] = dup(STDOUT_FILENO); - dup2(pipefd[pipewrite], STDOUT_FILENO); - va_start(ap, format); - ret = ft_vprintf(format, ap); - va_end(ap); - fflush(stdout); - dup2(pipefd[pipestdout], STDOUT_FILENO); - close(pipefd[pipestdout]); - close(pipefd[pipewrite]); - exit (ret); - } else { - close(pipefd[pipewrite]); - while (read(pipefd[piperead], &c, 1) > 0) - *str++ = c; - close(pipefd[piperead]); - wait(&state); - return (WEXITSTATUS(state)); - } -} - -size_t ft_unescape_len(const char *str) -{ - size_t len; - - len = 0; - while (*str != '\0') - { - if (*str == '\\') - str++; - len++; - str++; - } - return (len); -} - -char ft_unescape_char(const char c) -{ - if (c == 'a') - return ('\a'); - else if (c == 'b') - return ('\b'); - else if (c == 't') - return ('\t'); - else if (c == 'n') - return ('\n'); - else if (c == 'v') - return ('\v'); - else if (c == 'f') - return ('\f'); - else if (c == 'r') - return ('\r'); - else if (c == 'e') - return ('\033'); - else - return (c); -} - -char *ft_unescape(const char *str) -{ - char *s; - void *ptr; - - s = (char *) ft_calloc(ft_unescape_len(str) + 1, sizeof(char)); - if (s == NULL) - return (NULL); - ptr = s; - while (*str != '\0') - { - if (*str == '\\') - *s++ = ft_unescape_char(*++str); - else - *s++ = *str; - str++; - } - *s = '\0'; - s = ptr; - return (s); -} - -int main(int argc, char *argv[]) -{ - int ft_ret; int ret; + int ft_ret; char out[256]; char ft_out[256]; - char *format; - char *f; - int d; - char c; - char *s; - int x; - void *ptr; - int fd[3]; - d = 0; - c = '\0'; - s = ""; - x = 42; - ptr = &x; - (void)s; - if (argc > 1) + ret = _sprintf(printf, out, format, arg); + printf("%d = printf(\"%s\", '%s')\n%s\n", ret, format, arg, out); + ft_ret = _sprintf(ft_printf, ft_out, format, arg); + printf("%d = ft_printf(\"%s\", '%s')\n%s\n\n", ft_ret, format, arg, ft_out); + assert(ret == ft_ret); + assert(strcmp(out, ft_out) == 0); + return (ret); +} + +int main(int args, char *argv[]) +{ + char *fmt; + char *format; + char *arg; + + argv++; + if (--args < 1) + return (127); + fmt = *argv++; + format = ft_fmtsplit(&fmt); + while (format != NULL) { - f = argv[1]; - format = ft_unescape(f); - if (format[0] == '%') - { - if (format[1] == 'c') - { - c = argv[2][0]; - ret = sprintf(out, format, c); - printf("%d = printf(\"%s\", '%c')\n%s\n", ret, f, c, out); - ft_begin(fd); - ft_ret = ft_printf(format, c); - ft_end(fd, ft_out); - printf("%d = ft_printf(\"%s\", '%c')\n%s\n\n", ft_ret, f, c, ft_out); - assert(ret == ft_ret); - assert(strcmp(out, ft_out) == 0); - } - else if (format[1] == 's') - { - s = argv[2]; - ret = sprintf(out, format, s); - printf("%d = printf(\"%s\", \"%s\")\n%s\n", ret, f, s, out); - ft_begin(fd); - ft_ret = ft_printf(format, s); - ft_end(fd, ft_out); - printf("%d = ft_printf(\"%s\", \"%s\")\n%s\n\n", ft_ret, f, s, ft_out); - assert(ret == ft_ret); - assert(strcmp(out, ft_out) == 0); - } - else if (format[1] == 'p') - { - s = argv[2]; - if (ft_strlen(s) == 0) - { - s = NULL; - ptr = NULL; - } - ret = sprintf(out, format, ptr); - printf("%d = printf(\"%s\", %p)\n%s\n", ret, f, ptr, out); - ft_begin(fd); - ft_ret = ft_printf(format, ptr); - ft_end(fd, ft_out); - printf("%d = ft_printf(\"%s\", %p)\n%s\n\n", ft_ret, f, ptr, ft_out); - assert(ret == ft_ret); - assert(strcmp(out, ft_out) == 0); - } - else if (format[1] == 'd' || format[1] == 'i' || format[1] == 'u') - { - d = atoi(argv[2]); - ret = sprintf(out, format, d); - printf("%d = printf(\"%s\", %d)\n%s\n", ret, f, d, out); - ft_begin(fd); - ft_ret = ft_printf(format, d); - ft_end(fd, ft_out); - printf("%d = ft_printf(\"%s\", %d)\n%s\n\n", ft_ret, f, d, ft_out); - assert(ret == ft_ret); - assert(strcmp(out, ft_out) == 0); - } - else if (format[1] == 'x' || format[1] == 'X') - { - d = atoi(argv[2]); - ret = sprintf(out, format, d); - printf("%d = printf(\"%s\", %d)\n%s\n", ret, f, d, out); - ft_begin(fd); - ft_ret = ft_printf(format, d); - ft_end(fd, ft_out); - printf("%d = ft_printf(\"%s\", %d)\n%s\n\n", ft_ret, f, d, ft_out); - assert(ret == ft_ret); - assert(strcmp(out, ft_out) == 0); - } - } - else - { - s = argv[2]; - ret = sprintf(out, format, s); - printf("%d = printf(\"%s\", \"%s\")\n%s\n", ret, f, s, out); - ft_begin(fd); - ft_ret = ft_printf(format, s); - ft_end(fd, ft_out); - printf("%d = ft_printf(\"%s\", \"%s\")\n%s\n\n", ft_ret, f, s, ft_out); - assert(ret == ft_ret); - assert(strcmp(out, ft_out) == 0); - } + if (*format == '%' && *(format + 1) != '%' && --args) + arg = *argv++; + else + arg = NULL; + assert_printf(format, arg); free(format); + format = ft_fmtsplit(&fmt); } return (0); }