home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 100-199 / ff197.lzh / Find / find.c < prev    next >
C/C++ Source or Header  |  1989-03-28  |  22KB  |  969 lines

  1. /**********************************************************************/
  2. /*                                                                    */
  3. /* find - Amiga Version 1.2                                           */
  4. /*                                                                    */
  5. /* Copyright (c) 1988,89 - Rodney Lewis                               */
  6. /*                                                                    */
  7. /* This program is freely copyable and distributable. All copyrights  */
  8. /* are reserved by the author. You may give copies of this program to */
  9. /* anyone you wish but you may not sell it.                           */
  10. /*                                                                    */
  11. /* Pattern matching routine taken from Matt Dillon's csh program;     */
  12. /* reproduced by permission.                                          */
  13. /*                                                                    */
  14. /* Changes from Version 1.0:                                          */
  15. /*                                                                    */
  16. /*   - dynamic allocation of file name space when recursing down      */
  17. /*     the directory tree and when executing commands.                */
  18. /*                                                                    */
  19. /*   - changed comparison to assignment on line 652 of find.c.        */
  20. /*     Though this makes no difference to the program, (i.e the       */
  21. /*     line doesn't really need to be there in the first place),      */
  22. /*     it was incorrect code. Thanks to Hume Smith, Acadia U.         */
  23. /*                                                                    */
  24. /*   - added support for the 1.3 hidden, script, pure and archive     */
  25. /*     bits in "-perm" primary.                                       */
  26. /*                                                                    */
  27. /*   - added extra primary "-prot" to test for indiviual protection   */
  28. /*     bits. "-perm" tests only for an exact permissions match. This  */
  29. /*     allows the you (for example) to search for all files that have */
  30. /*     not been archived using "! -prot a".                           */
  31. /*                                                                    */
  32. /*   - changed find so the path name used for each file is relative   */
  33. /*     to the current directory; which is as it should be. In V1.0,   */
  34. /*     the full path name of each file from the root of the device    */
  35. /*     was always used.                                               */
  36. /*                                                                    */
  37. /**********************************************************************/
  38.  
  39. /**********************************************************************/
  40. /*                                                                    */
  41. /* find    - searches the directory hierachy looking for files that   */
  42. /*           match a given boolean expression. Based  on  the  U**X   */
  43. /*           find command.                                            */
  44. /*                                                                    */
  45. /**********************************************************************/
  46.  
  47. #include <exec/types.h>
  48. #include <exec/memory.h>
  49. #include <libraries/dosextens.h>
  50. #include <stdio.h>
  51. #include <functions.h>
  52.  
  53. /* define new 1.3 protection bits */
  54.  
  55. #ifndef FIBB_HIDDEN
  56. #define FIBB_HIDDEN    7L
  57. #define FIBB_SCRIPT    6L
  58. #define FIBB_PURE    5L
  59.  
  60. #define FIBF_HIDDEN    (1L << FIBB_HIDDEN)
  61. #define FIBF_SCRIPT    (1L << FIBB_SCRIPT)
  62. #define FIBF_PURE    (1L << FIBB_PURE)
  63. #endif
  64.  
  65. #define MAXARGS        50
  66. #define NULL_PRIM    (struct primary *) NULL
  67. #define EQ(x,y)        (strcmp(x, y) == 0)
  68. #define PROTECTION    (FIBF_READ | FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE)
  69. #define STATUS        (FIBF_HIDDEN | FIBF_SCRIPT | FIBF_PURE | FIBF_ARCHIVE | PROTECTION)
  70.  
  71. /* boolean expression node structure */
  72.  
  73. struct node {
  74.     unsigned long        type;
  75.     struct node    *first;
  76.     struct node    *second;
  77. };
  78.  
  79. /* Node types - must be different from primary node types (below) */
  80.  
  81. #define OR    0x000000ff
  82. #define AND    0x0000ff00
  83. #define NOT    0x00ff0000
  84.  
  85. /* structure to hold interpreted primary information */
  86.  
  87. struct primary {
  88.     unsigned long        type;
  89.     unsigned long        size;
  90.     char                *data[MAXARGS];
  91. };
  92.  
  93. /* start of compiled expression tree */
  94.  
  95. struct node *node_head;
  96.  
  97. /* Primary types */
  98.  
  99. #define PRINT    0x00000001
  100. #define NAME    0x00000002
  101. #define SIZE    0x00000004
  102. #define TYPE    0x00000008
  103. #define EXEC    0x00000010
  104. #define NEWER    0x00000020
  105. #define MTIME    0x00000040
  106. #define PERM    0x00000080
  107. #define PROT    0x00000100
  108. #define PRIMS    0x0000ffff
  109.  
  110. /* type qualifiers */
  111.  
  112. #define DIRECT    0x00010000        /* directory for -type */
  113. #define PLAIN    0x00020000        /* plain file for -type */
  114. #define PROMPT    0x00040000        /* prompt for EXEC */
  115. #define LT        0x00080000        /* greater than */
  116. #define GT        0x00100000        /* less than */
  117. #define CHAR    0x00200000        /* use characters in -size check */
  118. #define QUALS    0xffff0000
  119.  
  120. int breakflag = FALSE;
  121.  
  122. char *path = NULL;                /* memory to hold full path name */
  123. int p_alloc = 500;
  124.  
  125. struct DateStamp date;
  126.  
  127. /* manx releases the memory allocated by calloc when you call exit() */
  128.  
  129. extern char        *calloc();
  130. extern char        *malloc();
  131.  
  132. main(argc, argv)
  133. int argc;
  134. char *argv[];
  135. {
  136.     register struct FileLock *start;
  137.     register i;
  138.     extern struct node *compile();
  139.  
  140.     DateStamp(&date);
  141.  
  142.     /* must be at least three arguments */
  143.  
  144.     if (argc < 3) {
  145.         fprintf(stderr, "Usage: find <path-list> <expression>\n");
  146.         exit(1);
  147.     }
  148.  
  149.     /* find the start of the boolean expression */
  150.  
  151.     for (i = 1 ; argv[i][0] != '-' && argv[i][0] != '!' && argv[i][0] != '(' ; i++);
  152.     if (i == 1) {
  153.         /* no path name list */
  154.         fprintf(stderr, "Usage: find <path-list> <expression>\n");
  155.         exit(1);
  156.     }
  157.  
  158.     /* compile the boolean expression */
  159.  
  160.     if (node_head = compile(argc - i, &argv[i])) {
  161.  
  162.         /* search each path-name specified */
  163.  
  164.         for (i = 1 ; argv[i][0] != '-' && argv[i][0] != '!' && argv[i][0] != '(' ; ++i) {
  165.             start = Lock(argv[i], ACCESS_READ);
  166.             if (start == NULL) {
  167.                 fprintf(stderr, "can't access '%s'\n", argv[i]);
  168.                 continue;
  169.             }
  170.  
  171.             search(start, argv[i]);
  172.             UnLock(start);
  173.  
  174.             if (path) {
  175.                 free(path);
  176.                 path = (char *) NULL;
  177.                 p_alloc = 500;
  178.             }
  179.         }
  180.     }
  181.  
  182.     exit(0);
  183. }
  184.  
  185. /* search the given directory and for each file
  186.  * execute the boolean expression.
  187.  */
  188.  
  189. search(lock, name)
  190. register struct FileLock *lock;
  191. register char *name;
  192. {
  193.     register struct FileInfoBlock *fib;
  194.     register struct FileLock *nlock;
  195.     char *prev = NULL, *file;
  196.     int ret;
  197.  
  198.     fib = (struct FileInfoBlock *) AllocMem((long) sizeof(struct FileInfoBlock), MEMF_CLEAR);
  199.     if (fib == NULL) {
  200.         fprintf(stderr, "can't allocate file info block\n");
  201.         return(0);
  202.     }
  203.  
  204.     /* save current position in full path name */
  205.  
  206.     if (path)
  207.         prev = path + strlen(path);
  208.  
  209.     /* examine initial path name */
  210.  
  211.     if (Examine(lock, fib)) {
  212.  
  213.         /* execute the expression on the inital path */
  214.  
  215.         execute(node_head, fib, name);
  216.  
  217.         if (name)
  218.             ret = add_pname(name);
  219.         else
  220.             ret = add_pname(fib->fib_FileName);
  221.  
  222.         if (ret == 0) {
  223.             fprintf(stderr, "out of memory\n");
  224.             FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  225.             return(0);
  226.         }
  227.  
  228.         if (fib->fib_DirEntryType <= 0) {
  229.  
  230.             /* if initial path name is not a directory then we just return */
  231.  
  232.             if (prev)
  233.                 *prev = '\0';
  234.             FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  235.             return(0);
  236.         }
  237.  
  238.         /* examine directory contents */
  239.  
  240.         while(ExNext(lock, fib)) {
  241.             if (breakflag) break;
  242.  
  243.             /* recurse if we have found a directory */
  244.  
  245.             if (fib->fib_DirEntryType > 0) {
  246.                 file = malloc(strlen(path) + strlen(fib->fib_FileName) + 1);
  247.                 if (file == NULL) {
  248.                     fprintf(stderr, "out of memory\n");
  249.                     breakflag = TRUE;
  250.                     break;
  251.                 }
  252.                 strcpy(file, path);
  253.                 strcat(file, fib->fib_FileName);
  254.                 nlock = Lock(file, ACCESS_READ);
  255.                 if (nlock == NULL)
  256.                     fprintf(stderr, "locking error - %s\n", file);
  257.                 else {
  258.                     search(nlock, NULL);
  259.                     UnLock(nlock);
  260.                 }
  261.                 free(file);
  262.             }
  263.             else
  264.                 execute(node_head, fib, NULL);
  265.  
  266.             if (SetSignal(0L, 0L) & SIGBREAKF_CTRL_C) {
  267.                 breakflag = TRUE;
  268.                 break;
  269.             }
  270.         }
  271.     }
  272.  
  273.     if (prev)
  274.         *prev = '\0';
  275.     FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  276. }
  277.  
  278. add_pname(name)
  279. register char *name;
  280. {
  281.     register char *tmp;
  282.     register char c;
  283.  
  284.     if (path == NULL) {
  285.         path = calloc(1, p_alloc);
  286.         if (path == NULL)
  287.             return(0);
  288.     }
  289.  
  290.     while (strlen(name) + strlen(path) + 1 > p_alloc) {
  291.         p_alloc *= 2;
  292.         tmp = calloc(1, p_alloc);
  293.         if (tmp == NULL)
  294.             return(0);
  295.  
  296.         strcpy(tmp, path);
  297.         free(path);
  298.         path = tmp;
  299.     }
  300.  
  301.     if (strlen(path) && (c = path[strlen(path) - 1]) != ':' && c != '/')
  302.         strcat(path, "/");
  303.  
  304.     strcat(path, name);
  305.     if (strlen(path) && (c = path[strlen(path) - 1]) != ':' && c != '/')
  306.         strcat(path, "/");
  307.  
  308.     return(1);
  309. }
  310.  
  311. /* execute the boolean expression on the given file */
  312.  
  313. execute(cnode, fib, name)
  314. register struct node *cnode;
  315. register struct FileInfoBlock *fib;
  316. char *name;
  317. {
  318.     register struct primary *prim;
  319.     register long checksize;
  320.     register j;
  321.     register struct DateStamp *ds;
  322.     char *file, ok[10];
  323.     char *av[MAXARGS + 1];
  324.  
  325.     /* check node type */
  326.  
  327.     if (cnode->type == AND)
  328.         if  (execute(cnode->first, fib, name))
  329.             return(execute(cnode->second, fib, name));
  330.         else
  331.             return(0);
  332.  
  333.     else if (cnode->type == OR)
  334.         if  (execute(cnode->first, fib, name))
  335.             return(1);
  336.         else
  337.             return(execute(cnode->second, fib, name));
  338.  
  339.     else if (cnode->type == NOT)
  340.         return(!execute(cnode->first, fib, name));
  341.  
  342.     else {
  343.  
  344.         /* we have an actual primary */
  345.  
  346.         if (name == NULL)
  347.             name = fib->fib_FileName;
  348.  
  349.         prim = (struct primary *) cnode;
  350.         switch (prim->type & PRIMS) {
  351.  
  352.         case PRINT:
  353.  
  354.             if (*path)
  355.                 printf("%s%s\n", path, name);
  356.             else
  357.                 printf("%s\n", name);
  358.             return(1);
  359.  
  360.         case NAME:
  361.  
  362.             if (compare_ok(prim->data[0], name))
  363.                 return(1);
  364.             else
  365.                 return(0);
  366.  
  367.         case SIZE:
  368.  
  369.             if (prim->type & CHAR)
  370.                 checksize = fib->fib_Size;
  371.             else
  372.                 checksize = fib->fib_NumBlocks;
  373.  
  374.             if (((prim->type & GT) && (checksize > prim->size) ) ||
  375.                 ((prim->type & LT) && (checksize < prim->size) ) ||
  376.                 ((prim->type & (GT | LT)) == 0 && (checksize == prim->size)))
  377.                 return(1);
  378.             else
  379.                 return(0);
  380.  
  381.         case TYPE:
  382.  
  383.             switch (prim->type & QUALS | (fib->fib_DirEntryType > 0)) {
  384.  
  385.             case DIRECT:
  386.             case (PLAIN | 1):
  387.                 return(0);
  388.  
  389.             default:
  390.                 return(1);
  391.             }
  392.  
  393.         case EXEC:
  394.  
  395.             for (j = 0 ; prim->data[j] ; j++)
  396.                 if (EQ("{}", prim->data[j])) {
  397.                     file = malloc(strlen(path) + strlen(name) + 1);
  398.                     if (file == NULL) {
  399.                         fprintf(stderr, "out of memory\n");
  400.                         return(0);
  401.                     }
  402.                     strcpy(file, path);
  403.                     strcat(file, name);
  404.                     av[j] = file;
  405.                 }
  406.                 else
  407.                     av[j] = prim->data[j];
  408.             av[j] = NULL;
  409.  
  410.             if (!(prim->type & PROMPT) || (pr_cmd(av) && gets(ok) &&
  411.                  ((ok[0] == 'y') || (ok[0] == 'Y')))) {
  412.                 if (fexecv(av[0], av) == -1)
  413.                     return(0);
  414.                 else if (wait())
  415.                     return(0);
  416.                 else
  417.                     return(1);
  418.             }
  419.  
  420.             return(0);
  421.  
  422.         case NEWER:
  423.  
  424.             ds = (struct DateStamp *) prim->data[0];
  425.             if (fib->fib_Date.ds_Days > ds->ds_Days)
  426.                 return(1);
  427.             else if (fib->fib_Date.ds_Days == ds->ds_Days &&
  428.                      fib->fib_Date.ds_Minute > ds->ds_Minute)
  429.                 return(1);
  430.             else if (fib->fib_Date.ds_Days == ds->ds_Days &&
  431.                      fib->fib_Date.ds_Minute == ds->ds_Minute &&
  432.                      fib->fib_Date.ds_Tick > ds->ds_Tick)
  433.                 return(1);
  434.             else
  435.                 return(0);
  436.  
  437.         case MTIME:
  438.  
  439.             checksize = date.ds_Days - fib->fib_Date.ds_Days;
  440.  
  441.             if (((prim->type & GT) && (checksize > prim->size) ) ||
  442.                 ((prim->type & LT) && (checksize < prim->size) ) ||
  443.                 ((prim->type & (GT | LT)) == 0 && (checksize == prim->size)))
  444.                 return(1);
  445.             else
  446.                 return(0);
  447.  
  448.         case PERM:
  449.  
  450.             if ((fib->fib_Protection & STATUS) == prim->size)
  451.                 return(1);
  452.             else
  453.                 return(0);
  454.  
  455.         case PROT:
  456.  
  457.             if ((fib->fib_Protection & prim->size) == prim->size)
  458.                 return(1);
  459.             else
  460.                 return(0);
  461.  
  462.         }
  463.         return(0);
  464.     }
  465. }
  466.  
  467. /* print the command to be executed on the screen */
  468.  
  469. pr_cmd(av)
  470. char *av[];
  471. {
  472.     register j;
  473.  
  474.     printf("< ");
  475.     for (j = 0 ; av[j] ; j++) printf("%s ", av[j]);
  476.     printf("> ? ");
  477.     return(1);
  478. }
  479.  
  480. /* compile the boolean expression: returns a pointer to the start
  481.  * of the compiled expression tree, or NULL if a failure occurs.
  482.  */
  483.  
  484. struct node *
  485. compile(argc, argv)
  486. int argc;
  487. char *argv[];
  488. {
  489.     register i, j, scan;
  490.     register struct primary *prim;
  491.     register struct node *node_head = (struct node *) NULL, *tmp_node;
  492.  
  493.     for(i = 0 ; i < argc ; i++) {
  494.  
  495.         prim = (struct primary *) calloc(1, sizeof(struct primary));
  496.         if (prim == NULL_PRIM) {
  497.             fprintf(stderr, "out memory in primary interpretation\n");
  498.             exit(5);
  499.         }
  500.  
  501.  
  502.         if (EQ("-o", argv[i])) {
  503.             free(prim);
  504.  
  505.             /* -o cannot be the first argument */
  506.  
  507.             if (node_head == NULL_PRIM) {
  508.                 fprintf(stderr, "misplaced 'or' operator ... ignored\n");
  509.                 continue;
  510.             }
  511.  
  512.             else {
  513.  
  514.                 /* create OR node */
  515.  
  516.                 tmp_node = (struct node *) calloc(1, sizeof(struct node));
  517.                 if (tmp_node == NULL) {
  518.                     fprintf(stderr, "out of memory in expression compilation");
  519.                     exit(5);
  520.                 }
  521.                 tmp_node->type = OR;
  522.                 tmp_node->first = node_head;
  523.  
  524.                 /* compile rest of expression and attach it to OR node */
  525.  
  526.                 if ((tmp_node->second = compile(argc - i - 1, argv + i + 1)) == NULL) {
  527.                     free(tmp_node);
  528.                     return(node_head);
  529.                 }
  530.                 else
  531.                     return(tmp_node);
  532.             }
  533.         }
  534.  
  535.         else if (EQ("(", argv[i])) {
  536.             free(prim);
  537.  
  538.             /* scan to matching brackets */
  539.  
  540.             for (j = 0, scan = 0 ; ++i < argc && (!EQ(")", argv[i]) || scan != 0) ; j++) {
  541.                 if (EQ("(", argv[i])) scan++;
  542.                 if (EQ(")", argv[i])) scan--;
  543.             }
  544.  
  545.             if (i >= argc) {
  546.                 fprintf(stderr, "unmatched bracket\n");
  547.                 exit(5);
  548.             }
  549.  
  550.             if (j == 0) {
  551.                 fprintf(stderr, "empty brackets ... ignored\n");
  552.                 continue;
  553.             }
  554.  
  555.             /* compile what is in the brackets */
  556.  
  557.             if ((prim = (struct primary *) compile(j, argv + i - j)) == NULL)
  558.                 continue;
  559.         }
  560.  
  561.         else if (EQ("!", argv[i])) {
  562.             if (++i >= argc) {
  563.                 fprintf(stderr, "trailing '!' ignored\n");
  564.                 continue;
  565.             }
  566.             if (EQ("-o", argv[i])) {
  567.                 fprintf(stderr, "illegal 'or' operator placement\n");
  568.                 exit(5);
  569.             }
  570.  
  571.             tmp_node = (struct node *) calloc(1, sizeof(struct node));
  572.             if (tmp_node == NULL) {
  573.                 fprintf(stderr, "out of memory in expression compilation\n");
  574.                 exit(5);
  575.             }
  576.             tmp_node->type = NOT;
  577.  
  578.             if (EQ("(", argv[i])) {
  579.  
  580.                 /* scan to matching bracket */
  581.  
  582.                 for (j = 0, scan = 0 ; ++i < argc && (!EQ(")", argv[i]) || scan != 0) ; j++) {
  583.                     if (EQ("(", argv[i])) scan++;
  584.                     if (EQ(")", argv[i])) scan--;
  585.                 }
  586.  
  587.                 if (i >= argc) {
  588.                     fprintf(stderr, "unmatched bracket\n");
  589.                     exit(5);
  590.                 }
  591.  
  592.                 if (j == 0) {
  593.                     fprintf(stderr, "empty brackets ... ignored\n");
  594.                     free(tmp_node);
  595.                     continue;
  596.                 }
  597.  
  598.                 /* compile what is in the brackets */
  599.  
  600.                 if ((tmp_node->first = compile(j, argv + i - j)) == NULL)
  601.                     continue;
  602.             }
  603.             else {
  604.                 tmp_node->first = (struct node *) prim;
  605.                 i += interpret(prim, argc - i, argv + i);
  606.             }
  607.             prim = (struct primary *) tmp_node;
  608.         }
  609.  
  610.         else
  611.             i += interpret(prim, argc - i, argv + i);
  612.  
  613.         /* attach interpreted primary to expression tree */
  614.  
  615.         if (node_head == NULL)
  616.             node_head = (struct node *) prim;
  617.         else {
  618.             tmp_node = (struct node *) calloc(1, sizeof(struct node));
  619.             if (tmp_node == NULL) {
  620.                 fprintf(stderr, "out of memory in expression compilation\n");
  621.                 exit(5);
  622.             }
  623.             tmp_node->type   = AND;
  624.             tmp_node->first  = node_head;
  625.             tmp_node->second = (struct node *) prim;
  626.             node_head        = tmp_node;
  627.         }
  628.     }
  629.  
  630.     return(node_head);
  631. }
  632.  
  633. /* interpret a primary */
  634.  
  635. interpret(prim, argc, argv)
  636. struct primary *prim;
  637. char *argv[];
  638. {
  639.     register i, j;
  640.     register struct FileLock *lock;
  641.     register struct FileInfoBlock *fib;
  642.     register struct DateStamp *ds;
  643.     char *numstr;
  644.     extern unsigned long atol();
  645.  
  646.     for (i = 0 ; i < argc ; i++) {
  647.  
  648.         if (EQ("-print", argv[i]))
  649.             prim->type = PRINT;
  650.  
  651.         else if (EQ("-name", argv[i])) {
  652.             prim->type = NAME;
  653.             prim->data[0] = argv[++i];
  654.         }
  655.  
  656.         else if (EQ("-size", argv[i])) {
  657.             prim->type = SIZE;
  658.  
  659.             /* get required size */
  660.  
  661.             numstr = argv[++i];
  662.  
  663.             if (*numstr == '+') {
  664.                 prim->type |= GT;
  665.                 numstr++;
  666.             }
  667.  
  668.             else if (*numstr == '-') {
  669.                 prim->type |= LT;
  670.                 numstr++;
  671.             }
  672.  
  673.             if (numstr[strlen(numstr) - 1] == 'c') {
  674.                 prim->type |= CHAR;
  675.                 numstr[strlen(numstr) - 1] = '\0';
  676.             }
  677.  
  678.             prim->size = atol(numstr);
  679.         }
  680.  
  681.         else if (EQ("-type", argv[i])) {
  682.             prim->type = TYPE;
  683.             if (EQ(argv[++i], "d"))
  684.                 prim->type |= DIRECT;
  685.             else if (EQ(argv[i], "f"))
  686.                 prim->type |= PLAIN;
  687.             else {
  688.                 fprintf(stderr, "illegal file type specified\n");
  689.                 exit(5);
  690.             }
  691.         }
  692.  
  693.         else if (EQ("-exec", argv[i])) {
  694.             prim->type = EXEC;
  695.  
  696.             /* scan to ending ';', saving pointers to arguments */
  697.  
  698.             for (j=0 ; (j<MAXARGS) && (++i < argc) && !EQ(";",argv[i]) ; j++)
  699.                 prim->data[j] = argv[i];
  700.  
  701.             if (i >= argc) {
  702.                 fprintf(stderr, "no ending ';' on command\n");
  703.                 exit(5);
  704.             }
  705.  
  706.             else if (j >= MAXARGS) {
  707.                 fprintf(stderr, "command too long\n");
  708.                 exit(5);
  709.             }
  710.  
  711.             else
  712.                 argv[j] = NULL;
  713.         }
  714.  
  715.         else if (EQ("-ok", argv[i])) {
  716.             prim->type = EXEC | PROMPT;
  717.  
  718.             /* scan to ending ';', saving pointers to arguments */
  719.  
  720.             for (j=0 ; (j<MAXARGS) && (++i < argc) && !EQ(";",argv[i]) ; j++)
  721.                 prim->data[j] = argv[i];
  722.  
  723.             if (i >= argc) {
  724.                 fprintf(stderr, "no ending ';' on command\n");
  725.                 exit(5);
  726.             }
  727.  
  728.             else if (j >= MAXARGS) {
  729.                 fprintf(stderr, "command too long\n");
  730.                 exit(5);
  731.             }
  732.  
  733.             else
  734.                 argv[j] = NULL;
  735.         }
  736.  
  737.         else if (EQ("-newer", argv[i])) {
  738.             prim->type = NEWER;
  739.  
  740.             if (lock = Lock(argv[++i])) {
  741.                 fib = (struct FileInfoBlock *) AllocMem((long) sizeof(struct FileInfoBlock), MEMF_CLEAR);
  742.                 if (fib == NULL) {
  743.                     fprintf(stderr, "no mem for -newer test\n");
  744.                     UnLock(lock);
  745.                     exit(5);
  746.                 }
  747.  
  748.                 if (Examine(lock, fib) == 0) {
  749.                     fprintf(stderr, "could not examine %s\n", argv[i]);
  750.                     FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  751.                     UnLock(lock);
  752.                     exit(5);
  753.                 }
  754.  
  755.                 /* save date stamp of given file */
  756.  
  757.                 ds = (struct DateStamp *) calloc(1, sizeof(struct DateStamp));
  758.                 if (ds == NULL) {
  759.                     fprintf(stderr, "no mem for DateStamp on %s\n", argv[i]);
  760.                     FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  761.                     UnLock(lock);
  762.                     exit(5);
  763.                 }
  764.  
  765.                 prim->data[0] = (char *) ds;
  766.                 *ds = fib->fib_Date;
  767.  
  768.                 FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  769.                 UnLock(lock);
  770.             }
  771.  
  772.             else {
  773.                 fprintf(stderr, "unable to access %s\n", argv[i]);
  774.                 exit(5);
  775.             }
  776.         }
  777.  
  778.         else if (EQ("-mtime", argv[i])) {
  779.             prim->type = MTIME;
  780.  
  781.             /* get required number of days */
  782.  
  783.             numstr = argv[++i];
  784.  
  785.             if (*numstr == '+') {
  786.                 prim->type |= GT;
  787.                 numstr++;
  788.             }
  789.             else if (*numstr == '-') {
  790.                 prim->type |= LT;
  791.                 numstr++;
  792.             }
  793.  
  794.             prim->size = atol(numstr);
  795.         }
  796.  
  797.         else if (EQ("-perm", argv[i])) {
  798.             prim->type = PERM;
  799.             prim->size = PROTECTION;
  800.  
  801.             /* assemble desired protection bits */
  802.  
  803.             for(i++, j = 0 ; argv[i][j] ; j++) {
  804.                 switch(argv[i][j]) {
  805.  
  806.                 case 'n':
  807.                     if (prim->size != PROTECTION)
  808.                         fprintf(stderr, "'n' permission code overriding other given codes \n");
  809.  
  810.                     prim->size = PROTECTION;
  811.                     return(i);
  812.  
  813.                 case 'h':
  814.                     prim->size |= FIBF_HIDDEN;
  815.                     break;
  816.  
  817.                 case 's':
  818.                     prim->size |= FIBF_SCRIPT;
  819.                     break;
  820.  
  821.                 case 'p':
  822.                     prim->size |= FIBF_PURE;
  823.                     break;
  824.  
  825.                 case 'a':
  826.                     prim->size |= FIBF_ARCHIVE;
  827.                     break;
  828.  
  829.                 case 'r':
  830.                     prim->size &= ~FIBF_READ;
  831.                     break;
  832.  
  833.                 case 'w':
  834.                     prim->size &= ~FIBF_WRITE;
  835.                     break;
  836.  
  837.                 case 'e':
  838.                     prim->size &= ~FIBF_EXECUTE;
  839.                     break;
  840.  
  841.                 case 'd':
  842.                     prim->size &= ~FIBF_DELETE;
  843.                     break;
  844.  
  845.                 default:
  846.                     fprintf(stderr, "unknown permission code '%c' ... ignored\n", argv[i][j]);
  847.                     break;
  848.                 }
  849.             }
  850.         }
  851.  
  852.         else if (EQ("-prot", argv[i])) {
  853.             prim->type = PROT;
  854.             prim->size = 0;
  855.  
  856.             /* assemble desired protection bits */
  857.  
  858.             for(i++, j = 0 ; argv[i][j] ; j++) {
  859.                 switch(argv[i][j]) {
  860.  
  861.                 case 'h':
  862.                     prim->size |= FIBF_HIDDEN;
  863.                     break;
  864.  
  865.                 case 's':
  866.                     prim->size |= FIBF_SCRIPT;
  867.                     break;
  868.  
  869.                 case 'p':
  870.                     prim->size |= FIBF_PURE;
  871.                     break;
  872.  
  873.                 case 'a':
  874.                     prim->size |= FIBF_ARCHIVE;
  875.                     break;
  876.  
  877.                 case 'r':
  878.                     prim->size |= FIBF_READ;
  879.                     break;
  880.  
  881.                 case 'w':
  882.                     prim->size |= FIBF_WRITE;
  883.                     break;
  884.  
  885.                 case 'e':
  886.                     prim->size |= FIBF_EXECUTE;
  887.                     break;
  888.  
  889.                 case 'd':
  890.                     prim->size |= FIBF_DELETE;
  891.                     break;
  892.  
  893.                 default:
  894.                     fprintf(stderr, "unknown protection code '%c' ... ignored\n", argv[i][j]);
  895.                     break;
  896.                 }
  897.             }
  898.         }
  899.  
  900.         else {
  901.             fprintf(stderr, "unknown primary: %s\n", argv[i]);
  902.             exit(5);
  903.         }
  904.  
  905.         return(i);
  906.     }
  907. }
  908.  
  909. /*
  910.  * Compare a wild card name with a normal name.
  911.  * Taken from Matt Dillon's csh program.
  912.  */
  913.  
  914. #define MAXB   8
  915.  
  916. compare_ok(wild, name)
  917. char *wild, *name;
  918. {
  919.    register char *w = wild;
  920.    register char *n = name;
  921.    char *back[MAXB][2];
  922.    register char s1, s2;
  923.    int    bi = 0;
  924.  
  925.    while (*n || *w) {
  926.       switch (*w) {
  927.       case '*':
  928.      if (bi == MAXB) {
  929.         fprintf(stderr,"Too many levels of '*'\n");
  930.         return (0);
  931.      }
  932.      back[bi][0] = w;
  933.      back[bi][1] = n;
  934.      ++bi;
  935.      ++w;
  936.      continue;
  937. goback:
  938.      --bi;
  939.      while (bi >= 0 && *back[bi][1] == '\0')
  940.         --bi;
  941.      if (bi < 0)
  942.         return (0);
  943.      w = back[bi][0] + 1;
  944.      n = ++back[bi][1];
  945.      ++bi;
  946.      continue;
  947.       case '?':
  948.      if (!*n) {
  949.         if (bi)
  950.            goto goback;
  951.         return (0);
  952.      }
  953.      break;
  954.       default:
  955.      s1 = (*n >= 'A' && *n <= 'Z') ? *n - 'A' + 'a' : *n;
  956.      s2 = (*w >= 'A' && *w <= 'Z') ? *w - 'A' + 'a' : *w;
  957.      if (s1 != s2) {
  958.         if (bi)
  959.            goto goback;
  960.         return (0);
  961.      }
  962.      break;
  963.       }
  964.       if (*n)  ++n;
  965.       if (*w)  ++w;
  966.    }
  967.    return (1);
  968. }
  969.