summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryctct <yctct>2026-01-28 12:43:28 +0100
committeryctct <yctct>2026-01-28 12:43:28 +0100
commit925989f7e7af67d965e2b501a51068acfe449ab0 (patch)
tree7a83e51d2872f9c97abf3166f883ff8dfcf7e2e0
Add all files, first commit
-rw-r--r--.gitignore6
-rw-r--r--Makefile22
-rw-r--r--README.txt75
-rw-r--r--ft_checkpadd.c19
-rw-r--r--ft_printf.c73
-rw-r--r--ft_printf.h19
-rw-r--r--ft_putchar.c11
-rw-r--r--ft_puthexlower.c30
-rw-r--r--ft_puthexupper.c26
-rw-r--r--ft_putnbr.c63
-rw-r--r--ft_putstr.c29
-rw-r--r--ft_putunsigned.c29
12 files changed, 402 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..56a534c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+a.out
+*.a
+*.o
+*swp
+*bak
+*main.c
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e269455
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,22 @@
+CC = cc
+CFLAGS = -Wall -Werror -Wextra -g
+SRCS = ft_printf.c ft_putnbr.c ft_putstr.c ft_putchar.c ft_putunsigned.c ft_puthexlower.c ft_puthexupper.c ft_checkpadd.c
+OBJS = $(SRCS:.c=.o)
+NAME = libftprintf.a
+DEPS = ft_printf.h
+
+%.o : %.c $(DEPS)
+ $(CC) -c -o $@ $< $(CFLAGS)
+
+$(NAME) : $(OBJS)
+ ar rcs $(NAME) $(OBJS)
+
+all: $(NAME)
+
+.PHONY: clean fclean re
+
+clean:
+ rm -f *.o
+fclean: clean
+ rm -f $(NAME)
+re: fclean all
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..ce18a02
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,75 @@
+ft_printf library
+----------------
+
+Description
+----------
+
+This is a custom implementation of printf.
+
+I wrote this implementation to carry on learning C and understand what printf does, to an extend.
+
+This is implementation is concerned with the following specifiers only: c, s, i, d, u, x, X, p.
+
+Instructions
+-----------
+
+To clone the repository of this library run:
+
+ $ git clone url directory_name
+ $ cd directory_name
+
+To compile the library run:
+
+ $ make
+
+To recompile the library run:
+
+ $ make re
+
+To delete all object files run:
+
+ $ make clean
+
+To delete all object files and libft.a run:
+
+ $ make fclean
+
+Then to use the library, ft_printf.a, with a programme, say main.c, run:
+
+ $ cc main.c libftprintf.a
+
+and append each of the c files with:
+
+ #include "path/to/ft_printf.h"
+
+Implementation choice
+---------------------
+
+ft_printf.c parses the string for the specifier.
+When it finds a specifier, a helper function check the character following the specifier against conversion specifier, when the condition is true (i.e. the char following the specifier is a conversion specifier, then the argument pointer is passed to a function that will convert the argument according to the conversion specifier.
+
+Possible improvements:
+
+- I could probably merge both functions converting decimal to hexadecimal into a single function.
+- At the end of my implement, I added a function, ft_checkpadd.c to check whether the address a pointer is pointing to is zero. I could try to integrate that function elsewhere.
+- deal with edge case when % is the last char of a string
+
+
+Some edge cases this implementation takes into account:
+
+- specifier followed by a non-conversation specifier character e.g. %t
+- print(0);
+- print ("");
+
+Relevant projects
+-----------------
+
+- tests for printf
+
+Resources
+---------
+
+- Oceano's tutorials on variadic functions and "mini printf"
+- man stdarg for variadic functions.
+- man limits.h for INT_MAX, etc.
+- man 3 printf
diff --git a/ft_checkpadd.c b/ft_checkpadd.c
new file mode 100644
index 0000000..a1881d1
--- /dev/null
+++ b/ft_checkpadd.c
@@ -0,0 +1,19 @@
+
+#include "ft_printf.h"
+
+int ft_checkpadd(va_list ap)
+{
+ int counter;
+ unsigned long pointer_address;
+
+ counter = 0;
+ pointer_address = ((long)(va_arg(ap, void *)));
+ if (pointer_address == 0)
+ counter += write(1, "(nil)", 5);
+ else
+ {
+ counter += write(1, "0x", 2);
+ counter += ft_puthexlower(pointer_address);
+ }
+ return (counter);
+}
diff --git a/ft_printf.c b/ft_printf.c
new file mode 100644
index 0000000..1058f5b
--- /dev/null
+++ b/ft_printf.c
@@ -0,0 +1,73 @@
+
+// for specifier 'c', we use int because char will be promoted to
+// int anyway
+//
+// we store address of pointer in variable cause variadic
+//
+// ap: argument pointer
+// ap gets incremented on each call
+//
+// a pointer pointing to the first flag/argument
+// format states how many arguments are there
+//
+// va_start initialise the vector argument
+//
+// *format is the whole string printed by printf
+//
+// the last condition of ft_whichspecifier is to deal with
+// specifier followed by a non-conversion specifier
+
+#include "ft_printf.h"
+
+int ft_whichspecifier(va_list ap, const char *format)
+{
+ int counter;
+
+ counter = 0;
+ if (*format == 'c')
+ counter += ft_putchar((char)(va_arg(ap, int)));
+ else if (*format == 's')
+ counter += ft_putstr((va_arg(ap, char *)));
+ else if (*format == 'i' || *format == 'd')
+ counter += ft_putnbr((va_arg(ap, int)));
+ else if (*format == 'u')
+ counter += ft_putunsigned((va_arg(ap, unsigned int)));
+ else if (*format == 'x')
+ counter += ft_puthexlower((va_arg(ap, unsigned int)));
+ else if (*format == 'X')
+ counter += ft_puthexupper((va_arg(ap, unsigned int)));
+ else if (*format == 'p')
+ counter += ft_checkpadd(ap);
+ else if (*format == '%')
+ counter += write(1, "%", 1);
+ else
+ {
+ counter += write(1, "%", 1);
+ //counter += ft_putchar(*format);
+ counter += write(1, &(*format), 1);
+ }
+ return (counter);
+}
+
+int ft_printf(const char *format, ...)
+{
+ int counter;
+ va_list ap;
+
+ va_start(ap, format);
+ counter = 0;
+ if (!format)
+ return (-1);
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ format++;
+ counter += ft_whichspecifier(ap, format);
+ }
+ else
+ counter += ft_putchar(*format);
+ format++;
+ }
+ return (counter);
+}
diff --git a/ft_printf.h b/ft_printf.h
new file mode 100644
index 0000000..5fffc0f
--- /dev/null
+++ b/ft_printf.h
@@ -0,0 +1,19 @@
+#ifndef FT_PRINTF_H
+
+# define FT_PRINTF_H
+
+# include <limits.h> // for INT and MAX values
+# include <stdarg.h> // for variadic function
+# include <stdio.h>
+# include <unistd.h> // for write function
+
+int ft_putchar(char c);
+int ft_putstr(char *str);
+int ft_putnbr(int n);
+int ft_putunsigned(unsigned int nb);
+int ft_puthexlower(unsigned long n);
+int ft_puthexupper(unsigned int n);
+int ft_checkpadd(va_list ap);
+int ft_printf(const char *format, ...);
+
+#endif
diff --git a/ft_putchar.c b/ft_putchar.c
new file mode 100644
index 0000000..4ff8dda
--- /dev/null
+++ b/ft_putchar.c
@@ -0,0 +1,11 @@
+
+#include "ft_printf.h"
+
+int ft_putchar(char c)
+{
+ int counter;
+
+ counter = 0;
+ counter = write(1, &c, 1);
+ return (counter);
+}
diff --git a/ft_puthexlower.c b/ft_puthexlower.c
new file mode 100644
index 0000000..282328a
--- /dev/null
+++ b/ft_puthexlower.c
@@ -0,0 +1,30 @@
+
+// parameter is unsigned long so function does not
+// overflow when LONG_MAX is the address
+// we use recursion to print backwards
+
+#include "ft_printf.h"
+
+int ft_puthexlower(unsigned long n)
+{
+ const char hex[16] = "0123456789abcdef";
+ int save;
+ int remainder;
+ int counter;
+
+ remainder = 0;
+ save = 0;
+ counter = 0;
+ if (n > 15)
+ {
+ save = n;
+ n /= 16;
+ remainder = save - (n * 16);
+ counter += ft_puthexlower(n);
+ counter += write(1, &hex[remainder], 1);
+ }
+ else
+ counter += write(1, &hex[n], 1);
+ return (counter);
+}
+
diff --git a/ft_puthexupper.c b/ft_puthexupper.c
new file mode 100644
index 0000000..b5518bf
--- /dev/null
+++ b/ft_puthexupper.c
@@ -0,0 +1,26 @@
+
+// using unsigned int as a paramter to deal with with negative numbers
+#include "ft_printf.h"
+
+int ft_puthexupper(unsigned int n)
+{
+ const char hex[16] = "0123456789ABCDEF";
+ int save;
+ int remainder;
+ int counter;
+
+ remainder = 0;
+ save = 0;
+ counter = 0;
+ if (n > 15)
+ {
+ save = n;
+ n /= 16;
+ remainder = save - (n * 16);
+ counter += ft_puthexupper(n);
+ counter += write(1, &hex[remainder], 1);
+ }
+ else
+ counter += write(1, &hex[n], 1);
+ return (counter);
+}
diff --git a/ft_putnbr.c b/ft_putnbr.c
new file mode 100644
index 0000000..fe138ff
--- /dev/null
+++ b/ft_putnbr.c
@@ -0,0 +1,63 @@
+
+#include "ft_printf.h"
+
+int ft_putnbr(int n)
+{
+ int counter;
+
+ counter = 0;
+ if (n == -2147483648)
+ counter += ft_putstr("-2147483648");
+ else if (n < 0)
+ {
+ counter += ft_putchar('-');
+ n = -n;
+ counter += ft_putnbr(n);
+ }
+ else if (n == 0)
+ counter += ft_putchar('0');
+ else if (n > 9)
+ {
+ counter += ft_putnbr(n / 10);
+ counter += ft_putchar((n % 10) + 48);
+ }
+ else
+ counter += ft_putchar(n + 48);
+ return (counter);
+}
+
+/*
+// non-recursive implementation
+int ft_putnbr(int nb)
+{
+ char c[11];
+ int i;
+ long int nbl;
+ int counter;
+
+ nbl = nb;
+ counter = 0;
+ if (nbl < 0)
+ {
+ nbl *= -1;
+ counter += write(1, "-", 1);
+ }
+ if (nbl == 0)
+ counter += write(1, "0", 1);
+ i = 0;
+ while (nbl)
+ {
+ c[i] = (nbl % 10) + 48;
+ nbl = nbl / 10;
+ i++;
+ }
+ while (i > 0)
+ {
+ i--;
+ counter += write(1, &c[i], 1);
+ }
+ c[i] = '\0';
+ return (counter);
+}
+*/
+
diff --git a/ft_putstr.c b/ft_putstr.c
new file mode 100644
index 0000000..19a2c37
--- /dev/null
+++ b/ft_putstr.c
@@ -0,0 +1,29 @@
+
+// we use putchar to count each character
+
+#include "ft_printf.h"
+
+int ft_putstr(char *str)
+{
+ int counter;
+ const char *snull = "(null)";
+
+ counter = 0;
+ if (str == NULL)
+ {
+ while (*snull)
+ {
+ counter += ft_putchar(*snull);
+ snull++;
+ }
+ }
+ else
+ {
+ while (*str)
+ {
+ counter += ft_putchar(*str);
+ str++;
+ }
+ }
+ return (counter);
+}
diff --git a/ft_putunsigned.c b/ft_putunsigned.c
new file mode 100644
index 0000000..8908de0
--- /dev/null
+++ b/ft_putunsigned.c
@@ -0,0 +1,29 @@
+
+#include "ft_printf.h"
+
+int ft_putunsigned(unsigned int nb)
+{
+ char c[11];
+ int i;
+ long int nbl;
+ int counter;
+
+ nbl = nb;
+ counter = 0;
+ if (nbl == 0)
+ counter += write(1, "0", 1);
+ i = 0;
+ while (nbl)
+ {
+ c[i] = (nbl % 10) + 48;
+ nbl = nbl / 10;
+ i++;
+ }
+ while (i > 0)
+ {
+ i--;
+ counter += write(1, &c[i], 1);
+ }
+ c[i] = '\0';
+ return (counter);
+}