summaryrefslogtreecommitdiff
path: root/graphs/piscine/tinyprintf
diff options
context:
space:
mode:
Diffstat (limited to 'graphs/piscine/tinyprintf')
-rw-r--r--graphs/piscine/tinyprintf/Makefile17
-rw-r--r--graphs/piscine/tinyprintf/src/tinyprintf.c251
-rw-r--r--graphs/piscine/tinyprintf/src/tinyprintf.h15
-rw-r--r--graphs/piscine/tinyprintf/tests/tests.c213
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);
+}