194 lines
3.7 KiB
C
194 lines
3.7 KiB
C
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
|
|
/*
|
|
* Consome todos os caracteres de espaço em branco consecutivos do stream.
|
|
* Retorna 1 em sucesso, -1 em caso de erro de leitura.
|
|
*/
|
|
int match_space(FILE *f)
|
|
{
|
|
int ch;
|
|
|
|
// Lê caracteres enquanto não for o fim do ficheiro e forem espaços
|
|
while ((ch = fgetc(f)) != EOF && isspace(ch))
|
|
{
|
|
// O corpo do loop está vazio de propósito, apenas consome os caracteres
|
|
}
|
|
|
|
// Se o loop parou por um caractere que não é espaço, coloca-o de volta
|
|
if (ch != EOF)
|
|
ungetc(ch, f);
|
|
|
|
// Verifica se ocorreu um erro de leitura durante as operações
|
|
if (ferror(f))
|
|
return -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Tenta corresponder a um caractere específico 'c'.
|
|
* Já era simples e eficiente, não necessitou de alterações.
|
|
*/
|
|
int match_char(FILE *f, char c)
|
|
{
|
|
int ch = fgetc(f);
|
|
if (ch == c)
|
|
return 1; // Sucesso, caractere corresponde
|
|
|
|
// Se não correspondeu, e não é o fim do ficheiro, devolve o caractere
|
|
if (ch != EOF)
|
|
ungetc(ch, f);
|
|
|
|
return -1; // Falha na correspondência
|
|
}
|
|
|
|
/*
|
|
* Lê um único caractere do stream e armazena-o.
|
|
* Já era simples e direto, não necessitou de alterações.
|
|
*/
|
|
int scan_char(FILE *f, va_list ap)
|
|
{
|
|
int ch = fgetc(f);
|
|
char *cp = va_arg(ap, char *);
|
|
|
|
if (ch == EOF)
|
|
return -1; // Falha se chegar ao fim do ficheiro
|
|
|
|
*cp = (char)ch;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Lê um inteiro do stream, ignorando espaços iniciais e tratando o sinal.
|
|
*/
|
|
int scan_int(FILE *f, va_list ap)
|
|
{
|
|
int *ip = va_arg(ap, int *);
|
|
int value = 0;
|
|
int sign = 1;
|
|
int ch;
|
|
|
|
ch = fgetc(f);
|
|
|
|
if (ch == '-')
|
|
{
|
|
sign = -1;
|
|
ch = fgetc(f);
|
|
}
|
|
else if (ch == '+')
|
|
{
|
|
ch = fgetc(f);
|
|
}
|
|
|
|
if (!isdigit(ch))
|
|
{
|
|
if (ch != EOF)
|
|
ungetc(ch, f);
|
|
return -1;
|
|
}
|
|
|
|
while (isdigit(ch))
|
|
{
|
|
value = value * 10 + (ch - '0');
|
|
ch = fgetc(f);
|
|
}
|
|
|
|
if (ch != EOF)
|
|
ungetc(ch, f);
|
|
|
|
*ip = value * sign;
|
|
return 1;
|
|
}
|
|
|
|
int scan_string(FILE *f, va_list ap)
|
|
{
|
|
char *sp = va_arg(ap, char *);
|
|
int i = 0;
|
|
int ch;
|
|
|
|
ch = fgetc(f);
|
|
if (ch == EOF)
|
|
return -1;
|
|
|
|
while (ch != EOF && !isspace(ch))
|
|
{
|
|
sp[i++] = (char)ch;
|
|
ch = fgetc(f);
|
|
}
|
|
sp[i] = '\0';
|
|
|
|
if (ch != EOF)
|
|
ungetc(ch, f);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int match_conv(FILE *f, const char **format, va_list ap)
|
|
{
|
|
switch (**format)
|
|
{
|
|
case 'c':
|
|
return scan_char(f, ap);
|
|
case 'd':
|
|
match_space(f);
|
|
return scan_int(f, ap);
|
|
case 's':
|
|
match_space(f);
|
|
return scan_string(f, ap);
|
|
case '\0':
|
|
return -1;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int ft_vfscanf(FILE *f, const char *format, va_list ap)
|
|
{
|
|
int nconv = 0;
|
|
|
|
int c = fgetc(f);
|
|
if (c == EOF)
|
|
return EOF;
|
|
ungetc(c, f);
|
|
|
|
while (*format)
|
|
{
|
|
if (*format == '%')
|
|
{
|
|
format++;
|
|
if (match_conv(f, &format, ap) != 1)
|
|
break;
|
|
else
|
|
nconv++;
|
|
}
|
|
else if (isspace(*format))
|
|
{
|
|
if (match_space(f) == -1)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (match_char(f, *format) != 1)
|
|
break;
|
|
}
|
|
format++;
|
|
}
|
|
|
|
if (ferror(f))
|
|
return EOF;
|
|
|
|
return nconv;
|
|
}
|
|
|
|
int ft_scanf(const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
int ret = ft_vfscanf(stdin, format, ap);
|
|
va_end(ap);
|
|
|
|
return ret;
|
|
} |