home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume15 / look_rac / part01 / look.c next >
C/C++ Source or Header  |  1990-12-16  |  4KB  |  185 lines

  1. /*
  2.  * look - search a sorted file for lines beginning with string
  3.  *  Roger Cornelius (rac@sherpa.uucp)
  4.  *  Fri Oct 26 13:13:54 EDT 1990
  5.  *  public domain
  6.  */
  7.  
  8. #define _USE_MACROS     /* for SCO UNIX, see ctype.h */
  9. #include <stdio.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #define ERR 2
  15.  
  16. extern void exit();
  17. int dstrncmp();
  18. off_t backup();
  19. FILE *fopen();
  20. int fold = 0;
  21. int dict = 0;
  22. int (*compare)();
  23.  
  24. main(argc, argv)
  25.     register int argc;
  26.     register char **argv;
  27. {
  28.     extern int optind;
  29.     char *file = "/usr/dict/words";
  30.     char *string;
  31.     int ch;
  32.     
  33.     while ((ch = getopt(argc, argv, "df?")) != -1)
  34.         switch(ch) {
  35.             case 'd':   dict = 1; break;
  36.             case 'f':   fold = 1; break;
  37.             case '?':   goto usage;
  38.         }
  39.     argc -= optind;
  40.     argv += optind;
  41.  
  42.     if (argc < 1 || argc > 2) {
  43. usage:  (void)fputs("Usage: look [-df] string [file]\n", stderr);
  44.         exit(ERR);
  45.     }
  46.     string = *argv;
  47.     if (*++argv)
  48.         file = *argv;
  49.     else
  50.         fold = dict = 1;
  51.  
  52.     return search(string, file);
  53. }
  54.  
  55. /*
  56.  * search --
  57.  *  search a sorted file for lines beginning with string
  58.  *  adapted from binsearch(), K&R 2nd ed.
  59.  */
  60. static
  61. search(string, file)
  62.     char *string;
  63.     char *file;
  64. {
  65.     FILE *fp;
  66.     char buf[BUFSIZ], save[BUFSIZ];
  67.     off_t low, mid, high, savemid = -1;
  68.     off_t found = -1;
  69.     register char *t;
  70.     struct stat sbuf;
  71.     size_t slen = strlen(string);
  72.     int n, res = 1;                 /* not found */
  73.  
  74.     if ((fp = freopen(file, "r", stdin)) == NULL
  75.     || stat(file, &sbuf) != 0) {
  76.         /* avoid the printf kitchen sink */
  77.         (void) fputs("look: can't access ", stderr);
  78.         (void) fputs(file, stderr);
  79.         (void) fputs("\n", stderr);
  80.         return ERR;
  81.     }
  82.     low = 0;
  83.     high = sbuf.st_size;
  84.     compare = dict ? dstrncmp : strncmp;
  85.     if (fold)
  86.         for (t=string; *t; *t = tolower(*t), t++)
  87.             ;
  88.  
  89.     while (low < high) {
  90.         mid = (low+high) / 2;
  91.         if (backup(&low, &mid, &high) == -1 || mid == savemid)
  92.             break;
  93.         savemid = mid;
  94.         if (fseek(fp, mid, 0) != 0 || gets(buf) == NULL)
  95.             return ERR;
  96.  
  97.         if (fold)
  98.             for (t=buf; *t; *t = tolower(*t), t++)
  99.                 ;
  100.         n = (*compare)(string, buf, slen);
  101.         if (n < 0)
  102.             high = mid - 1;
  103.         else if (n > 0)
  104.             low = mid + 1;
  105.         else {
  106.             found = mid;            /* save offset of found string */
  107.             high = mid - 1;
  108.             if (strlen(buf) == slen)
  109.                 break;
  110.         }
  111.     }
  112.     if (found >= 0) {
  113.         if (fseek(fp, found, 0) != 0)
  114.             return ERR;
  115.         while (gets(buf) != NULL) {
  116.             if (fold) {
  117.                 (void)strcpy(save, buf);
  118.                 for (t=buf; *t; *t = tolower(*t), t++)
  119.                     ;
  120.             }
  121.             if ((*compare)(string, buf, slen) != 0)
  122.                 break;
  123.             (void)puts(fold ? save : buf);
  124.         }
  125.         res = 0;                    /* found */
  126.     }
  127.     (void)fclose(fp);
  128.     return res;
  129. }
  130.  
  131. /*
  132.  * backup --
  133.  *  search backwards for newline - if none found
  134.  *  then reverse direction and start over
  135.  */
  136. static off_t
  137. backup(low, offset, high)
  138.     register off_t *low, *offset, *high;
  139. {
  140.     register int c;
  141.     register int inc = -1;
  142.     off_t save = *offset;
  143.  
  144.     if (*offset == 0)
  145.         return(*offset);
  146.  
  147.     for (; *offset < *high && fseek(stdin, *offset, 0) == 0; *offset += inc) {
  148.         c = getchar();
  149.         if (c == '\n' || *offset == 0)
  150.             return (*offset == 0) ? *offset : (*offset)++;
  151.         else if (c == EOF)      /* should never happen */
  152.             break;
  153.         if (*offset <= *low) {  /* start over, reversing direction */
  154.             *offset = save;
  155.             inc = 1;
  156.         }
  157.     }
  158.     return -1L;
  159. }
  160.  
  161. /*
  162.  * dstrncmp --
  163.  *  dictionary strncmp() - only alpha characters,
  164.  *  digits, blanks and tabs participate in comparisons
  165.  */
  166. static
  167. dstrncmp(s1, s2, n)
  168.     register char *s1, *s2;
  169.     register size_t n;
  170. {
  171.     for (; n--; s1++, s2++) {
  172.         while (*s1 && !(isalpha(*s1) || isdigit(*s1) || isspace(*s1)))
  173.             s1++;
  174.         if (*s1 == '\0')
  175.             break;
  176.         while (*s2 && !(isalpha(*s2) || isdigit(*s2) || isspace(*s2)))
  177.             s2++;
  178.         if (*s1 != *s2)
  179.             return *s1 - *s2;
  180.     }
  181.     return 0;
  182. }
  183.  
  184. /* end of look.c */
  185.