#include <sys/types.h>
#include <sys/dir.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int mindist(char *, char*, char *);
int spname(char *, char *);
int spdist(char *, char *);
void print(FILE *, int );
char ttyin();
FILE *efopen(char *, char *);
#define EQ(s,t) (strcmp(s,t) == 0)
#define PAGESIZE 22
#define DIRSIZE 14
char *progname; // nombre del programa para mensajes de error
FILE *efopen(char *file, char *mode)
{
FILE *fp, *fopen();
extern char *progname; // variable definida como global aquí se declara como extern par poderla usar
if ((fp = fopen(file, mode)) != NULL) return fp;
fprintf(stderr, "%s: Imposible abrir el archivo %s mode %s\n", progname, file, mode);
exit(1);
}
// procesamiento de la respuesta a partir de /dev/tty (versión 1)
char ttyin()
{
char buf[BUFSIZ];
FILE *efopen();
static FILE *tty = NULL; // es como una variable global
if (tty == NULL) tty = efopen("/dev/tty", "r");
if (fgets(buf, BUFSIZ, tty) == NULL || buf[0] == 'q') exit(0);
else return buf[0]; // línea ordinaria
}
void print(FILE *fp, int pagesize)
{
static int lines = 0; // número de líneas hasta aquí
char buf[BUFSIZ];
while (fgets(buf, sizeof buf, fp) != NULL )
if (++lines < pagesize) fputs(buf, stdout);
else
{
buf[strlen(buf)-1] = '\0';
fputs(buf, stdout);
fflush(stdout);
ttyin();
lines = 0;
}
}
/*
spdist: retorna la distancia entre dos nombres
parametros poco precisos de escritura:
0 si las cadebas son idénticas
1 si dos caracteres están transpuestos
2 si un carácter está equivocado, de más o de menos
3 cualquier otra cosa
*/
int spdist(char *s, char *t)
{
while(*s++ == *t) if(*t++ == '\0') return 0; // correspondencia exácta
if(*--s)
{
if(*t)
{
if(s[1] && t[1] && *s == t[1] && *t == s[1] && EQ(s+2, t+2)) return 1; // transpuesto
if(EQ(s+1, t+1)) return 2; // un carácter extra
}
if(*t && EQ(s, t+1)) return 2; // falta un carácter
return 3;
}
}
/*
spname: retorna el nombre del archivo correctamente escrito
-1 si no se encuentra nada parecido a oldname
0 si concuerda exactamente
1 si se corrigio
guarda el nombre correcto en newname
*/
// ==========================
int spname(char *oldname, char *newname)
{
char *p, guess[DIRSIZE+1], best[DIRSIZE+1], *new=newname, *old=oldname;
for(;;)
{
while(*old == '/') *new++ = *old++; // saltar las diagonales
*new = '\0';
if(*old == '\0') return strcmp(oldname, newname) != 0; // exacto o corregido
p = guess; // copiar el siguiente componente en el nombre supuesto
for( ; *old != '/' && *old != '\0'; old++)
if(p < guess + DIRSIZE) *p++ = *old;
*p = '\0';
if(mindist(newname, guess, best) >= 3) return -1; // nada que hacer
for(p = best; *new = *p++; ) new++; // agregar al final de newname
}
}
// Buscar nombre supuesto en el directorio
// ==========================
int mindist(char *dir, char *guess, char *best)
{
int d, nd, fd;
struct // escoge el mejor, retorna la distancia 0..3
{
ino_t ino;
char name[DIRSIZE+1]; // 1 mas que en dir.h
} nbuf;
nbuf.name[DIRSIZE] = '\0'; // +1 para el '\0' terminal
if(dir[0] == '\0') dir = "."; // directorio actual
d = 3; // distancia minima
if((fd = open(dir, 0)) == -1) return d;
while(read(fd, (char*) &nbuf, sizeof(struct direct)) > 0)
if(nbuf.ino)
{
nd = spdist(nbuf.name, guess);
if(nd <= d && nd != 3)
{
strcpy(best, nbuf.name);
d = nd;
if(d == 0) break; // correspondencia exacta
}
}
close(fd);
return d;
}
int main(int Argc, char **Argv)
{
FILE *fp, *efopen();
int i, pagesize = PAGESIZE;
char *p, *getenv(), buf[BUFSIZ];
progname = malloc(sizeof(char)*80);
strcpy(progname, Argv[0]);
if ((p = getenv("PAGESIZE")) != NULL) pagesize = atoi(p);
if ((Argc > 1) && Argv[1][0] == '-')
{
pagesize = atoi(&Argv[1][1]);
Argc--;
Argv++;
}
if (Argc == 1) print(stdin, pagesize);
else
for (i = 1; i < Argc; i++)
switch (spname(Argv[i], buf))
{
case -1: // no hay correspondencia posible
fp = efopen(Argv[i], "r"); break;
case 1:
fprintf(stderr, "\"%s\"? ", buf);
if (ttyin() == 'n') break;
Argv[i] = buf; // aborta
case 0: // correspondencia exácta
fp = efopen(Argv[i], "r");
print(fp, pagesize);
fclose(fp);
}
exit(0);
}