#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); }