/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   main.c                                             :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: gbaconni@student.42lausanne.ch             +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2022/04/13 06:58:46 by gbaconni          #+#    #+#             */
/*   Updated: 2022/04/25 07:08:49 by gbaconni         ###   lausanne.ch       */
/*                                                                            */
/* ************************************************************************** */

#include <stdio.h>  // printf
#include <string.h> // strlen
#include <ctype.h>  // isdigit
#include <assert.h> // assert

#include "libftprintf/libftprintf.h"

char	*ft_fmtsplit(char **fmt)
{
	char	*format;
	char	*start;
	char	*end;
	int		len;

	format = NULL;
	start = *fmt;
	end = *fmt;
	if (start == NULL)
		return (NULL);
	if (*end == '%')
		if (*end++ == '%')
			end++;
	while (*end != '\0' && *end != '%')
		end++;
	len = end - start;
	format = (char *) calloc(len + 1, sizeof(char));
	if (format == NULL)
		return (NULL);
	strncpy(format, start, len);
	if (*end == '\0')
		*fmt = NULL;
	else
		*fmt += len;
	return (format);
}

int	_printf(int (*f)(const char *restrict, ...), \
		char *format, char *arg)
{
	int		ret;
	char	c;

	ret = 0;
	c = *(format + 1 + ft_skipchars(format + 1, "0123456789# +"));
	if (c == 'c')
		ret = (*f)(format, *arg);
	else if (c == 's')
		ret = (*f)(format, arg);
	else if (c == 'p')
		ret = (*f)(format, (arg)? &arg: NULL);
	else if (c == 'x' || c == 'X')
		ret = (*f)(format, atol(arg));
	else if (c == 'd' || c == 'i' || c == 'u')
		ret = (*f)(format, atoi(arg));
	else
		ret = (*f)(format);
	return (ret);
}

int	_sprintf(int (*f)(const char *restrict, ...), \
		char *str, char *format, char *arg)
{
	int			ret;
	char		c;
	int			fd[3];

	ret = 0;
	setbuf(stdout, NULL);
	pipe(fd);
	fd[2] = dup(STDOUT_FILENO);
	dup2(fd[1], STDOUT_FILENO);
	ret = _printf((*f), format, arg);
	dup2(fd[2], STDOUT_FILENO);
	fflush(stdout);
	close(fd[1]);
	while (read(fd[0], &c, 1) > 0)
		*str++ = c;
	*str = '\0';
	close(fd[0]);
	return (ret);
}

int	assert_printf(char *format, char *arg)
{
	int		ret;
	int		ft_ret;
	char	out[256];
	char	ft_out[256];

	if (arg == NULL || strcmp(arg, "") == 0)
		arg = NULL;
	ret = _sprintf(printf, out, format, arg);
	printf("%d = printf(\"%s\", '%s')\n%s\n", ret, format, arg, out);
	ft_ret = _sprintf(ft_printf, ft_out, format, arg);
	printf("%d = ft_printf(\"%s\", '%s')\n%s\n\n", ft_ret, format, arg, ft_out);
	assert(ret == ft_ret);
	assert(strcmp(out, ft_out) == 0);
	return (!(ret == ft_ret));
}

int	main(int args, char *argv[])
{
	int		ret;
	char	*fmt;
	char	*format;
	char	*arg;

	ret = 0;
	argv++;
	if (--args < 1)
		return (127);
	fmt = *argv++;
	format = ft_fmtsplit(&fmt);
	while (format != NULL)
	{
		if (*format == '%' && *(format + 1) != '%' && --args)
			arg = *argv++;
		else
			arg = NULL;
		ret |= assert_printf(format, arg);
		free(format);
		format = ft_fmtsplit(&fmt);
	}
	return (ret);
}
