diff options
Diffstat (limited to 'graphs/piscine/tinyprintf')
| -rw-r--r-- | graphs/piscine/tinyprintf/Makefile | 17 | ||||
| -rw-r--r-- | graphs/piscine/tinyprintf/src/tinyprintf.c | 251 | ||||
| -rw-r--r-- | graphs/piscine/tinyprintf/src/tinyprintf.h | 15 | ||||
| -rw-r--r-- | graphs/piscine/tinyprintf/tests/tests.c | 213 |
4 files changed, 496 insertions, 0 deletions
diff --git a/graphs/piscine/tinyprintf/Makefile b/graphs/piscine/tinyprintf/Makefile new file mode 100644 index 0000000..6a07d90 --- /dev/null +++ b/graphs/piscine/tinyprintf/Makefile @@ -0,0 +1,17 @@ +CC=gcc +CFLAGS=-std=c99 -Wall -Wextra -Werror -Wvla -pedantic +LDLIBS=-lcriterion + +all: src/tinyprintf.o + +check: src/tinyprintf.o + $(CC) $(CFLAGS) -o tinytests src/tinyprintf.o tests/tests.c $(LDLIBS) + ./tinytests + +src/tinyprintf.o: src/tinyprintf.c + $(CC) $(CFLAGS) -c -o src/tinyprintf.o src/tinyprintf.c + +.PHONY: clean + +clean: + rm src/tinyprintf.o tinytests diff --git a/graphs/piscine/tinyprintf/src/tinyprintf.c b/graphs/piscine/tinyprintf/src/tinyprintf.c new file mode 100644 index 0000000..d005db7 --- /dev/null +++ b/graphs/piscine/tinyprintf/src/tinyprintf.c @@ -0,0 +1,251 @@ +#include "tinyprintf.h" + +#include <stdio.h> +#include <stdlib.h> + +int tinyprintf(const char *format, ...) +{ + if (format == NULL || *format == '\0') + { + return 0; + } + + va_list ap; + va_start(ap, format); + int res = 0; + + size_t i = 0; + while (format[i]) + { + if (format[i] != '%') + { + putchar(format[i]); + res++; + } + else + { + dispatch(format[i + 1], ap, &res); + format++; + } + format++; + } + va_end(ap); + return res; +} + +void dispatch(char c, va_list ap, int *res) +{ + switch (c) + { + case '%': + putchar('%'); + (*res)++; + break; + case 'd': + handle_d(va_arg(ap, int), res); + break; + case 'u': + handle_u(va_arg(ap, unsigned int), res); + break; + case 'x': + handle_x(va_arg(ap, unsigned int), res); + break; + case 'o': + handle_o(va_arg(ap, unsigned int), res); + break; + case 'c': + putchar(va_arg(ap, int)); + (*res)++; + break; + case 's': + handle_s(va_arg(ap, char *), res); + break; + default: + putchar('%'); + putchar(c); + *res += 2; + break; + } +} + +void handle_d(int val, int *res) +{ + if (val < 0) + { + putchar('-'); + (*res)++; + val = -val; + } + + if (val == 0) + { + putchar('0'); + (*res)++; + } + + int t = val; + int n = 0; + while (t > 0) + { + t /= 10; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 10 + '0'; + val /= 10; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_s(char *s, int *res) +{ + if (s == NULL) + { + char *text = "(null)"; + for (; *text; text++) + { + putchar(*text); + (*res)++; + } + return; + } + for (; *s; s++) + { + putchar(*s); + (*res)++; + } +} + +void handle_u(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 10; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 10 + '0'; + val /= 10; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_x(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 16; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 16 + '0'; + if (s[n] > '9') + { + s[n] = (s[n] - '0') % 10 + 'a'; + } + val /= 16; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} + +void handle_o(unsigned int val, int *res) +{ + if (val == 0) + { + putchar('0'); + (*res)++; + } + + unsigned int t = val; + int n = 0; + while (t > 0) + { + t /= 8; + n++; + } + + char *s = malloc(n * sizeof(char)); + int m = n; + if (s == NULL) + { + return; + } + n--; + for (; n >= 0; n--) + { + s[n] = val % 8 + '0'; + val /= 8; + } + + // actual printing + for (int i = 0; i < m; i++) + { + putchar(s[i]); + (*res)++; + } + free(s); +} diff --git a/graphs/piscine/tinyprintf/src/tinyprintf.h b/graphs/piscine/tinyprintf/src/tinyprintf.h new file mode 100644 index 0000000..fd1f0b4 --- /dev/null +++ b/graphs/piscine/tinyprintf/src/tinyprintf.h @@ -0,0 +1,15 @@ +#ifndef TINYPRINTF_H +#define TINYPRINTF_H + +#include <stdarg.h> +#include <stddef.h> + +int tinyprintf(const char *format, ...); +void handle_d(int val, int *res); +void handle_u(unsigned int val, int *res); +void handle_x(unsigned int val, int *res); +void handle_o(unsigned int val, int *res); +void handle_s(char *s, int *res); +void dispatch(char c, va_list ap, int *res); + +#endif /* ! TINYPRINTF_H */ diff --git a/graphs/piscine/tinyprintf/tests/tests.c b/graphs/piscine/tinyprintf/tests/tests.c new file mode 100644 index 0000000..4235203 --- /dev/null +++ b/graphs/piscine/tinyprintf/tests/tests.c @@ -0,0 +1,213 @@ +#include <criterion/criterion.h> +#include <criterion/assert.h> +#include <criterion/redirect.h> +#include <stdio.h> + +#include "../src/tinyprintf.h" + +TestSuite(TestHandleD); + +Test(TestHandleD, handle_d42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("42"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleD, handle_d0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleD, handle_dminus42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_d(-42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("-42"); + cr_expect(res == 3, "Expected: %d. Got: %d", 3, res); +} + +Test(TestHandleD, simple_print, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%d] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [42] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleX); + +Test(TestHandleX, handle_x42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("2a"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleX, handle_x0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleX, handle_x15, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(15, &res); + fflush(stdout); + cr_assert_stdout_eq_str("f"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleX, handle_0xdeadc0de, .init = cr_redirect_stdout) +{ + int res = 0; + handle_x(0xdeadc0de, &res); + fflush(stdout); + cr_assert_stdout_eq_str("deadc0de"); + cr_expect(res == 8, "Expected: %d. Got: %d", 8, res); +} + +Test(TestHandleX, simple_print_hexa, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%x] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [2a] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleU); + +Test(TestHandleU, handle_u42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("42"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleU, handle_u0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleU, handle_u15, .init = cr_redirect_stdout) +{ + int res = 0; + handle_u(15, &res); + fflush(stdout); + cr_assert_stdout_eq_str("15"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleU, simple_print_unsigned, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%u] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [42] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestHandleO); + +Test(TestHandleO, handle_o42, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(42, &res); + fflush(stdout); + cr_assert_stdout_eq_str("52"); + cr_expect(res == 2, "Expected: %d. Got: %d", 2, res); +} + +Test(TestHandleO, handle_o0, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(0, &res); + fflush(stdout); + cr_assert_stdout_eq_str("0"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleO, handle_o7, .init = cr_redirect_stdout) +{ + int res = 0; + handle_o(7, &res); + fflush(stdout); + cr_assert_stdout_eq_str("7"); + cr_expect(res == 1, "Expected: %d. Got: %d", 1, res); +} + +Test(TestHandleO, simple_print_octal, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%s [%o] %s", "Hello", 42, "world!"); + fflush(stdout); + cr_assert_stdout_eq_str("Hello [52] world!"); + cr_expect(retval == 17, "Expected: %d. Got: %d", 17, retval); +} + +TestSuite(TestPrint); + +Test(TestPrint, print_percent, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%%s", "in your head"); + fflush(stdout); + cr_assert_stdout_eq_str("%s"); + cr_expect(retval == 2, "Expected: %d. Got: %d", 2, retval); +} + +Test(TestPrint, print_unknown_option, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("Good morning ACU! %t Tinyprintf is cool", 12); + fflush(stdout); + cr_assert_stdout_eq_str("Good morning ACU! %t Tinyprintf is cool"); + cr_expect(retval == 39, "Expected: %d. Got: %d", 39, retval); +} + +Test(TestPrint, print_tricky, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%c%c is %s... %d too.", '4', '2', "the answer", '*'); + fflush(stdout); + cr_assert_stdout_eq_str("42 is the answer... 42 too."); + cr_expect(retval == 27, "Expected: %d. Got: %d", 27, retval); +} + +Test(TestPrint, print_null, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("%c%c is %s... %d too.", '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str("42 is (null)... 42 too."); + cr_expect(retval == 23, "Expected: %d. Got: %d", 23, retval); +} + +Test(TestPrint, print_null_fmt, .init = cr_redirect_stdout) +{ + int retval = tinyprintf(NULL, '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str(""); + cr_expect(retval == 0, "Expected: %d. Got: %d", 0, retval); +} + +Test(TestPrint, print_empty_fmt, .init = cr_redirect_stdout) +{ + int retval = tinyprintf("", '4', '2', NULL, '*'); + fflush(stdout); + cr_assert_stdout_eq_str(""); + cr_expect(retval == 0, "Expected: %d. Got: %d", 0, retval); +} |
