Introduction
Objective of this project was to implement my_printf() function to
reproduce the behavior of C standard library's
printf().
The following functions were authorised for use in this project:
- write(2)
- malloc
- free
- va_start, va_arg, va_copy, va_end
The following were not authorised for use in this project:
- printf and co. (fprintf, sprintf, snprintf, asprintf, dprintf, vprintf, vfprintf, vsprintf, vsnprintf, vasprintf, vdprintf)
- Multiline macros
- Include another.c
- Macros with logic (while/if/variables/...)
The Program
my_printf.c
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdint.h>
#define OCTAL 8
#define DECIMAL 10
#define HEXDECIMAL 16
void my_putchar(char str)
{
write(1, &str, 1);
}
void my_putstr(char *str)
{
int i = 0;
while(str[i] != '\0')
{
my_putchar(str[i]);
i++;
}
}
int my_strlen(char* str)
{
int i = 0;
while (str[i] != '\0')
{
i++;
}
return i;
}
void my_reverse_str(char *str)
{
int len = my_strlen(str);
for (int i = len -1; i >= 0; i--)
{
my_putchar(str[i]);
}
}
int my_printchar(char character)
{
int len = 1;
my_putchar(character);
return len;
}
int my_printstring(char* str)
{
int len = 0;
if (str == NULL)
{
my_putstr("(null)");
len = 6; // length of the string "(null)"
}
else
{
len = my_strlen(str);
int i = 0;
while (i < len)
{
my_putchar(str[i]);
i++;
}
}
return len;
}
/* Converting an integer number into a character string and output
the chars using my_putchar function, the function returns the number
of characters that were outputted */
int my_printd(int number)
{
char str[100];
int i = 0;
int len = 0;
if (number == 0)
{
str[i++] = '0';
}
// Checking if number is negative and output '-' to the first position of the string
if (number < 0)
{
my_putchar('-');
// Converting the number to a positive value
number = -number;
// Increment the length for the '-' character
len++;
}
while (number > 0)
{
str[i++] = '0' + (number % DECIMAL);// '0' is 48 in ASCII
number = number / DECIMAL;
}
str[i] = '\0';
my_reverse_str(str);
len += my_strlen(str);
return len;
}
/* Converting decimal to octal */
int my_printo(unsigned int number)
{
char str[100];
int i = 0;
while (number > 0)
{
str[i++] = '0' + (number % OCTAL);
number = number / OCTAL;
}
str[i] = '\0';
my_reverse_str(str);
int len = my_strlen(str);
return len;
}
int my_printu(unsigned int number)
{
char str[100];
int i = 0;
while (number > 0)
{
str[i++] = '0' + (number % DECIMAL);
number = number / DECIMAL;
}
str[i] = '\0';
my_reverse_str(str);
int len = my_strlen(str);
return len;
}
/* Converting the decimal number to hexadecimal representation */
int my_printhex(unsigned long number, char ch)
{
char hex_str[100];
char hex_digits[] = "0123456789ABCDEF";
int i = 0;
int len = 0;
while (number > 0)
{
hex_str[i++] = hex_digits[number % HEXDECIMAL];
number /= HEXDECIMAL;
}
hex_str[i] = '\0';
len = my_strlen(hex_str);
//my_reverse_str(hex_str);
for (int i = len - 1; i >= 0; i--)
{
if (hex_str[i] >= 65 && hex_str[i] <= 90 && ch == 'p')
{
my_putchar(hex_str[i] + 32);
}
else
{
my_putchar(hex_str[i]);
}
}
return len;
}
/* Casting the pointer to uintptr_t, printing its hexdec value preceded by 0x,
and returning len of the string */
int my_printptr(void *ptr)
{
// Cast the void pointer to uintptr_t
intptr_t ptr_value = (intptr_t) ptr;
my_putstr("0x");
// Return the length of the string
int len = 2 + my_printhex(ptr_value, 'p');
return len;
}
int my_printf(char * format_str, ...)
{
int i = 0;
int len = 0;
// Define a va_list variable named args
va_list args;
/* Begin the argument list with the va_start - macros, act as markers to mark
where the arg list starts */
va_start(args, format_str);
while(format_str[i] != '\0')
{
if (format_str[i] == '%')
{
i++;
switch (format_str[i])
{
case 'd':
len += my_printd(va_arg(args, int));
break;
case 'o':
len += my_printo(va_arg(args, unsigned int));
break;
case 'u':
len += my_printu(va_arg(args, unsigned int));
break;
case 'x':
len += my_printhex(va_arg(args, unsigned long), 'x');
break;
case 'p':
len += my_printptr(va_arg(args, intptr_t *));
break;
case 'c':
/* a second argument is the type that is expected to be received ;
'char' changes to 'int' in va_arg() break; */
len += my_printchar(va_arg(args, int));
case 's':
len += my_printstring(va_arg(args, char*));
break;
default:
my_printchar(format_str[i]);
len++;
}
}
else
{
my_printchar(format_str[i]);
len++;
}
i++;
}
va_end(args);
return len;
}
int main()
{
int count = my_printf("string: %s\nchar: %c\nint: %d\nneg_int: %d\no:
%o\nu: %u\nx: %x\npointer: %p\n", "Hello world!", 'X', 5, -5, 334, 100, 4, &count);
my_printf("%s!\n", NULL);
my_printf("14 -- %x!\n", 14); // E
int variable = 12;
my_printf(" my_printf-- var 12 p:%p!\n", &variable);
my_printf("1337 %d!\n", 1337);
int len = my_printf("%d - %d - %d!\n", 2048, 0, -1337);
my_printf("%u!\n", 1337);
return 0;
}
