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