subject en:

Assignment name  : ft_printf
Expected files   : ft_printf.c
Allowed functions: malloc, free, write, va_start, va_arg, va_copy, va_end
--------------------------------------------------------------------------------

Write a function named `ft_printf` that will mimic the real printf with the following constraints:

- It will manage only the following conversions: s,d and x
- It will manage the minimum field width. (we will never test with a field with of 0)
- It will manage only the precison flag `.`.

Your function must be declared as follows:

int ft_printf(const char *, ... );

Before you start we advise you to read the `man 3 printf` and the `man va_arg`.
To test your program compare your results with the true printf.

Exemples of the function output:

call: ft_printf("%10.2s\\n", "toto");
out:        to$

call: ft_printf("Magic %s is %5d", "number", 42);
out:Magic number is    42%

call: ft_printf("Hexadecimal for %d is %x\\n", 42, 42);
out:Hexadecimal for 42 is 2a$

subject ru:

Название задания  : ft_printf
Ожидаемые файлы   : ft_printf.c
Разрешенные функции: malloc, free, write, va_start, va_arg, va_copy, va_end
--------------------------------------------------------------------------------

Напишите функцию с именем ft_printf, которая будет имитировать реальный printf со следующими ограничениями:

- Он будет управлять только следующими преобразованиями: s, d и x
- Он будет управлять минимальной шириной поля. (мы никогда не будем тестировать поле с 0)
- Он будет управлять только флагом точности `.`.

Ваша функция должна быть объявлена следующим образом:

int ft_printf(const char *, ... );

Прежде чем начать, мы советуем вам прочитать `man 3 printf` и `man va_arg`.
Чтобы протестировать свою программу, сравните свои результаты с истинным printf.

Примеры вывода функции:

call: ft_printf("%10.2s\\n", "toto");
out:        to$

call: ft_printf("Magic %s is %5d", "number", 42);
out:Magic number is    42%

call: ft_printf("Hexadecimal for %d is %x\\n", 42, 42);
out:Hexadecimal for 42 is 2a$

Решение:

<https://github.com/parismart/exam_rank02/blob/master/ft_printf/ft_printf.c>
#include <unistd.h>
#include <stdarg.h>

static int	ft_nbrlen(long n, int base_len)
{
	int	i;

	i = 1;
	while (n >= base_len)
	{
		n /= base_len;
		i++;
	}
	return (i);
}

static void	ft_putnbr(long nbr, int base_len, char *base)
{
	if (nbr >= base_len)
		ft_putnbr(nbr / base_len, base_len, base);
	write(1, &base[nbr % base_len], 1);
}

int		ft_printf(const char *format, ...)
{
	va_list	args;
	char	*str;
	char	*s;
	long	nbr;
	int		neg;
	int		len;
	int		width;
	int		prec;
	int		spaces;
	int		zeros;
	int		length;

	va_start(args, format);
	str = (char *)format;
	length = 0;
	while (*str)
	{
		if (*str == '%')
		{
			str++;
			neg = 0;
			len = 0;
			width = 0;
			prec = -1;
			spaces = 0;
			zeros = 0;
			while (*str >= '0' && *str <= '9')
			{
				width = width * 10 + (*str - 48);
				str++;
			}
			if (*str == '.')
			{
				prec = 0;
				str++;
				while (*str >= '0' && *str <= '9')
				{
					prec = prec * 10 + (*str - 48);
					str++;
				}
			}
			if (*str == 's')
			{
				s = va_arg(args, char *);
				if (!s)
					s = "(null)";
				while (s[len])
					len++;
			}
			if (*str == 'd')
			{
				nbr = va_arg(args, int);
				if (nbr < 0)
				{
					nbr = -nbr;
					neg = 1;
				}
				len = ft_nbrlen(nbr, 10) + neg;
			}
			if (*str == 'x')
			{
				nbr = va_arg(args, unsigned);
				len = ft_nbrlen(nbr, 16);
			}
			if (prec >= len && *str != 's')
				zeros = prec - len + neg;
			else if (prec > -1 && prec < len && *str == 's')
				len = prec;
			else if (prec == 0 && (*str == 's' || nbr == 0))
				len = 0;
			spaces = width - zeros - len;
			while (spaces-- > 0)
				length += write(1, " ", 1);
			if (neg == 1)
				write(1, "-", 1);
			while (zeros-- > 0)
				length += write(1, "0", 1);
			if (*str == 's')
				write(1, s, len);
			else if (len > 0 && *str == 'd')
				ft_putnbr(nbr, 10, "0123456789");
			else if (len > 0 && *str == 'x')
				ft_putnbr(nbr, 16, "0123456789abcdef");
			length += len;
		}
		else
			length += write(1, str, 1);
		str++;
	}
	va_end(args);
	return (length);
}