home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2284 / lid.c
C/C++ Source or Header  |  1990-12-28  |  21KB  |  1,011 lines

  1. static char copyright[] = "@(#)Copyright (c) 1986, Greg McGary";
  2. static char sccsid[] = "@(#)lid.c    1.4 86/11/06";
  3.  
  4. #include    <bool.h>
  5. #include    <stdio.h>
  6. #include    <string.h>
  7. #include    <ctype.h>
  8. #include    <signal.h>
  9. #include    <errno.h>
  10. #include    <radix.h>
  11. #include    <id.h>
  12. #include    <bitops.h>
  13. #include    <extern.h>
  14.  
  15. #ifdef REGEX
  16. extern char *regex();
  17. extern char *regcmp();
  18. #endif
  19. #ifdef RE_EXEC
  20. extern char *re_comp();
  21. extern int re_exec();
  22. #endif
  23.  
  24. bool isMagic();
  25. char **bitsToArgv();
  26. char *fileRE();
  27. char *strcpos();
  28. int skipToArgv();
  29. int findAnchor();
  30. int findApropos();
  31. #if REGEX || RE_EXEC
  32. int findRegExp();
  33. #endif
  34. int matchPaths();
  35. int findNonUnique();
  36. int findNumber();
  37. int findPlain();
  38. int idCompare();
  39. long searchName();
  40. void editId();
  41. void grepId();
  42. void lookId();
  43.  
  44. #ifdef USG
  45. #define    TOLOWER(c)    (isupper(c) ? _tolower(c) : (c))
  46. #else
  47. #define    TOLOWER(c)    (isupper(c) ? tolower(c) : (c))
  48. #endif
  49.  
  50. /*
  51. *  Sorry about all the globals, but it's really cleaner this way.
  52. */
  53. FILE        *IdFILE;
  54. bool        Merging;
  55. bool        Radix;
  56. bool            EchoOn = TRUE;
  57. bool            CrunchOn = TRUE;
  58. bool        pathRegExp = FALSE;
  59. bool        matchBase = FALSE;
  60. char        IdDir[BUFSIZ];
  61. long        AnchorOffset;
  62. int        BitArraySize;
  63. char        PWDname[BUFSIZ];
  64. struct idhead    Idh;
  65. struct idarg    *IdArgs;
  66. int        (*FindFunc)() = NULL;
  67. int        Solo = 0;
  68. #define    IGNORE_SOLO(buf) \
  69. ( \
  70.        (Solo == '-' && !(ID_FLAGS(buf) & IDN_SOLO)) \
  71.     || (Solo == '+' &&  (ID_FLAGS(buf) & IDN_SOLO)) \
  72. )
  73.  
  74. char *MyName;
  75. static void
  76. usage()
  77. {
  78.     fprintf(stderr, "Usage: %s [-f<file>] [-u<n>] [-r<dir>] [-mewdoxasknc] patterns...\n", MyName);
  79.     exit(1);
  80. }
  81. main(argc, argv)
  82.     int        argc;
  83.     char        **argv;
  84. {
  85.     char        *idFile = IDFILE;
  86.     char        *arg;
  87.     long        val;
  88.     void        (*doit)();
  89.     bool        forceMerge = FALSE;
  90.     int        uniqueLimit = 0;
  91.     int        useIDpath = TRUE;
  92.     int        usePWDpath = FALSE;
  93.     int        useRELpath = FALSE;
  94.     char *        RELpath;
  95.     int        op;
  96.  
  97.     MyName = basename(GETARG(argc, argv));
  98.  
  99.     while (argc) {
  100.         arg = GETARG(argc, argv);
  101.         switch (op = *arg++)
  102.         {
  103.         case '-':
  104.         case '+':
  105.             break;
  106.         default:
  107.             UNGETARG(argc, argv);
  108.             goto argsdone;
  109.         }
  110.         while (*arg) switch (*arg++)
  111.         {
  112.         case 'f': idFile = arg; goto nextarg;
  113.         case 'u': uniqueLimit = stoi(arg); goto nextarg;
  114.         case 'm': forceMerge = TRUE; break;
  115. #if REGEX || RE_EXEC
  116.         case 'e': FindFunc = findRegExp; pathRegExp = TRUE; break;
  117. #endif
  118.         case 'w': FindFunc = findPlain; break;
  119.         case 'd': Radix |= RADIX_DEC; break;
  120.         case 'o': Radix |= RADIX_OCT; break;
  121.         case 'x': Radix |= RADIX_HEX; break;
  122.         case 'a': Radix |= RADIX_ALL; break;
  123.         case 's': Solo = op; break;
  124.         case 'k': CrunchOn = FALSE; break;
  125.         case 'n': EchoOn = FALSE; break;
  126.         case 'c': useIDpath = FALSE; usePWDpath = TRUE; break;
  127.         case 'b': matchBase = TRUE; break;
  128.         case 'r': useIDpath = FALSE; useRELpath = TRUE;
  129.             RELpath = arg; goto nextarg;
  130.         default:
  131.             usage();
  132.         }
  133.     nextarg:;
  134.     }
  135. argsdone:
  136.  
  137.     if (usePWDpath && useRELpath) {
  138.         fprintf(stderr,"%s: please use only one of -c or -r\n",MyName);
  139.         usage();
  140.     }
  141.     /* Look for the ID database up the tree */
  142.     if ((idFile = LookUp(idFile)) == NULL) {
  143.         filerr("open", idFile);
  144.         exit(1);
  145.     }
  146.     /* Find out current directory to relate names to */
  147.     if (kshgetwd(PWDname) == NULL) {
  148.         fprintf(stderr,"%s: cannot determine current directory\n",MyName);
  149.         exit(1);
  150.     }
  151.     strcat(PWDname,"/");
  152.     /* Determine absolute path name that database files are relative to */
  153.     if (useIDpath) {
  154.         strcpy(IdDir, spanPath(PWDname, idFile));
  155.         *(strrchr(IdDir, '/') + 1) = '\0';
  156.     } else if (usePWDpath) {
  157.         strcpy(IdDir, PWDname);
  158.     } else {
  159.         strcpy(IdDir, spanPath(PWDname, RELpath));
  160.         strcat(IdDir, "/");
  161.     }
  162.     if ((IdFILE = initID(idFile, &Idh, &IdArgs)) == NULL) {
  163.         filerr("open", idFile);
  164.         exit(1);
  165.     }
  166.     BitArraySize = (Idh.idh_pthc + 7) >> 3;
  167.  
  168.     switch (MyName[0])
  169.     {
  170.     case 'a':
  171.         FindFunc = findApropos;
  172.         /*FALLTHROUGH*/
  173.     case 'l':
  174.         doit = lookId;
  175.         break;
  176.     case 'g':
  177.         doit = grepId;
  178.         break;
  179.     case 'e':
  180.         doit = editId;
  181.         break;
  182.     case 'p':
  183.         FindFunc = matchPaths;
  184.         doit = lookId;
  185.         break;
  186.     default:
  187.         MyName = "[algep]id";
  188.         usage();
  189.     }
  190.  
  191.     if (argc == 0) {
  192.         UNGETARG(argc, argv);
  193.         *argv = ".";
  194.     }
  195.  
  196.     while (argc) {
  197.         arg = GETARG(argc, argv);
  198.         if (FindFunc)
  199.             ;
  200.         else if ((radix(arg)) && (val = stoi(arg)) >= 0)
  201.             FindFunc = findNumber;
  202. #if REGEX || RE_EXEC
  203.         else if (isMagic(arg))
  204.             FindFunc = findRegExp;
  205. #endif
  206.         else if (arg[0] == '^')
  207.             FindFunc = findAnchor;
  208.         else
  209.             FindFunc = findPlain;
  210.  
  211.         if ((doit == lookId && !forceMerge)
  212.         || (FindFunc == findNumber && bitCount(Radix) > 1 && val > 7))
  213.             Merging = FALSE;
  214.         else
  215.             Merging = TRUE;
  216.  
  217.         if (uniqueLimit) {
  218.             if (!findNonUnique(uniqueLimit, doit))
  219.                 fprintf(stderr, "All identifiers are unique within the first %d characters\n", uniqueLimit);
  220.             exit(0);
  221.         } else if (!(*FindFunc)(arg, doit)) {
  222.             fprintf(stderr, "%s: not found\n", arg);
  223.             continue;
  224.         }
  225.     }
  226.     exit(0);
  227. }
  228.  
  229. void
  230. lookId(name, argv)
  231.     char        *name;
  232.     register char    **argv;
  233. {
  234.     register char    *arg;
  235.     register bool    crunching = FALSE;
  236.     register char    *dir;
  237.  
  238.     if (EchoOn) printf("%-14s ", name);
  239.     while (*argv) {
  240.         arg = *argv++;
  241.         if (*argv && CrunchOn && canCrunch(arg, *argv)) {
  242.             if (crunching)
  243.                 printf(",%s", rootName(arg));
  244.             else if ((dir = dirname(arg)) && dir[0] == '.' && dir[1] == '\0')
  245.                 printf("{%s", rootName(arg));
  246.             else
  247.                 printf("%s/{%s", dir, rootName(arg));
  248.             /*}}*/
  249.             crunching = TRUE;
  250.         } else {
  251.             if (crunching) /*{*/
  252.                 printf(",%s}%s", rootName(arg), suffName(arg));
  253.             else
  254.                 fputs(arg, stdout);
  255.             crunching = FALSE;
  256.             if (*argv)
  257.                 putchar(' ');
  258.         }
  259.     }
  260.     putchar('\n');
  261. }
  262.  
  263. void
  264. grepId(name, argv)
  265.     char        *name;
  266.     char        **argv;
  267. {
  268.     FILE        *gidFILE;
  269.     char        *gidName;
  270.     char        buf[BUFSIZ];
  271.     char        *delimit = "[^a-zA-Z0-9_]";
  272.     char        *re;
  273.     char        *reCompiled;
  274.     int        lineNumber;
  275.  
  276.     if (!Merging || (re = fileRE(name, delimit, delimit)) == NULL)
  277.         re = NULL;
  278. #ifdef REGEX
  279.     else if ((reCompiled = regcmp(re, 0)) == NULL) {
  280.         fprintf(stderr, "%s: Syntax Error: %s\n", MyName, re);
  281.         return;
  282.     }
  283. #endif
  284. #ifdef RE_EXEC
  285.     else if ((reCompiled = re_comp(re)) != NULL) {
  286.         fprintf(stderr, "%s: Syntax Error: %s (%s)\n", MyName, re, reCompiled);
  287.         return;
  288.     }
  289. #endif
  290.  
  291.     buf[0] = ' ';    /* sentry */
  292.     while (*argv) {
  293.         if ((gidFILE = fopen(gidName = *argv++, "r")) == NULL) {
  294.             filerr("open", gidName);
  295.             continue;
  296.         }
  297.         lineNumber = 0;
  298.         while (fgets(&buf[1], sizeof(buf), gidFILE)) {
  299.             lineNumber++;
  300.             if (re) {
  301. #ifdef REGEX
  302.                 if (regex(reCompiled, buf) == NULL)
  303. #endif
  304. #ifdef RE_EXEC
  305.                 if (!re_exec(buf))
  306. #endif
  307.                     continue;
  308.             } else if (!wordMatch(name, buf))
  309.                 continue;
  310.             printf("%s:%d: %s", gidName, lineNumber, &buf[1]);
  311.         }
  312.         fclose(gidFILE);
  313.     }
  314. }
  315.  
  316. void
  317. editId(name, argv)
  318.     char        *name;
  319.     char        **argv;
  320. {
  321.     char        reBuf[BUFSIZ];
  322.     char        edArgBuf[BUFSIZ];
  323.     char        *re;
  324.     int        c;
  325.     int        skip;
  326.     static char    *editor, *eidArg, *eidRightDel, *eidLeftDel;
  327.  
  328.     if (editor == NULL && (editor = getenv("EDITOR")) == NULL) {
  329.         char    *ucb_vi = "/usr/ucb/vi";
  330.         char    *bin_vi = "/usr/bin/vi";
  331.  
  332.         if (access(ucb_vi, 01) == 0)
  333.             editor = ucb_vi;
  334.         else if (access(bin_vi, 01) == 0)
  335.             editor = bin_vi;
  336.         else
  337.             editor = "/bin/ed";    /* YUCK! */
  338.         if (editor == ucb_vi || editor == bin_vi) {
  339.             eidArg = "+1;/%s/";
  340.             eidLeftDel = "\\<";
  341.             eidRightDel = "\\>";
  342.         }
  343.     }
  344.     if (eidLeftDel == NULL) {
  345.         eidArg = getenv("EIDARG");
  346.         if ((eidLeftDel = getenv("EIDLDEL")) == NULL)
  347.             eidLeftDel = "";
  348.         if ((eidRightDel = getenv("EIDRDEL")) == NULL)
  349.             eidRightDel = "";
  350.     }
  351.  
  352.     lookId(name, argv);
  353.     savetty();
  354.     for (;;) {
  355.         printf("Edit? [y1-9^S/nq] "); fflush(stdout);
  356.         chartty();
  357.         c = (getchar() & 0177);
  358.         restoretty();
  359.         switch (TOLOWER(c))
  360.         {
  361.         case '/': case ('s'&037):
  362.             putchar('/');
  363.             /*FALLTHROUGH*/
  364.             if ((skip = skipToArgv(argv)) < 0)
  365.                 continue;
  366.             argv += skip;
  367.             goto editit;
  368.         case '1': case '2': case '3': case '4':
  369.         case '5': case '6': case '7': case '8': case '9':
  370.             putchar(c);
  371.             skip = c - '0';
  372.             break;
  373.         case 'y':
  374.             putchar(c);
  375.             /*FALLTHROUGH*/
  376.         case '\n':
  377.         case '\r':
  378.             skip = 0;
  379.             break;
  380.         case 'q':
  381.             putchar(c);
  382.             putchar('\n');
  383.             exit(0);
  384.         case 'n':
  385.             putchar(c);
  386.             putchar('\n');
  387.             return;
  388.         default:
  389.             putchar(c);
  390.             putchar('\n');
  391.             continue;
  392.         }
  393.  
  394.         putchar('\n');
  395.         while (skip--)
  396.             if (*++argv == NULL)
  397.                 continue;
  398.         break;
  399.     }
  400. editit:
  401.  
  402.     if (!Merging || (re = fileRE(name, eidLeftDel, eidRightDel)) == NULL)
  403.         sprintf(re = reBuf, "%s%s%s", eidLeftDel, name, eidRightDel);
  404.  
  405.     switch (fork())
  406.     {
  407.     case -1:
  408.         fprintf(stderr, "%s: Cannot fork (%s)\n", MyName, uerror());
  409.         exit(1);
  410.     case 0:
  411.         argv--;
  412.         if (eidArg) {
  413.             argv--;
  414.             sprintf(edArgBuf, eidArg, re);
  415.             argv[1] = edArgBuf;
  416.         }
  417.         argv[0] = editor;
  418.         execv(editor, argv);
  419.         filerr("exec", editor);
  420.     default:
  421.         {
  422.             int (*oldint)() = signal(SIGINT, SIG_IGN);
  423.             int (*oldquit)() = signal(SIGQUIT, SIG_IGN);
  424.  
  425.             while(wait(0) == -1 && errno == EINTR)
  426.                 /* loop */;
  427.  
  428.             (void) signal(SIGINT, oldint);
  429.             (void) signal(SIGQUIT, oldquit);
  430.         }
  431.         break;
  432.     }
  433. }
  434.  
  435. int
  436. skipToArgv(argv)
  437.     char        **argv;
  438. {
  439.     char        pattern[BUFSIZ];
  440.     int        count;
  441.  
  442.     if (gets(pattern) == NULL)
  443.         return -1;
  444.     
  445.     for (count = 0; *argv; count++, argv++)
  446.         if (strcpos(*argv, pattern))
  447.             return count;
  448.     return -1;
  449. }
  450.  
  451. int
  452. findPlain(arg, doit)
  453.     char        *arg;
  454.     void        (*doit)();
  455. {
  456.     static char    *buf, *bitArray;
  457.     int        size;
  458.  
  459.     if (searchName(arg) == 0)
  460.         return 0;
  461.     if (buf == NULL) {
  462.         buf = malloc(Idh.idh_bsiz);
  463.         bitArray = malloc(BitArraySize);
  464.     }
  465.     bzero(bitArray, BitArraySize);
  466.  
  467.     if ((size = fgets0(buf, Idh.idh_bsiz, IdFILE)) == 0)
  468.         return 0;
  469.     size++;
  470.     getsFF(&buf[size], IdFILE);
  471.     if (IGNORE_SOLO(buf))
  472.         return 0;
  473.  
  474.     vecToBits(bitArray, &buf[size], Idh.idh_vecc);
  475.     (*doit)(ID_STRING(buf), bitsToArgv(bitArray));
  476.     return 1;
  477. }
  478.  
  479. int
  480. findAnchor(arg, doit)
  481.     register char    *arg;
  482.     void        (*doit)();
  483. {
  484.     static char    *buf, *bitArray;
  485.     int        count, size;
  486.     int        len;
  487.  
  488.     if (searchName(++arg) == 0)
  489.         return 0;
  490.  
  491.     if (buf == NULL) {
  492.         buf = malloc(Idh.idh_bsiz);
  493.         bitArray = malloc(BitArraySize);
  494.     }
  495.     bzero(bitArray, BitArraySize);
  496.  
  497.     len = strlen(arg);
  498.     count = 0;
  499.     while ((size = fgets0(buf, Idh.idh_bsiz, IdFILE)) > 0) {
  500.         size++;
  501.         getsFF(&buf[size], IdFILE);
  502.         if (IGNORE_SOLO(buf))
  503.             continue;
  504.         if (!strnequ(arg, ID_STRING(buf), len))
  505.             break;
  506.         vecToBits(bitArray, &buf[size], Idh.idh_vecc);
  507.         if (!Merging) {
  508.             (*doit)(ID_STRING(buf), bitsToArgv(bitArray));
  509.             bzero(bitArray, BitArraySize);
  510.         }
  511.         count++;
  512.     }
  513.     if (Merging && count)
  514.         (*doit)(--arg, bitsToArgv(bitArray));
  515.  
  516.     return count;
  517. }
  518.  
  519. #if REGEX || RE_EXEC
  520. int
  521. findRegExp(re, doit)
  522.     char        *re;
  523.     void        (*doit)();
  524. {
  525.     static char    *buf, *bitArray;
  526.     int        count, size;
  527.     char        *reCompiled;
  528.  
  529. #ifdef REGEX
  530.     if ((reCompiled = regcmp(re, 0)) == NULL) {
  531.         fprintf(stderr, "%s: Syntax Error: %s\n", MyName, re);
  532.         return 0;
  533.     }
  534. #endif
  535. #ifdef RE_EXEC
  536.     if ((reCompiled = re_comp(re)) != NULL) {
  537.         fprintf(stderr, "%s: Syntax Error: %s (%s)\n", MyName, re, reCompiled);
  538.         return 0;
  539.     }
  540. #endif
  541.     fseek(IdFILE, Idh.idh_namo, 0);
  542.  
  543.     if (buf == NULL) {
  544.         buf = malloc(Idh.idh_bsiz);
  545.         bitArray = malloc(BitArraySize);
  546.     }
  547.     bzero(bitArray, BitArraySize);
  548.  
  549.     count = 0;
  550.     while ((size = fgets0(buf, Idh.idh_bsiz, IdFILE)) > 0) {
  551.         size++;
  552.         getsFF(&buf[size], IdFILE);
  553.         if (IGNORE_SOLO(buf))
  554.             continue;
  555. #ifdef REGEX
  556.         if (regex(reCompiled, ID_STRING(buf)) == NULL)
  557. #endif
  558. #ifdef RE_EXEC
  559.         if (!re_exec(ID_STRING(buf)))
  560. #endif
  561.             continue;
  562.         vecToBits(bitArray, &buf[size], Idh.idh_vecc);
  563.         if (!Merging) {
  564.             (*doit)(ID_STRING(buf), bitsToArgv(bitArray));
  565.             bzero(bitArray, BitArraySize);
  566.         }
  567.         count++;
  568.     }
  569.     if (Merging && count)
  570.         (*doit)(re, bitsToArgv(bitArray));
  571.  
  572.     return count;
  573. }
  574. #endif
  575.  
  576. int
  577. findNumber(arg, doit)
  578.     char        *arg;
  579.     void        (*doit)();
  580. {
  581.     static char    *buf, *bitArray;
  582.     int        count, size;
  583.     register int    rdx = 0;
  584.     register int    val;
  585.     register bool    hitDigits = FALSE;
  586.  
  587.     if ((val = stoi(arg)) <= 7)
  588.         rdx |= RADIX_ALL;
  589.     else
  590.         rdx = radix(arg);
  591.     fseek(IdFILE, Idh.idh_namo, 0);
  592.  
  593.     if (buf == NULL) {
  594.         buf = malloc(Idh.idh_bsiz);
  595.         bitArray = malloc(BitArraySize);
  596.     }
  597.     bzero(bitArray, BitArraySize);
  598.  
  599.     count = 0;
  600.     while ((size = fgets0(buf, Idh.idh_bsiz, IdFILE)) > 0) {
  601.         size++;
  602.         getsFF(&buf[size], IdFILE);
  603.         if (hitDigits) {
  604.             if (!isdigit(*ID_STRING(buf)))
  605.                 break;
  606.         } else if (isdigit(*ID_STRING(buf)))
  607.             hitDigits = TRUE;
  608.  
  609.         if (!((Radix ? Radix : rdx) & radix(ID_STRING(buf)))
  610.         || stoi(ID_STRING(buf)) != val)
  611.             continue;
  612.         vecToBits(bitArray, &buf[size], Idh.idh_vecc);
  613.         if (!Merging) {
  614.             (*doit)(ID_STRING(buf), bitsToArgv(bitArray));
  615.             bzero(bitArray, BitArraySize);
  616.         }
  617.         count++;
  618.     }
  619.     if (Merging && count)
  620.         (*doit)(arg, bitsToArgv(bitArray));
  621.  
  622.     return count;
  623. }
  624.  
  625. /*
  626.     Find identifiers that are non-unique within
  627.     the first `count' characters.
  628. */
  629. int
  630. findNonUnique(limit, doit)
  631.     int        limit;
  632.     void        (*doit)();
  633. {
  634.     static char    *buf1, *buf2, *bitArray;
  635.     register char    *old;
  636.     register char    *new;
  637.     register int    consecutive;
  638.     char        *cptmp;
  639.     int        itmp;
  640.     int        count, oldsize, newsize;
  641.     char        *name;
  642.  
  643.     if (limit <= 1)
  644.         usage();
  645.  
  646.     fseek(IdFILE, Idh.idh_namo, 0);
  647.  
  648.     if (buf1 == NULL) {
  649.         buf1 = malloc(Idh.idh_bsiz);
  650.         buf2 = malloc(Idh.idh_bsiz);
  651.         bitArray = malloc(BitArraySize);
  652.     }
  653.     bzero(bitArray, BitArraySize);
  654.  
  655.     name = calloc(1, limit+2);
  656.     name[0] = '^';
  657.     old = buf1;
  658.     *ID_STRING(new = buf2) = '\0';
  659.     count = consecutive = 0;
  660.     while ((oldsize = fgets0(old, Idh.idh_bsiz, IdFILE)) > 0) {
  661.         oldsize++;
  662.         getsFF(&old[oldsize], IdFILE);
  663.         if (!(ID_FLAGS(old) & IDN_NAME))
  664.             continue;
  665.         cptmp = old; old = new; new = cptmp;
  666.         itmp = oldsize; oldsize = newsize; newsize = itmp;
  667.         if (!strnequ(ID_STRING(new), ID_STRING(old), limit)) {
  668.             if (consecutive && Merging) {
  669.                 strncpy(&name[1], ID_STRING(old), limit); 
  670.                 (*doit)(name, bitsToArgv(bitArray));
  671.             }
  672.             consecutive = 0;
  673.             continue;
  674.         }
  675.         if (!consecutive++) {
  676.             vecToBits(bitArray, &old[oldsize], Idh.idh_vecc);
  677.             if (!Merging) {
  678.                 (*doit)(ID_STRING(old), bitsToArgv(bitArray));
  679.                 bzero(bitArray, BitArraySize);
  680.             }
  681.             count++;
  682.         }
  683.         vecToBits(bitArray, &new[newsize], Idh.idh_vecc);
  684.         if (!Merging) {
  685.             (*doit)(ID_STRING(new), bitsToArgv(bitArray));
  686.             bzero(bitArray, BitArraySize);
  687.         }
  688.         count++;
  689.     }
  690.  
  691.     return count;
  692. }
  693.  
  694. int
  695. findApropos(arg, doit)
  696.     char        *arg;
  697.     void        (*doit)();
  698. {
  699.     static char    *buf, *bitArray;
  700.     int        count, size;
  701.  
  702.     fseek(IdFILE, Idh.idh_namo, 0);
  703.  
  704.     if (buf == NULL) {
  705.         buf = malloc(Idh.idh_bsiz);
  706.         bitArray = malloc(BitArraySize);
  707.     }
  708.     bzero(bitArray, BitArraySize);
  709.  
  710.     count = 0;
  711.     while ((size = fgets0(buf, Idh.idh_bsiz, IdFILE)) > 0) {
  712.         size++;
  713.         getsFF(&buf[size], IdFILE);
  714.         if (IGNORE_SOLO(buf))
  715.             continue;
  716.         if (strcpos(ID_STRING(buf), arg) == NULL)
  717.             continue;
  718.         vecToBits(bitArray, &buf[size], Idh.idh_vecc);
  719.         if (!Merging) {
  720.             (*doit)(ID_STRING(buf), bitsToArgv(bitArray));
  721.             bzero(bitArray, BitArraySize);
  722.         }
  723.         count++;
  724.     }
  725.     if (Merging && count)
  726.         (*doit)(arg, bitsToArgv(bitArray));
  727.  
  728.     return count;
  729. }
  730.  
  731. /*
  732.     if string `s2' occurs in `s1', return a pointer to the
  733.     first match.  Ignore differences in alphabetic case.
  734. */
  735. char *
  736. strcpos(s1, s2)
  737.     char        *s1;
  738.     char        *s2;
  739. {
  740.     register char    *s1p;
  741.     register char    *s2p;
  742.     char        *s1last;
  743.  
  744.     for (s1last = &s1[strlen(s1) - strlen(s2)]; s1 <= s1last; s1++)
  745.         for (s1p = s1, s2p = s2; TOLOWER(*s1p) == TOLOWER(*s2p); s1p++)
  746.             if (*++s2p == '\0')
  747.                 return s1;
  748.     return NULL;
  749. }
  750.  
  751. /*
  752.     Convert the regular expression that we used to
  753.     locate identifiers in the id database into one
  754.     suitable for locating the identifiers in files.
  755. */
  756. char *
  757. fileRE(name0, leftDelimit, rightDelimit)
  758.     char        *name0;
  759.     char        *leftDelimit;
  760.     char        *rightDelimit;
  761. {
  762.     static char    reBuf[BUFSIZ];
  763.     register char    *name = name0;
  764.  
  765.     if (FindFunc == findNumber && Merging) {
  766.         sprintf(reBuf, "%s0*[Xx]*0*%d[Ll]*%s", leftDelimit, stoi(name), rightDelimit);
  767.         return reBuf;
  768.     }
  769.  
  770.     if (!isMagic(name) && name[0] != '^')
  771.         return NULL;
  772.  
  773.     if (name[0] == '^')
  774.         name0++;
  775.     else
  776.         leftDelimit = "";
  777.     while (*++name)
  778.         ;
  779.     if (*--name == '$')
  780.         *name = '\0';
  781.     else
  782.         rightDelimit = "";
  783.  
  784.     sprintf(reBuf, "%s%s%s", leftDelimit, name0, rightDelimit);
  785.     return reBuf;
  786. }
  787.  
  788. long
  789. searchName(name)
  790.     char        *name;
  791. {
  792.     long        offset;
  793.  
  794.     AnchorOffset = 0;
  795.     offset = (long)bsearch(name, (char *)(Idh.idh_namo-1), Idh.idh_endo-(Idh.idh_namo-1), 1, idCompare);
  796.     if (offset == 0)
  797.         offset = AnchorOffset;
  798.     if (offset == 0)
  799.         return 0;
  800.     fseek(IdFILE, offset, 0);
  801.     skipFF(IdFILE);
  802.     return ftell(IdFILE);
  803. }
  804.  
  805. int
  806. idCompare(key, offset)
  807.     register char    *key;
  808.     long        offset;
  809. {
  810.     register int    c;
  811.  
  812.     fseek(IdFILE, offset, 0);
  813.     skipFF(IdFILE);
  814.     getc(IdFILE);
  815.  
  816.     while (*key == (c = getc(IdFILE)))
  817.         if (*key++ == '\0')
  818.             return 0;
  819.     if (*key == '\0' && FindFunc == findAnchor)
  820.         AnchorOffset = offset;
  821.  
  822.     return *key - c;
  823. }
  824.  
  825. /*
  826.     Are there any magic Regular Expression meta-characters in name??
  827. */
  828. bool
  829. isMagic(name)
  830.     register char    *name;
  831. {
  832.     char        *magichar = "[]{}().*+^$";
  833.     int        backslash = 0;
  834.  
  835.     if (*name == '^')
  836.         name++;
  837.     while (*name) {
  838.         if (*name == '\\')
  839.             name++, backslash++;
  840.         else if (strchr(magichar, *name))
  841.             return TRUE;
  842.         name++;
  843.     }
  844.     if (backslash)
  845.         while (*name) {
  846.             if (*name == '\\')
  847.                 strcpy(name, name+1);
  848.             name++;
  849.         }
  850.     return FALSE;
  851. }
  852.  
  853. char **
  854. bitsToArgv(bitArray)
  855.     char        *bitArray;
  856. {
  857.     char *        absname;
  858.     char *        relname;
  859.     static char    **argv;
  860.     struct idarg    *idArgs;
  861.     register char    **av;
  862.     register int    i;
  863. #define    ARGV1stPATH    3 /* available argv[] slots before first pathname */
  864.  
  865.     if (argv == NULL)
  866.         argv = (char **)malloc(sizeof(char *) * (Idh.idh_pthc + ARGV1stPATH + 2));
  867.  
  868.     av = argv + ARGV1stPATH;
  869.     for (idArgs = IdArgs, i = 0; i < Idh.idh_pthc; i++, idArgs++) {
  870.         if (!BITTST(bitArray, i))
  871.             continue;
  872.         if (idArgs->ida_flags & IDA_BLANK) {
  873.             printf("BOTCH: blank index!\n");
  874.             abort();
  875.         }
  876.         if (!(idArgs->ida_flags & IDA_ADJUST)) {
  877.             absname = spanPath(IdDir, idArgs->ida_arg);
  878.             relname = relPath(PWDname, absname);
  879.             idArgs->ida_arg = strsav(strlen(relname) > strlen(absname) ? absname : relname);
  880.             idArgs->ida_flags |= IDA_ADJUST;
  881.         }
  882.         *av++ = idArgs->ida_arg;
  883.     }
  884.     *av = NULL;
  885.     return (argv + ARGV1stPATH);
  886. }
  887.  
  888. /* pathWildCard implements a simple pattern matcher that emulates the
  889.  * shell wild card capability.
  890.  *
  891.  *   * - any string of chars
  892.  *   ? - any char
  893.  *   [] - any char in set (if first char is !, any not in set)
  894.  *   \ - literal match next char
  895.  */
  896. int
  897. pathWildCard(re, fn)
  898.     char        *re;
  899.     char        *fn;
  900. {
  901.     register int    c;
  902.     register int    i;
  903.     char        set[256];
  904.     int        revset;
  905.  
  906.     while ((c = *re++) != '\0') {
  907.            if (c == '*') {
  908.                if (*re == '\0') return 1; /* match anything at end */
  909.                while (*fn != '\0') {
  910.                   if (pathWildCard(re,fn)) return 1;
  911.                   ++fn;
  912.                }
  913.                return 0;
  914.            } else if (c == '?') {
  915.                if (*fn++ == '\0') return 0;
  916.            } else if (c == '[') {
  917.                c = *re++;
  918.                bzero(set,256);
  919.                if (c == '!') {
  920.                    revset=1;
  921.                    c = *re++;
  922.                } else {
  923.                    revset=0;
  924.                }
  925.                while (c != ']') {
  926.                   if (c == '\\') c = *re++;
  927.                   set[c]=1;
  928.                   if ((*re == '-') && (*(re+1) != ']')) {
  929.                      re+=1;
  930.                      while (++c <= *re) set[c]=1;
  931.                      ++re;
  932.                   }
  933.                   c = *re++;
  934.                }
  935.                if (revset) for (i=1;i<256;++i) set[i] = ! set[i];
  936.                if (! set[*fn++]) return 0;
  937.            } else {
  938.                if (c == '\\') c = *re++;
  939.                if (c != *fn++) return 0;
  940.            }
  941.     }
  942.     return(*fn == '\0');
  943. }
  944.  
  945. /* matchPaths implements the pid tool. This matches the *names* of files
  946.  * in the database against the input pattern rather than the *contents*
  947.  * of the files.
  948.  */
  949. int
  950. matchPaths(re, doit)
  951.     char        *re;
  952.     void        (*doit)();
  953. {
  954.     char *        absname;
  955.     static char    *bitArray;
  956.     struct idarg    *idArgs;
  957.     register int    i;
  958.     char        *reCompiled;
  959.     int        count=0;
  960.     int        matched;
  961.  
  962.     if (pathRegExp) {
  963. #ifdef REGEX
  964.         if ((reCompiled = regcmp(re, 0)) == NULL) {
  965.             fprintf(stderr, "%s: Syntax Error: %s\n", MyName, re);
  966.             return 0;
  967.         }
  968. #endif
  969. #ifdef RE_EXEC
  970.         if ((reCompiled = re_comp(re)) != NULL) {
  971.             fprintf(stderr, "%s: Syntax Error: %s (%s)\n", MyName, re, reCompiled);
  972.             return 0;
  973.         }
  974. #endif
  975.     }
  976.  
  977.     if (bitArray == NULL) {
  978.         bitArray = malloc(BitArraySize);
  979.     }
  980.     bzero(bitArray, BitArraySize);
  981.  
  982.     for (idArgs = IdArgs, i = 0; i < Idh.idh_pthc; i++, idArgs++) {
  983.         if (idArgs->ida_flags & IDA_BLANK) continue;
  984.         if (matchBase) {
  985.             absname = strrchr(idArgs->ida_arg, '/');
  986.             if (absname == NULL) {
  987.                 absname = idArgs->ida_arg;
  988.             }
  989.         } else {
  990.             absname = spanPath(IdDir, idArgs->ida_arg);
  991.         }
  992.         if (pathRegExp) {
  993. #ifdef REGEX
  994.             matched = (regex(reCompiled, absname) != NULL);
  995. #endif
  996. #ifdef RE_EXEC
  997.             matched = (re_exec(absname));
  998. #endif
  999.         } else {
  1000.             matched = pathWildCard(re, absname);
  1001.         }
  1002.         if (matched) {
  1003.             BITSET(bitArray, i);
  1004.             ++count;
  1005.         }
  1006.     }
  1007.     if (count)
  1008.         (*doit)(re, bitsToArgv(bitArray));
  1009.     return count;
  1010. }
  1011.