home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD2.bin / bbs / gnu / findutils-4.1-src.lha / findutils-4.1 / find / parser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-03  |  46.5 KB  |  1,885 lines

  1. /* parser.c -- convert the command line args into an expression tree.
  2.    Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <config.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <ctype.h>
  22. #include <stdio.h>
  23. #include <pwd.h>
  24. #include <grp.h>
  25. #include "modechange.h"
  26. #include "defs.h"
  27. #include "modetype.h"
  28.  
  29. #if !defined (isascii) || defined (STDC_HEADERS)
  30. #ifdef isascii
  31. #undef isascii
  32. #endif
  33. #define isascii(c) 1
  34. #endif
  35.  
  36. #define ISDIGIT(c) (isascii (c) && isdigit (c))
  37. #define ISUPPER(c) (isascii (c) && isupper (c))
  38.  
  39. #ifndef _POSIX_VERSION
  40. /* POSIX.1 header files should declare these.  */
  41. struct group *getgrnam ();
  42. struct passwd *getpwnam ();
  43. #endif
  44.  
  45. #ifdef CACHE_IDS
  46. /* These two aren't specified by POSIX.1.  */
  47. struct group *getgrent ();
  48. struct passwd *getpwent ();
  49. #endif
  50.  
  51. #ifndef S_IFLNK
  52. #define lstat stat
  53. #endif
  54.  
  55. char *strstr ();
  56. int lstat ();
  57. int stat ();
  58. #ifndef atol /* for Linux */
  59. long atol ();
  60. #endif
  61. struct tm *localtime ();
  62.  
  63. #ifdef _POSIX_SOURCE
  64. #define endgrent()
  65. #define endpwent()
  66. #else
  67. void endgrent ();
  68. void endpwent ();
  69. #endif
  70.  
  71. static boolean parse_amin P_((char *argv[], int *arg_ptr));
  72. static boolean parse_and P_((char *argv[], int *arg_ptr));
  73. static boolean parse_anewer P_((char *argv[], int *arg_ptr));
  74. static boolean parse_atime P_((char *argv[], int *arg_ptr));
  75. boolean parse_close P_((char *argv[], int *arg_ptr));
  76. static boolean parse_cmin P_((char *argv[], int *arg_ptr));
  77. static boolean parse_cnewer P_((char *argv[], int *arg_ptr));
  78. static boolean parse_comma P_((char *argv[], int *arg_ptr));
  79. static boolean parse_ctime P_((char *argv[], int *arg_ptr));
  80. static boolean parse_daystart P_((char *argv[], int *arg_ptr));
  81. static boolean parse_depth P_((char *argv[], int *arg_ptr));
  82. static boolean parse_empty P_((char *argv[], int *arg_ptr));
  83. static boolean parse_exec P_((char *argv[], int *arg_ptr));
  84. static boolean parse_false P_((char *argv[], int *arg_ptr));
  85. static boolean parse_fls P_((char *argv[], int *arg_ptr));
  86. static boolean parse_fprintf P_((char *argv[], int *arg_ptr));
  87. static boolean parse_follow P_((char *argv[], int *arg_ptr));
  88. static boolean parse_fprint P_((char *argv[], int *arg_ptr));
  89. static boolean parse_fprint0 P_((char *argv[], int *arg_ptr));
  90. static boolean parse_fstype P_((char *argv[], int *arg_ptr));
  91. static boolean parse_gid P_((char *argv[], int *arg_ptr));
  92. static boolean parse_group P_((char *argv[], int *arg_ptr));
  93. static boolean parse_help P_((char *argv[], int *arg_ptr));
  94. static boolean parse_ilname P_((char *argv[], int *arg_ptr));
  95. static boolean parse_iname P_((char *argv[], int *arg_ptr));
  96. static boolean parse_inum P_((char *argv[], int *arg_ptr));
  97. static boolean parse_ipath P_((char *argv[], int *arg_ptr));
  98. static boolean parse_iregex P_((char *argv[], int *arg_ptr));
  99. static boolean parse_links P_((char *argv[], int *arg_ptr));
  100. static boolean parse_lname P_((char *argv[], int *arg_ptr));
  101. static boolean parse_ls P_((char *argv[], int *arg_ptr));
  102. static boolean parse_maxdepth P_((char *argv[], int *arg_ptr));
  103. static boolean parse_mindepth P_((char *argv[], int *arg_ptr));
  104. static boolean parse_mmin P_((char *argv[], int *arg_ptr));
  105. static boolean parse_mtime P_((char *argv[], int *arg_ptr));
  106. static boolean parse_name P_((char *argv[], int *arg_ptr));
  107. static boolean parse_negate P_((char *argv[], int *arg_ptr));
  108. static boolean parse_newer P_((char *argv[], int *arg_ptr));
  109. static boolean parse_noleaf P_((char *argv[], int *arg_ptr));
  110. static boolean parse_nogroup P_((char *argv[], int *arg_ptr));
  111. static boolean parse_nouser P_((char *argv[], int *arg_ptr));
  112. static boolean parse_ok P_((char *argv[], int *arg_ptr));
  113. boolean parse_open P_((char *argv[], int *arg_ptr));
  114. static boolean parse_or P_((char *argv[], int *arg_ptr));
  115. static boolean parse_path P_((char *argv[], int *arg_ptr));
  116. static boolean parse_perm P_((char *argv[], int *arg_ptr));
  117. boolean parse_print P_((char *argv[], int *arg_ptr));
  118. static boolean parse_print0 P_((char *argv[], int *arg_ptr));
  119. static boolean parse_printf P_((char *argv[], int *arg_ptr));
  120. static boolean parse_prune P_((char *argv[], int *arg_ptr));
  121. static boolean parse_regex P_((char *argv[], int *arg_ptr));
  122. static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
  123. static boolean parse_size P_((char *argv[], int *arg_ptr));
  124. static boolean parse_true P_((char *argv[], int *arg_ptr));
  125. static boolean parse_type P_((char *argv[], int *arg_ptr));
  126. static boolean parse_uid P_((char *argv[], int *arg_ptr));
  127. static boolean parse_used P_((char *argv[], int *arg_ptr));
  128. static boolean parse_user P_((char *argv[], int *arg_ptr));
  129. static boolean parse_version P_((char *argv[], int *arg_ptr));
  130. static boolean parse_xdev P_((char *argv[], int *arg_ptr));
  131. static boolean parse_xtype P_((char *argv[], int *arg_ptr));
  132.  
  133. static boolean insert_regex P_((char *argv[], int *arg_ptr, boolean ignore_case));
  134. static boolean insert_type P_((char *argv[], int *arg_ptr, boolean (*which_pred )()));
  135. static boolean insert_fprintf P_((FILE *fp, boolean (*func )(), char *argv[], int *arg_ptr));
  136. static struct segment **make_segment P_((struct segment **segment, char *format, int len, int kind));
  137. static boolean insert_exec_ok P_((boolean (*func )(), char *argv[], int *arg_ptr));
  138. static boolean get_num_days P_((char *str, unsigned long *num_days, enum comparison_type *comp_type));
  139. static boolean insert_time P_((char *argv[], int *arg_ptr, PFB pred));
  140. static boolean get_num P_((char *str, unsigned long *num, enum comparison_type *comp_type));
  141. static boolean insert_num P_((char *argv[], int *arg_ptr, PFB pred));
  142. static FILE *open_output_file P_((char *path));
  143.  
  144. #ifdef DEBUG
  145. char *find_pred_name _P((PFB pred_func));
  146. #endif /* DEBUG */
  147.  
  148. struct parser_table
  149. {
  150.   char *parser_name;
  151.   PFB parser_func;
  152. };
  153.  
  154. /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
  155.    If they are in some Unix versions of find, they are marked `Unix'. */
  156.  
  157. static struct parser_table const parse_table[] =
  158. {
  159.   {"!", parse_negate},
  160.   {"not", parse_negate},    /* GNU */
  161.   {"(", parse_open},
  162.   {")", parse_close},
  163.   {",", parse_comma},        /* GNU */
  164.   {"a", parse_and},
  165.   {"amin", parse_amin},        /* GNU */
  166.   {"and", parse_and},        /* GNU */
  167.   {"anewer", parse_anewer},    /* GNU */
  168.   {"atime", parse_atime},
  169.   {"cmin", parse_cmin},        /* GNU */
  170.   {"cnewer", parse_cnewer},    /* GNU */
  171. #ifdef UNIMPLEMENTED_UNIX
  172.   /* It's pretty ugly for find to know about archive formats.
  173.      Plus what it could do with cpio archives is very limited.
  174.      Better to leave it out.  */
  175.   {"cpio", parse_cpio},        /* Unix */
  176. #endif
  177.   {"ctime", parse_ctime},
  178.   {"daystart", parse_daystart},    /* GNU */
  179.   {"depth", parse_depth},
  180.   {"empty", parse_empty},    /* GNU */
  181.   {"exec", parse_exec},
  182.   {"false", parse_false},    /* GNU */
  183.   {"fls", parse_fls},        /* GNU */
  184.   {"follow", parse_follow},    /* GNU, Unix */
  185.   {"fprint", parse_fprint},    /* GNU */
  186.   {"fprint0", parse_fprint0},    /* GNU */
  187.   {"fprintf", parse_fprintf},    /* GNU */
  188.   {"fstype", parse_fstype},    /* GNU, Unix */
  189.   {"gid", parse_gid},        /* GNU */
  190.   {"group", parse_group},
  191.   {"help", parse_help},        /* GNU */
  192.   {"-help", parse_help},    /* GNU */
  193.   {"ilname", parse_ilname},    /* GNU */
  194.   {"iname", parse_iname},    /* GNU */
  195.   {"inum", parse_inum},        /* GNU, Unix */
  196.   {"ipath", parse_ipath},    /* GNU */
  197.   {"iregex", parse_iregex},    /* GNU */
  198.   {"links", parse_links},
  199.   {"lname", parse_lname},    /* GNU */
  200.   {"ls", parse_ls},        /* GNU, Unix */
  201.   {"maxdepth", parse_maxdepth},    /* GNU */
  202.   {"mindepth", parse_mindepth},    /* GNU */
  203.   {"mmin", parse_mmin},        /* GNU */
  204.   {"mount", parse_xdev},    /* Unix */
  205.   {"mtime", parse_mtime},
  206.   {"name", parse_name},
  207. #ifdef UNIMPLEMENTED_UNIX
  208.   {"ncpio", parse_ncpio},    /* Unix */
  209. #endif
  210.   {"newer", parse_newer},
  211.   {"noleaf", parse_noleaf},    /* GNU */
  212.   {"nogroup", parse_nogroup},
  213.   {"nouser", parse_nouser},
  214.   {"o", parse_or},
  215.   {"or", parse_or},        /* GNU */
  216.   {"ok", parse_ok},
  217.   {"path", parse_path},        /* GNU, HP-UX */
  218.   {"perm", parse_perm},
  219.   {"print", parse_print},
  220.   {"print0", parse_print0},    /* GNU */
  221.   {"printf", parse_printf},    /* GNU */
  222.   {"prune", parse_prune},
  223.   {"regex", parse_regex},    /* GNU */
  224.   {"size", parse_size},
  225.   {"true", parse_true},        /* GNU */
  226.   {"type", parse_type},
  227.   {"uid", parse_uid},        /* GNU */
  228.   {"used", parse_used},        /* GNU */
  229.   {"user", parse_user},
  230.   {"version", parse_version},    /* GNU */
  231.   {"-version", parse_version},    /* GNU */
  232.   {"xdev", parse_xdev},
  233.   {"xtype", parse_xtype},    /* GNU */
  234.   {0, 0}
  235. };
  236.  
  237. /* Return a pointer to the parser function to invoke for predicate
  238.    SEARCH_NAME.
  239.    Return NULL if SEARCH_NAME is not a valid predicate name. */
  240.  
  241. PFB
  242. find_parser (search_name)
  243.      char *search_name;
  244. {
  245.   int i;
  246.  
  247.   if (*search_name == '-')
  248.     search_name++;
  249.   for (i = 0; parse_table[i].parser_name != 0; i++)
  250.     if (strcmp (parse_table[i].parser_name, search_name) == 0)
  251.       return (parse_table[i].parser_func);
  252.   return (NULL);
  253. }
  254.  
  255. /* The parsers are responsible to continue scanning ARGV for
  256.    their arguments.  Each parser knows what is and isn't
  257.    allowed for itself.
  258.    
  259.    ARGV is the argument array.
  260.    *ARG_PTR is the index to start at in ARGV,
  261.    updated to point beyond the last element consumed.
  262.  
  263.    The predicate structure is updated with the new information. */
  264.  
  265. static boolean
  266. parse_amin (argv, arg_ptr)
  267.      char *argv[];
  268.      int *arg_ptr;
  269. {
  270.   struct predicate *our_pred;
  271.   unsigned long num;
  272.   enum comparison_type c_type;
  273.  
  274.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  275.     return (false);
  276.   if (!get_num_days (argv[*arg_ptr], &num, &c_type))
  277.     return (false);
  278.   our_pred = insert_primary (pred_amin);
  279.   our_pred->args.info.kind = c_type;
  280.   our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
  281.   (*arg_ptr)++;
  282.   return (true);
  283. }
  284.  
  285. static boolean
  286. parse_and (argv, arg_ptr)
  287.      char *argv[];
  288.      int *arg_ptr;
  289. {
  290.   struct predicate *our_pred;
  291.  
  292.   our_pred = get_new_pred ();
  293.   our_pred->pred_func = pred_and;
  294. #ifdef    DEBUG
  295.   our_pred->p_name = find_pred_name (pred_and);
  296. #endif    /* DEBUG */
  297.   our_pred->p_type = BI_OP;
  298.   our_pred->p_prec = AND_PREC;
  299.   our_pred->need_stat = false;
  300.   return (true);
  301. }
  302.  
  303. static boolean
  304. parse_anewer (argv, arg_ptr)
  305.      char *argv[];
  306.      int *arg_ptr;
  307. {
  308.   struct predicate *our_pred;
  309.   struct stat stat_newer;
  310.  
  311.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  312.     return (false);
  313.   if ((*xstat) (argv[*arg_ptr], &stat_newer))
  314.     error (1, errno, "%s", argv[*arg_ptr]);
  315.   our_pred = insert_primary (pred_anewer);
  316.   our_pred->args.time = stat_newer.st_mtime;
  317.   (*arg_ptr)++;
  318.   return (true);
  319. }
  320.  
  321. static boolean
  322. parse_atime (argv, arg_ptr)
  323.      char *argv[];
  324.      int *arg_ptr;
  325. {
  326.   return (insert_time (argv, arg_ptr, pred_atime));
  327. }
  328.  
  329. boolean
  330. parse_close (argv, arg_ptr)
  331.      char *argv[];
  332.      int *arg_ptr;
  333. {
  334.   struct predicate *our_pred;
  335.  
  336.   our_pred = get_new_pred ();
  337.   our_pred->pred_func = pred_close;
  338. #ifdef    DEBUG
  339.   our_pred->p_name = find_pred_name (pred_close);
  340. #endif    /* DEBUG */
  341.   our_pred->p_type = CLOSE_PAREN;
  342.   our_pred->p_prec = NO_PREC;
  343.   our_pred->need_stat = false;
  344.   return (true);
  345. }
  346.  
  347. static boolean
  348. parse_cmin (argv, arg_ptr)
  349.      char *argv[];
  350.      int *arg_ptr;
  351. {
  352.   struct predicate *our_pred;
  353.   unsigned long num;
  354.   enum comparison_type c_type;
  355.  
  356.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  357.     return (false);
  358.   if (!get_num_days (argv[*arg_ptr], &num, &c_type))
  359.     return (false);
  360.   our_pred = insert_primary (pred_cmin);
  361.   our_pred->args.info.kind = c_type;
  362.   our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
  363.   (*arg_ptr)++;
  364.   return (true);
  365. }
  366.  
  367. static boolean
  368. parse_cnewer (argv, arg_ptr)
  369.      char *argv[];
  370.      int *arg_ptr;
  371. {
  372.   struct predicate *our_pred;
  373.   struct stat stat_newer;
  374.  
  375.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  376.     return (false);
  377.   if ((*xstat) (argv[*arg_ptr], &stat_newer))
  378.     error (1, errno, "%s", argv[*arg_ptr]);
  379.   our_pred = insert_primary (pred_cnewer);
  380.   our_pred->args.time = stat_newer.st_mtime;
  381.   (*arg_ptr)++;
  382.   return (true);
  383. }
  384.  
  385. static boolean
  386. parse_comma (argv, arg_ptr)
  387.      char *argv[];
  388.      int *arg_ptr;
  389. {
  390.   struct predicate *our_pred;
  391.  
  392.   our_pred = get_new_pred ();
  393.   our_pred->pred_func = pred_comma;
  394. #ifdef    DEBUG
  395.   our_pred->p_name = find_pred_name (pred_comma);
  396. #endif /* DEBUG */
  397.   our_pred->p_type = BI_OP;
  398.   our_pred->p_prec = COMMA_PREC;
  399.   our_pred->need_stat = false;
  400.   return (true);
  401. }
  402.  
  403. static boolean
  404. parse_ctime (argv, arg_ptr)
  405.      char *argv[];
  406.      int *arg_ptr;
  407. {
  408.   return (insert_time (argv, arg_ptr, pred_ctime));
  409. }
  410.  
  411. static boolean
  412. parse_daystart (argv, arg_ptr)
  413.      char *argv[];
  414.      int *arg_ptr;
  415. {
  416.   struct tm *local;
  417.  
  418.   if (full_days == false)
  419.     {
  420.       cur_day_start += DAYSECS;
  421.       local = localtime (&cur_day_start);
  422.       cur_day_start -= local->tm_sec + local->tm_min * 60
  423.     + local->tm_hour * 3600;
  424.       full_days = true;
  425.     }
  426.   return (true);
  427. }
  428.  
  429. static boolean
  430. parse_depth (argv, arg_ptr)
  431.      char *argv[];
  432.      int *arg_ptr;
  433. {
  434.   do_dir_first = false;
  435.   return (true);
  436. }
  437.  
  438. static boolean
  439. parse_empty (argv, arg_ptr)
  440.      char *argv[];
  441.      int *arg_ptr;
  442. {
  443.   insert_primary (pred_empty);
  444.   return (true);
  445. }
  446.  
  447. static boolean
  448. parse_exec (argv, arg_ptr)
  449.      char *argv[];
  450.      int *arg_ptr;
  451. {
  452.   return (insert_exec_ok (pred_exec, argv, arg_ptr));
  453. }
  454.  
  455. static boolean
  456. parse_false (argv, arg_ptr)
  457.      char *argv[];
  458.      int *arg_ptr;
  459. {
  460.   struct predicate *our_pred;
  461.  
  462.   our_pred = insert_primary (pred_false);
  463.   our_pred->need_stat = false;
  464.   return (true);
  465. }
  466.  
  467. static boolean
  468. parse_fls (argv, arg_ptr)
  469.      char *argv[];
  470.      int *arg_ptr;
  471. {
  472.   struct predicate *our_pred;
  473.  
  474.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  475.     return (false);
  476.   our_pred = insert_primary (pred_fls);
  477.   our_pred->args.stream = open_output_file (argv[*arg_ptr]);
  478.   our_pred->side_effects = true;
  479.   (*arg_ptr)++;
  480.   return (true);
  481. }
  482.  
  483. static boolean 
  484. parse_fprintf (argv, arg_ptr)
  485.      char *argv[];
  486.      int *arg_ptr;
  487. {
  488.   FILE *fp;
  489.  
  490.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  491.     return (false);
  492.   if (argv[*arg_ptr + 1] == NULL)
  493.     {
  494.       /* Ensure we get "missing arg" message, not "invalid arg".  */
  495.       (*arg_ptr)++;
  496.       return (false);
  497.     }
  498.   fp = open_output_file (argv[*arg_ptr]);
  499.   (*arg_ptr)++;
  500.   return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr));
  501. }
  502.  
  503. static boolean
  504. parse_follow (argv, arg_ptr)
  505.      char *argv[];
  506.      int *arg_ptr;
  507. {
  508.   dereference = true;
  509.   xstat = stat;
  510.   no_leaf_check = true;
  511.   return (true);
  512. }
  513.  
  514. static boolean
  515. parse_fprint (argv, arg_ptr)
  516.      char *argv[];
  517.      int *arg_ptr;
  518. {
  519.   struct predicate *our_pred;
  520.  
  521.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  522.     return (false);
  523.   our_pred = insert_primary (pred_fprint);
  524.   our_pred->args.stream = open_output_file (argv[*arg_ptr]);
  525.   our_pred->side_effects = true;
  526.   our_pred->need_stat = false;
  527.   (*arg_ptr)++;
  528.   return (true);
  529. }
  530.  
  531. static boolean
  532. parse_fprint0 (argv, arg_ptr)
  533.      char *argv[];
  534.      int *arg_ptr;
  535. {
  536.   struct predicate *our_pred;
  537.  
  538.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  539.     return (false);
  540.   our_pred = insert_primary (pred_fprint0);
  541.   our_pred->args.stream = open_output_file (argv[*arg_ptr]);
  542.   our_pred->side_effects = true;
  543.   our_pred->need_stat = false;
  544.   (*arg_ptr)++;
  545.   return (true);
  546. }
  547.  
  548. static boolean
  549. parse_fstype (argv, arg_ptr)
  550.      char *argv[];
  551.      int *arg_ptr;
  552. {
  553.   struct predicate *our_pred;
  554.  
  555.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  556.     return (false);
  557.   our_pred = insert_primary (pred_fstype);
  558.   our_pred->args.str = argv[*arg_ptr];
  559.   (*arg_ptr)++;
  560.   return (true);
  561. }
  562.  
  563. static boolean
  564. parse_gid (argv, arg_ptr)
  565.      char *argv[];
  566.      int *arg_ptr;
  567. {
  568.   return (insert_num (argv, arg_ptr, pred_gid));
  569. }
  570.  
  571. static boolean
  572. parse_group (argv, arg_ptr)
  573.      char *argv[];
  574.      int *arg_ptr;
  575. {
  576.   struct group *cur_gr;
  577.   struct predicate *our_pred;
  578.   gid_t gid;
  579.   int gid_len;
  580.  
  581.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  582.     return (false);
  583.   cur_gr = getgrnam (argv[*arg_ptr]);
  584.   endgrent ();
  585.   if (cur_gr != NULL)
  586.     gid = cur_gr->gr_gid;
  587.   else
  588.     {
  589.       gid_len = strspn (argv[*arg_ptr], "0123456789");
  590.       if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0'))
  591.     return (false);
  592.       gid = atoi (argv[*arg_ptr]);
  593.     }
  594.   our_pred = insert_primary (pred_group);
  595.   our_pred->args.gid = gid;
  596.   (*arg_ptr)++;
  597.   return (true);
  598. }
  599.  
  600. static boolean
  601. parse_help (argv, arg_ptr)
  602.      char *argv[];
  603.      int *arg_ptr;
  604. {
  605.   printf ("\
  606. Usage: %s [path...] [expression]\n", program_name);
  607.   printf ("\
  608. default path is the current directory; default expression is -print\n\
  609. expression may consist of:\n\
  610. operators (decreasing precedence; -and is implicit where no others are given):\n\
  611.       ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n");
  612.   printf ("\
  613.       EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n\
  614. options (always true): -daystart -depth -follow --help\n\
  615.       -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev\n\
  616. tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n");
  617.   printf ("\
  618.       -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
  619.       -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN\n\
  620.       -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE\n");
  621.   printf ("\
  622.       -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
  623.       -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME\n\
  624.       -xtype [bcdpfls]\n");
  625.   printf ("\
  626. actions: -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT\n\
  627.       -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls\n");
  628.   exit (0);
  629. }
  630.  
  631. static boolean
  632. parse_ilname (argv, arg_ptr)
  633.      char *argv[];
  634.      int *arg_ptr;
  635. {
  636.   struct predicate *our_pred;
  637.  
  638.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  639.     return (false);
  640.   our_pred = insert_primary (pred_ilname);
  641.   our_pred->args.str = argv[*arg_ptr];
  642.   (*arg_ptr)++;
  643.   return (true);
  644. }
  645.  
  646. static boolean
  647. parse_iname (argv, arg_ptr)
  648.      char *argv[];
  649.      int *arg_ptr;
  650. {
  651.   struct predicate *our_pred;
  652.  
  653.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  654.     return (false);
  655.   our_pred = insert_primary (pred_iname);
  656.   our_pred->need_stat = false;
  657.   our_pred->args.str = argv[*arg_ptr];
  658.   (*arg_ptr)++;
  659.   return (true);
  660. }
  661.  
  662. static boolean
  663. parse_inum (argv, arg_ptr)
  664.      char *argv[];
  665.      int *arg_ptr;
  666. {
  667.   return (insert_num (argv, arg_ptr, pred_inum));
  668. }
  669.  
  670. static boolean
  671. parse_ipath (argv, arg_ptr)
  672.      char *argv[];
  673.      int *arg_ptr;
  674. {
  675.   struct predicate *our_pred;
  676.  
  677.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  678.     return (false);
  679.   our_pred = insert_primary (pred_ipath);
  680.   our_pred->need_stat = false;
  681.   our_pred->args.str = argv[*arg_ptr];
  682.   (*arg_ptr)++;
  683.   return (true);
  684. }
  685.  
  686. static boolean
  687. parse_iregex (argv, arg_ptr)
  688.      char *argv[];
  689.      int *arg_ptr;
  690. {
  691.   return insert_regex (argv, arg_ptr, true);
  692. }
  693.  
  694. static boolean
  695. parse_links (argv, arg_ptr)
  696.      char *argv[];
  697.      int *arg_ptr;
  698. {
  699.   return (insert_num (argv, arg_ptr, pred_links));
  700. }
  701.  
  702. static boolean
  703. parse_lname (argv, arg_ptr)
  704.      char *argv[];
  705.      int *arg_ptr;
  706. {
  707.   struct predicate *our_pred;
  708.  
  709.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  710.     return (false);
  711.   our_pred = insert_primary (pred_lname);
  712.   our_pred->args.str = argv[*arg_ptr];
  713.   (*arg_ptr)++;
  714.   return (true);
  715. }
  716.  
  717. static boolean
  718. parse_ls (argv, arg_ptr)
  719.      char *argv[];
  720.      int *arg_ptr;
  721. {
  722.   struct predicate *our_pred;
  723.  
  724.   our_pred = insert_primary (pred_ls);
  725.   our_pred->side_effects = true;
  726.   return (true);
  727. }
  728.  
  729. static boolean
  730. parse_maxdepth (argv, arg_ptr)
  731.      char *argv[];
  732.      int *arg_ptr;
  733. {
  734.   int depth_len;
  735.  
  736.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  737.     return (false);
  738.   depth_len = strspn (argv[*arg_ptr], "0123456789");
  739.   if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
  740.     return (false);
  741.   maxdepth = atoi (argv[*arg_ptr]);
  742.   if (maxdepth < 0)
  743.     return (false);
  744.   (*arg_ptr)++;
  745.   return (true);
  746. }
  747.  
  748. static boolean
  749. parse_mindepth (argv, arg_ptr)
  750.      char *argv[];
  751.      int *arg_ptr;
  752. {
  753.   int depth_len;
  754.  
  755.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  756.     return (false);
  757.   depth_len = strspn (argv[*arg_ptr], "0123456789");
  758.   if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0'))
  759.     return (false);
  760.   mindepth = atoi (argv[*arg_ptr]);
  761.   if (mindepth < 0)
  762.     return (false);
  763.   (*arg_ptr)++;
  764.   return (true);
  765. }
  766.  
  767. static boolean
  768. parse_mmin (argv, arg_ptr)
  769.      char *argv[];
  770.      int *arg_ptr;
  771. {
  772.   struct predicate *our_pred;
  773.   unsigned long num;
  774.   enum comparison_type c_type;
  775.  
  776.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  777.     return (false);
  778.   if (!get_num_days (argv[*arg_ptr], &num, &c_type))
  779.     return (false);
  780.   our_pred = insert_primary (pred_mmin);
  781.   our_pred->args.info.kind = c_type;
  782.   our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60;
  783.   (*arg_ptr)++;
  784.   return (true);
  785. }
  786.  
  787. static boolean
  788. parse_mtime (argv, arg_ptr)
  789.      char *argv[];
  790.      int *arg_ptr;
  791. {
  792.   return (insert_time (argv, arg_ptr, pred_mtime));
  793. }
  794.  
  795. static boolean
  796. parse_name (argv, arg_ptr)
  797.      char *argv[];
  798.      int *arg_ptr;
  799. {
  800.   struct predicate *our_pred;
  801.  
  802.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  803.     return (false);
  804.   our_pred = insert_primary (pred_name);
  805.   our_pred->need_stat = false;
  806.   our_pred->args.str = argv[*arg_ptr];
  807.   (*arg_ptr)++;
  808.   return (true);
  809. }
  810.  
  811. static boolean
  812. parse_negate (argv, arg_ptr)
  813.      char *argv[];
  814.      int *arg_ptr;
  815. {
  816.   struct predicate *our_pred;
  817.  
  818.   our_pred = get_new_pred_chk_op ();
  819.   our_pred->pred_func = pred_negate;
  820. #ifdef    DEBUG
  821.   our_pred->p_name = find_pred_name (pred_negate);
  822. #endif    /* DEBUG */
  823.   our_pred->p_type = UNI_OP;
  824.   our_pred->p_prec = NEGATE_PREC;
  825.   our_pred->need_stat = false;
  826.   return (true);
  827. }
  828.  
  829. static boolean
  830. parse_newer (argv, arg_ptr)
  831.      char *argv[];
  832.      int *arg_ptr;
  833. {
  834.   struct predicate *our_pred;
  835.   struct stat stat_newer;
  836.  
  837.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  838.     return (false);
  839.   if ((*xstat) (argv[*arg_ptr], &stat_newer))
  840.     error (1, errno, "%s", argv[*arg_ptr]);
  841.   our_pred = insert_primary (pred_newer);
  842.   our_pred->args.time = stat_newer.st_mtime;
  843.   (*arg_ptr)++;
  844.   return (true);
  845. }
  846.  
  847. static boolean
  848. parse_noleaf (argv, arg_ptr)
  849.      char *argv[];
  850.      int *arg_ptr;
  851. {
  852.   no_leaf_check = true;
  853.   return true;
  854. }
  855.  
  856. #ifdef CACHE_IDS
  857. /* Arbitrary amount by which to increase size
  858.    of `uid_unused' and `gid_unused'. */
  859. #define ALLOC_STEP 2048
  860.  
  861. /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
  862. char *uid_unused = NULL;
  863.  
  864. /* Number of elements in `uid_unused'. */
  865. unsigned uid_allocated;
  866.  
  867. /* Similar for GIDs and group entries. */
  868. char *gid_unused = NULL;
  869. unsigned gid_allocated;
  870. #endif
  871.  
  872. static boolean
  873. parse_nogroup (argv, arg_ptr)
  874.      char *argv[];
  875.      int *arg_ptr;
  876. {
  877.   struct predicate *our_pred;
  878.  
  879.   our_pred = insert_primary (pred_nogroup);
  880. #ifdef CACHE_IDS
  881.   if (gid_unused == NULL)
  882.     {
  883.       struct group *gr;
  884.  
  885.       gid_allocated = ALLOC_STEP;
  886.       gid_unused = xmalloc (gid_allocated);
  887.       memset (gid_unused, 1, gid_allocated);
  888.       setgrent ();
  889.       while ((gr = getgrent ()) != NULL)
  890.     {
  891.       if ((unsigned) gr->gr_gid >= gid_allocated)
  892.         {
  893.           unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
  894.           gid_unused = xrealloc (gid_unused, new_allocated);
  895.           memset (gid_unused + gid_allocated, 1,
  896.               new_allocated - gid_allocated);
  897.           gid_allocated = new_allocated;
  898.         }
  899.       gid_unused[(unsigned) gr->gr_gid] = 0;
  900.     }
  901.       endgrent ();
  902.     }
  903. #endif
  904.   return (true);
  905. }
  906.  
  907. static boolean
  908. parse_nouser (argv, arg_ptr)
  909.      char *argv[];
  910.      int *arg_ptr;
  911. {
  912.   struct predicate *our_pred;
  913.  
  914.   our_pred = insert_primary (pred_nouser);
  915. #ifdef CACHE_IDS
  916.   if (uid_unused == NULL)
  917.     {
  918.       struct passwd *pw;
  919.  
  920.       uid_allocated = ALLOC_STEP;
  921.       uid_unused = xmalloc (uid_allocated);
  922.       memset (uid_unused, 1, uid_allocated);
  923.       setpwent ();
  924.       while ((pw = getpwent ()) != NULL)
  925.     {
  926.       if ((unsigned) pw->pw_uid >= uid_allocated)
  927.         {
  928.           unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
  929.           uid_unused = xrealloc (uid_unused, new_allocated);
  930.           memset (uid_unused + uid_allocated, 1,
  931.               new_allocated - uid_allocated);
  932.           uid_allocated = new_allocated;
  933.         }
  934.       uid_unused[(unsigned) pw->pw_uid] = 0;
  935.     }
  936.       endpwent ();
  937.     }
  938. #endif
  939.   return (true);
  940. }
  941.  
  942. static boolean
  943. parse_ok (argv, arg_ptr)
  944.      char *argv[];
  945.      int *arg_ptr;
  946. {
  947.   return (insert_exec_ok (pred_ok, argv, arg_ptr));
  948. }
  949.  
  950. boolean
  951. parse_open (argv, arg_ptr)
  952.      char *argv[];
  953.      int *arg_ptr;
  954. {
  955.   struct predicate *our_pred;
  956.  
  957.   our_pred = get_new_pred_chk_op ();
  958.   our_pred->pred_func = pred_open;
  959. #ifdef    DEBUG
  960.   our_pred->p_name = find_pred_name (pred_open);
  961. #endif    /* DEBUG */
  962.   our_pred->p_type = OPEN_PAREN;
  963.   our_pred->p_prec = NO_PREC;
  964.   our_pred->need_stat = false;
  965.   return (true);
  966. }
  967.  
  968. static boolean
  969. parse_or (argv, arg_ptr)
  970.      char *argv[];
  971.      int *arg_ptr;
  972. {
  973.   struct predicate *our_pred;
  974.  
  975.   our_pred = get_new_pred ();
  976.   our_pred->pred_func = pred_or;
  977. #ifdef    DEBUG
  978.   our_pred->p_name = find_pred_name (pred_or);
  979. #endif    /* DEBUG */
  980.   our_pred->p_type = BI_OP;
  981.   our_pred->p_prec = OR_PREC;
  982.   our_pred->need_stat = false;
  983.   return (true);
  984. }
  985.  
  986. static boolean
  987. parse_path (argv, arg_ptr)
  988.      char *argv[];
  989.      int *arg_ptr;
  990. {
  991.   struct predicate *our_pred;
  992.  
  993.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  994.     return (false);
  995.   our_pred = insert_primary (pred_path);
  996.   our_pred->need_stat = false;
  997.   our_pred->args.str = argv[*arg_ptr];
  998.   (*arg_ptr)++;
  999.   return (true);
  1000. }
  1001.  
  1002. static boolean
  1003. parse_perm (argv, arg_ptr)
  1004.      char *argv[];
  1005.      int *arg_ptr;
  1006. {
  1007.   unsigned long perm_val;
  1008.   int mode_start = 0;
  1009.   struct mode_change *change;
  1010.   struct predicate *our_pred;
  1011.  
  1012.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1013.     return (false);
  1014.  
  1015.   switch (argv[*arg_ptr][0])
  1016.     {
  1017.     case '-':
  1018.     case '+':
  1019.       mode_start = 1;
  1020.       break;
  1021.     default:
  1022.       /* empty */
  1023.       break;
  1024.     }
  1025.  
  1026.   change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS);
  1027.   if (change == MODE_INVALID)
  1028.     error (1, 0, "invalid mode `%s'", argv[*arg_ptr]);
  1029.   else if (change == MODE_MEMORY_EXHAUSTED)
  1030.     error (1, 0, "virtual memory exhausted");
  1031.   perm_val = mode_adjust (0, change);
  1032.   mode_free (change);
  1033.  
  1034.   our_pred = insert_primary (pred_perm);
  1035.  
  1036.   switch (argv[*arg_ptr][0])
  1037.     {
  1038.     case '-':
  1039.       /* Set magic flag to indicate true if at least the given bits are set. */
  1040.       our_pred->args.perm = (perm_val & 07777) | 010000;
  1041.       break;
  1042.     case '+':
  1043.       /* Set magic flag to indicate true if any of the given bits are set. */
  1044.       our_pred->args.perm = (perm_val & 07777) | 020000;
  1045.       break;
  1046.     default:
  1047.       /* True if exactly the given bits are set. */
  1048.       our_pred->args.perm = (perm_val & 07777);
  1049.       break;
  1050.     }
  1051.   (*arg_ptr)++;
  1052.   return (true);
  1053. }
  1054.  
  1055. boolean
  1056. parse_print (argv, arg_ptr)
  1057.      char *argv[];
  1058.      int *arg_ptr;
  1059. {
  1060.   struct predicate *our_pred;
  1061.  
  1062.   our_pred = insert_primary (pred_print);
  1063.   /* -print has the side effect of printing.  This prevents us
  1064.      from doing undesired multiple printing when the user has
  1065.      already specified -print. */
  1066.   our_pred->side_effects = true;
  1067.   our_pred->need_stat = false;
  1068.   return (true);
  1069. }
  1070.  
  1071. static boolean
  1072. parse_print0 (argv, arg_ptr)
  1073.      char *argv[];
  1074.      int *arg_ptr;
  1075. {
  1076.   struct predicate *our_pred;
  1077.  
  1078.   our_pred = insert_primary (pred_print0);
  1079.   /* -print0 has the side effect of printing.  This prevents us
  1080.      from doing undesired multiple printing when the user has
  1081.      already specified -print0. */
  1082.   our_pred->side_effects = true;
  1083.   our_pred->need_stat = false;
  1084.   return (true);
  1085. }
  1086.  
  1087. static boolean
  1088. parse_printf (argv, arg_ptr)
  1089.      char *argv[];
  1090.      int *arg_ptr;
  1091. {
  1092.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1093.     return (false);
  1094.   return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr));
  1095. }
  1096.  
  1097. static boolean
  1098. parse_prune (argv, arg_ptr)
  1099.      char *argv[];
  1100.      int *arg_ptr;
  1101. {
  1102.   struct predicate *our_pred;
  1103.  
  1104.   our_pred = insert_primary (pred_prune);
  1105.   our_pred->need_stat = false;
  1106.   return (true);
  1107. }
  1108.  
  1109. static boolean
  1110. parse_regex (argv, arg_ptr)
  1111.      char *argv[];
  1112.      int *arg_ptr;
  1113. {
  1114.   return insert_regex (argv, arg_ptr, false);
  1115. }
  1116.  
  1117. static boolean
  1118. insert_regex (argv, arg_ptr, ignore_case)
  1119.      char *argv[];
  1120.      int *arg_ptr;
  1121.      boolean ignore_case;
  1122. {
  1123.   struct predicate *our_pred;
  1124.   struct re_pattern_buffer *re;
  1125.   const char *error_message;
  1126.  
  1127.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1128.     return (false);
  1129.   our_pred = insert_primary (pred_regex);
  1130.   our_pred->need_stat = false;
  1131.   re = (struct re_pattern_buffer *)
  1132.     xmalloc (sizeof (struct re_pattern_buffer));
  1133.   our_pred->args.regex = re;
  1134.   re->allocated = 100;
  1135.   re->buffer = (unsigned char *) xmalloc (re->allocated);
  1136.   re->fastmap = NULL;
  1137.  
  1138.   if (ignore_case)
  1139.     {
  1140.       unsigned i;
  1141.       
  1142.       re->translate = xmalloc (256);
  1143.       /* Map uppercase characters to corresponding lowercase ones.  */
  1144.       for (i = 0; i < 256; i++)
  1145.         re->translate[i] = ISUPPER (i) ? tolower (i) : i;
  1146.     }
  1147.   else
  1148.     re->translate = NULL;
  1149.  
  1150.   error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]),
  1151.                       re);
  1152.   if (error_message)
  1153.     error (1, 0, "%s", error_message);
  1154.   (*arg_ptr)++;
  1155.   return (true);
  1156. }
  1157.  
  1158. static boolean
  1159. parse_size (argv, arg_ptr)
  1160.      char *argv[];
  1161.      int *arg_ptr;
  1162. {
  1163.   struct predicate *our_pred;
  1164.   unsigned long num;
  1165.   enum comparison_type c_type;
  1166.   int blksize = 512;
  1167.   int len;
  1168.  
  1169.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1170.     return (false);
  1171.   len = strlen (argv[*arg_ptr]);
  1172.   if (len == 0)
  1173.     error (1, 0, "invalid null argument to -size");
  1174.   switch (argv[*arg_ptr][len - 1])
  1175.     {
  1176.     case 'b':
  1177.       blksize = 512;
  1178.       argv[*arg_ptr][len - 1] = '\0';
  1179.       break;
  1180.  
  1181.     case 'c':
  1182.       blksize = 1;
  1183.       argv[*arg_ptr][len - 1] = '\0';
  1184.       break;
  1185.  
  1186.     case 'k':
  1187.       blksize = 1024;
  1188.       argv[*arg_ptr][len - 1] = '\0';
  1189.       break;
  1190.  
  1191.     case 'w':
  1192.       blksize = 2;
  1193.       argv[*arg_ptr][len - 1] = '\0';
  1194.       break;
  1195.  
  1196.     case '0':
  1197.     case '1':
  1198.     case '2':
  1199.     case '3':
  1200.     case '4':
  1201.     case '5':
  1202.     case '6':
  1203.     case '7':
  1204.     case '8':
  1205.     case '9':
  1206.       break;
  1207.  
  1208.     default:
  1209.       error (1, 0, "invalid -size type `%c'", argv[*arg_ptr][len - 1]);
  1210.     }
  1211.   if (!get_num (argv[*arg_ptr], &num, &c_type))
  1212.     return (false);
  1213.   our_pred = insert_primary (pred_size);
  1214.   our_pred->args.size.kind = c_type;
  1215.   our_pred->args.size.blocksize = blksize;
  1216.   our_pred->args.size.size = num;
  1217.   (*arg_ptr)++;
  1218.   return (true);
  1219. }
  1220.  
  1221. static boolean
  1222. parse_true (argv, arg_ptr)
  1223.      char *argv[];
  1224.      int *arg_ptr;
  1225. {
  1226.   struct predicate *our_pred;
  1227.  
  1228.   our_pred = insert_primary (pred_true);
  1229.   our_pred->need_stat = false;
  1230.   return (true);
  1231. }
  1232.  
  1233. static boolean
  1234. parse_type (argv, arg_ptr)
  1235.      char *argv[];
  1236.      int *arg_ptr;
  1237. {
  1238.   return insert_type (argv, arg_ptr, pred_type);
  1239. }
  1240.  
  1241. static boolean
  1242. parse_uid (argv, arg_ptr)
  1243.      char *argv[];
  1244.      int *arg_ptr;
  1245. {
  1246.   return (insert_num (argv, arg_ptr, pred_uid));
  1247. }
  1248.  
  1249. static boolean
  1250. parse_used (argv, arg_ptr)
  1251.      char *argv[];
  1252.      int *arg_ptr;
  1253.  
  1254. {
  1255.   struct predicate *our_pred;
  1256.   unsigned long num_days;
  1257.   enum comparison_type c_type;
  1258.  
  1259.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1260.     return (false);
  1261.   if (!get_num (argv[*arg_ptr], &num_days, &c_type))
  1262.     return (false);
  1263.   our_pred = insert_primary (pred_used);
  1264.   our_pred->args.info.kind = c_type;
  1265.   our_pred->args.info.l_val = num_days * DAYSECS;
  1266.   (*arg_ptr)++;
  1267.   return (true);
  1268. }
  1269.  
  1270. static boolean
  1271. parse_user (argv, arg_ptr)
  1272.      char *argv[];
  1273.      int *arg_ptr;
  1274. {
  1275.   struct passwd *cur_pwd;
  1276.   struct predicate *our_pred;
  1277.   uid_t uid;
  1278.   int uid_len;
  1279.  
  1280.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1281.     return (false);
  1282.   cur_pwd = getpwnam (argv[*arg_ptr]);
  1283.   endpwent ();
  1284.   if (cur_pwd != NULL)
  1285.     uid = cur_pwd->pw_uid;
  1286.   else
  1287.     {
  1288.       uid_len = strspn (argv[*arg_ptr], "0123456789");
  1289.       if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0'))
  1290.     return (false);
  1291.       uid = atoi (argv[*arg_ptr]);
  1292.     }
  1293.   our_pred = insert_primary (pred_user);
  1294.   our_pred->args.uid = uid;
  1295.   (*arg_ptr)++;
  1296.   return (true);
  1297. }
  1298.  
  1299. static boolean
  1300. parse_version (argv, arg_ptr)
  1301.      char *argv[];
  1302.      int *arg_ptr;
  1303. {
  1304.   extern char *version_string;
  1305.  
  1306.   fflush (stderr);
  1307.   printf ("GNU find version %s\n", version_string);
  1308.   exit (0);
  1309. }
  1310.  
  1311. static boolean
  1312. parse_xdev (argv, arg_ptr)
  1313.      char *argv[];
  1314.      int *arg_ptr;
  1315. {
  1316.   stay_on_filesystem = true;
  1317.   return true;
  1318. }
  1319.  
  1320. static boolean
  1321. parse_xtype (argv, arg_ptr)
  1322.      char *argv[];
  1323.      int *arg_ptr;
  1324. {
  1325.   return insert_type (argv, arg_ptr, pred_xtype);
  1326. }
  1327.  
  1328. static boolean
  1329. insert_type (argv, arg_ptr, which_pred)
  1330.      char *argv[];
  1331.      int *arg_ptr;
  1332.      boolean (*which_pred) ();
  1333. {
  1334.   unsigned long type_cell;
  1335.   struct predicate *our_pred;
  1336.  
  1337.   if ((argv == NULL) || (argv[*arg_ptr] == NULL)
  1338.       || (strlen (argv[*arg_ptr]) != 1))
  1339.     return (false);
  1340.   switch (argv[*arg_ptr][0])
  1341.     {
  1342.     case 'b':            /* block special */
  1343.       type_cell = S_IFBLK;
  1344.       break;
  1345.     case 'c':            /* character special */
  1346.       type_cell = S_IFCHR;
  1347.       break;
  1348.     case 'd':            /* directory */
  1349.       type_cell = S_IFDIR;
  1350.       break;
  1351.     case 'f':            /* regular file */
  1352.       type_cell = S_IFREG;
  1353.       break;
  1354. #ifdef S_IFLNK
  1355.     case 'l':            /* symbolic link */
  1356.       type_cell = S_IFLNK;
  1357.       break;
  1358. #endif
  1359. #ifdef S_IFIFO
  1360.     case 'p':            /* pipe */
  1361.       type_cell = S_IFIFO;
  1362.       break;
  1363. #endif
  1364. #ifdef S_IFSOCK
  1365.     case 's':            /* socket */
  1366.       type_cell = S_IFSOCK;
  1367.       break;
  1368. #endif
  1369.     default:            /* None of the above ... nuke 'em. */
  1370.       return (false);
  1371.     }
  1372.   our_pred = insert_primary (which_pred);
  1373.   our_pred->args.type = type_cell;
  1374.   (*arg_ptr)++;            /* Move on to next argument. */
  1375.   return (true);
  1376. }
  1377.  
  1378. /* If true, we've determined that the current fprintf predicate
  1379.    uses stat information. */
  1380. static boolean fprintf_stat_needed;
  1381.  
  1382. static boolean
  1383. insert_fprintf (fp, func, argv, arg_ptr)
  1384.      FILE *fp;
  1385.      boolean (*func) ();
  1386.      char *argv[];
  1387.      int *arg_ptr;
  1388. {
  1389.   char *format;            /* Beginning of unprocessed format string. */
  1390.   register char *scan;        /* Current address in scanning `format'. */
  1391.   register char *scan2;        /* Address inside of element being scanned. */
  1392.   struct segment **segmentp;    /* Address of current segment. */
  1393.   struct predicate *our_pred;
  1394.  
  1395.   format = argv[(*arg_ptr)++];
  1396.  
  1397.   fprintf_stat_needed = false;    /* Might be overridden later. */
  1398.   our_pred = insert_primary (func);
  1399.   our_pred->side_effects = true;
  1400.   our_pred->args.printf_vec.stream = fp;
  1401.   segmentp = &our_pred->args.printf_vec.segment;
  1402.   *segmentp = NULL;
  1403.  
  1404.   for (scan = format; *scan; scan++)
  1405.     {
  1406.       if (*scan == '\\')
  1407.     {
  1408.       scan2 = scan + 1;
  1409.       if (*scan2 >= '0' && *scan2 <= '7')
  1410.         {
  1411.           register int n, i;
  1412.  
  1413.           for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
  1414.            i++, scan2++)
  1415.         n = 8 * n + *scan2 - '0';
  1416.           scan2--;
  1417.           *scan = n;
  1418.         }
  1419.       else
  1420.         {
  1421.           switch (*scan2)
  1422.         {
  1423.         case 'a':
  1424.           *scan = 7;
  1425.           break;
  1426.         case 'b':
  1427.           *scan = '\b';
  1428.           break;
  1429.         case 'c':
  1430.           make_segment (segmentp, format, scan - format, KIND_STOP);
  1431.           our_pred->need_stat = fprintf_stat_needed;
  1432.           return (true);
  1433.         case 'f':
  1434.           *scan = '\f';
  1435.           break;
  1436.         case 'n':
  1437.           *scan = '\n';
  1438.           break;
  1439.         case 'r':
  1440.           *scan = '\r';
  1441.           break;
  1442.         case 't':
  1443.           *scan = '\t';
  1444.           break;
  1445.         case 'v':
  1446.           *scan = '\v';
  1447.           break;
  1448.         case '\\':
  1449.           /* *scan = '\\'; * it already is */
  1450.           break;
  1451.         default:
  1452.           error (0, 0, "warning: unrecognized escape `\\%c'", *scan2);
  1453.           scan++;
  1454.           continue;
  1455.         }
  1456.         }
  1457.       segmentp = make_segment (segmentp, format, scan - format + 1,
  1458.                    KIND_PLAIN);
  1459.       format = scan2 + 1;    /* Move past the escape. */
  1460.       scan = scan2;        /* Incremented immediately by `for'. */
  1461.     }
  1462.       else if (*scan == '%')
  1463.     {
  1464.       if (scan[1] == '%')
  1465.         {
  1466.           segmentp = make_segment (segmentp, format, scan - format + 1,
  1467.                        KIND_PLAIN);
  1468.           scan++;
  1469.           format = scan + 1;
  1470.           continue;
  1471.         }
  1472.       /* Scan past flags, width and precision, to verify kind. */
  1473.       for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
  1474.         /* Do nothing. */ ;
  1475.       while (ISDIGIT (*scan2))
  1476.         scan2++;
  1477.       if (*scan2 == '.')
  1478.         for (scan2++; ISDIGIT (*scan2); scan2++)
  1479.           /* Do nothing. */ ;
  1480.       if (strchr ("abcdfFgGhHiklmnpPstuU", *scan2))
  1481.         {
  1482.           segmentp = make_segment (segmentp, format, scan2 - format,
  1483.                        (int) *scan2);
  1484.           scan = scan2;
  1485.           format = scan + 1;
  1486.         }
  1487.       else if (strchr ("ACT", *scan2) && scan2[1])
  1488.         {
  1489.           segmentp = make_segment (segmentp, format, scan2 - format,
  1490.                        *scan2 | (scan2[1] << 8));
  1491.           scan = scan2 + 1;
  1492.           format = scan + 1;
  1493.           continue;
  1494.         }
  1495.       else
  1496.         {
  1497.           /* An unrecognized % escape.  Print the char after the %. */
  1498.           error (0, 0, "warning: unrecognized format directive `%%%c'",
  1499.              *scan2);
  1500.           segmentp = make_segment (segmentp, format, scan - format,
  1501.                        KIND_PLAIN);
  1502.           format = scan + 1;
  1503.           continue;
  1504.         }
  1505.     }
  1506.     }
  1507.  
  1508.   if (scan > format)
  1509.     make_segment (segmentp, format, scan - format, KIND_PLAIN);
  1510.   our_pred->need_stat = fprintf_stat_needed;
  1511.   return (true);
  1512. }
  1513.  
  1514. /* Create a new fprintf segment in *SEGMENT, with type KIND,
  1515.    from the text in FORMAT, which has length LEN.
  1516.    Return the address of the `next' pointer of the new segment. */
  1517.  
  1518. static struct segment **
  1519. make_segment (segment, format, len, kind)
  1520.      struct segment **segment;
  1521.      char *format;
  1522.      int len, kind;
  1523. {
  1524.   char *fmt;
  1525.  
  1526.   *segment = (struct segment *) xmalloc (sizeof (struct segment));
  1527.  
  1528.   (*segment)->kind = kind;
  1529.   (*segment)->next = NULL;
  1530.   (*segment)->text_len = len;
  1531.  
  1532.   fmt = (*segment)->text = xmalloc (len + 3);    /* room for "ld\0" */
  1533.   strncpy (fmt, format, len);
  1534.   fmt += len;
  1535.  
  1536.   switch (kind & 0xff)
  1537.     {
  1538.     case KIND_PLAIN:        /* Plain text string, no % conversion. */
  1539.     case KIND_STOP:        /* Terminate argument, no newline. */
  1540.       break;
  1541.  
  1542.     case 'a':            /* atime in `ctime' format */
  1543.     case 'c':            /* ctime in `ctime' format */
  1544.     case 'F':            /* filesystem type */
  1545.     case 'g':            /* group name */
  1546.     case 'l':            /* object of symlink */
  1547.     case 't':            /* mtime in `ctime' format */
  1548.     case 'u':            /* user name */
  1549.     case 'A':            /* atime in user-specified strftime format */
  1550.     case 'C':            /* ctime in user-specified strftime format */
  1551.     case 'T':            /* mtime in user-specified strftime format */
  1552.       fprintf_stat_needed = true;
  1553.       /* FALLTHROUGH */
  1554.     case 'f':            /* basename of path */
  1555.     case 'h':            /* leading directories part of path */
  1556.     case 'H':            /* ARGV element file was found under */
  1557.     case 'p':            /* pathname */
  1558.     case 'P':            /* pathname with ARGV element stripped */
  1559.       *fmt++ = 's';
  1560.       break;
  1561.  
  1562.     case 'b':            /* size in 512-byte blocks */
  1563.     case 'k':            /* size in 1K blocks */
  1564.     case 's':            /* size in bytes */
  1565.       *fmt++ = 'l';
  1566.       /*FALLTHROUGH*/
  1567.     case 'n':            /* number of links */
  1568.       fprintf_stat_needed = true;
  1569.       /* FALLTHROUGH */
  1570.     case 'd':            /* depth in search tree (0 = ARGV element) */
  1571.       *fmt++ = 'd';
  1572.       break;
  1573.  
  1574.     case 'i':            /* inode number */
  1575.       *fmt++ = 'l';
  1576.       /*FALLTHROUGH*/
  1577.     case 'G':            /* GID number */
  1578.     case 'U':            /* UID number */
  1579.       *fmt++ = 'u';
  1580.       fprintf_stat_needed = true;
  1581.       break;
  1582.  
  1583.     case 'm':            /* mode as octal number (perms only) */
  1584.       *fmt++ = 'o';
  1585.       fprintf_stat_needed = true;
  1586.       break;
  1587.     }
  1588.   *fmt = '\0';
  1589.  
  1590.   return (&(*segment)->next);
  1591. }
  1592.  
  1593. static boolean
  1594. insert_exec_ok (func, argv, arg_ptr)
  1595.      boolean (*func) ();
  1596.      char *argv[];
  1597.      int *arg_ptr;
  1598. {
  1599.   int start, end;        /* Indexes in ARGV of start & end of cmd. */
  1600.   int num_paths;        /* Number of args with path replacements. */
  1601.   int path_pos;            /* Index in array of path replacements. */
  1602.   int vec_pos;            /* Index in array of args. */
  1603.   struct predicate *our_pred;
  1604.   struct exec_val *execp;    /* Pointer for efficiency. */
  1605.  
  1606.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1607.     return (false);
  1608.  
  1609.   /* Count the number of args with path replacements, up until the ';'. */
  1610.   start = *arg_ptr;
  1611.   for (end = start, num_paths = 0;
  1612.        (argv[end] != NULL)
  1613.        && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
  1614.        end++)
  1615.     if (strstr (argv[end], "{}"))
  1616.       num_paths++;
  1617.   /* Fail if no command given or no semicolon found. */
  1618.   if ((end == start) || (argv[end] == NULL))
  1619.     {
  1620.       *arg_ptr = end;
  1621.       return (false);
  1622.     }
  1623.  
  1624.   our_pred = insert_primary (func);
  1625.   our_pred->side_effects = true;
  1626.   execp = &our_pred->args.exec_vec;
  1627.   execp->paths =
  1628.     (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1));
  1629.   execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1));
  1630.   /* Record the positions of all args, and the args with path replacements. */
  1631.   for (end = start, path_pos = vec_pos = 0;
  1632.        (argv[end] != NULL)
  1633.        && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
  1634.        end++)
  1635.     {
  1636.       register char *p;
  1637.       
  1638.       execp->paths[path_pos].count = 0;
  1639.       for (p = argv[end]; *p; ++p)
  1640.     if (p[0] == '{' && p[1] == '}')
  1641.       {
  1642.         execp->paths[path_pos].count++;
  1643.         ++p;
  1644.       }
  1645.       if (execp->paths[path_pos].count)
  1646.     {
  1647.       execp->paths[path_pos].offset = vec_pos;
  1648.       execp->paths[path_pos].origarg = argv[end];
  1649.       path_pos++;
  1650.     }
  1651.       execp->vec[vec_pos++] = argv[end];
  1652.     }
  1653.   execp->paths[path_pos].offset = -1;
  1654.   execp->vec[vec_pos] = NULL;
  1655.  
  1656.   if (argv[end] == NULL)
  1657.     *arg_ptr = end;
  1658.   else
  1659.     *arg_ptr = end + 1;
  1660.   return (true);
  1661. }
  1662.  
  1663. /* Get a number of days and comparison type.
  1664.    STR is the ASCII representation.
  1665.    Set *NUM_DAYS to the number of days, taken as being from
  1666.    the current moment (or possibly midnight).  Thus the sense of the
  1667.    comparison type appears to be reversed.
  1668.    Set *COMP_TYPE to the kind of comparison that is requested.
  1669.  
  1670.    Return true if all okay, false if input error.
  1671.  
  1672.    Used by -atime, -ctime and -mtime (parsers) to
  1673.    get the appropriate information for a time predicate processor. */
  1674.  
  1675. static boolean
  1676. get_num_days (str, num_days, comp_type)
  1677.      char *str;
  1678.      unsigned long *num_days;
  1679.      enum comparison_type *comp_type;
  1680. {
  1681.   int len_days;            /* length of field */
  1682.  
  1683.   if (str == NULL)
  1684.     return (false);
  1685.   switch (str[0])
  1686.     {
  1687.     case '+':
  1688.       *comp_type = COMP_LT;
  1689.       str++;
  1690.       break;
  1691.     case '-':
  1692.       *comp_type = COMP_GT;
  1693.       str++;
  1694.       break;
  1695.     case '0':
  1696.     case '1':
  1697.     case '2':
  1698.     case '3':
  1699.     case '4':
  1700.     case '5':
  1701.     case '6':
  1702.     case '7':
  1703.     case '8':
  1704.     case '9':
  1705.       *comp_type = COMP_EQ;
  1706.       break;
  1707.     default:
  1708.       return (false);
  1709.     }
  1710.  
  1711.   /* We know the first char has been reasonable.  Find the
  1712.      number of days to play with. */
  1713.   len_days = strspn (str, "0123456789");
  1714.   if ((len_days == 0) || (str[len_days] != '\0'))
  1715.     return (false);
  1716.   *num_days = (unsigned long) atol (str);
  1717.   return (true);
  1718. }
  1719.  
  1720. /* Insert a time predicate PRED.
  1721.    ARGV is a pointer to the argument array.
  1722.    ARG_PTR is a pointer to an index into the array, incremented if
  1723.    all went well.
  1724.  
  1725.    Return true if input is valid, false if not.
  1726.  
  1727.    A new predicate node is assigned, along with an argument node
  1728.    obtained with malloc.
  1729.  
  1730.    Used by -atime, -ctime, and -mtime parsers. */
  1731.  
  1732. static boolean
  1733. insert_time (argv, arg_ptr, pred)
  1734.      char *argv[];
  1735.      int *arg_ptr;
  1736.      PFB pred;
  1737. {
  1738.   struct predicate *our_pred;
  1739.   unsigned long num_days;
  1740.   enum comparison_type c_type;
  1741.  
  1742.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1743.     return (false);
  1744.   if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
  1745.     return (false);
  1746.   our_pred = insert_primary (pred);
  1747.   our_pred->args.info.kind = c_type;
  1748.   our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS
  1749.     + ((c_type == COMP_GT) ? DAYSECS - 1 : 0);
  1750.   (*arg_ptr)++;
  1751. #ifdef    DEBUG
  1752.   printf ("inserting %s\n", our_pred->p_name);
  1753.   printf ("    type: %s    %s  ",
  1754.       (c_type == COMP_GT) ? "gt" :
  1755.       ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
  1756.       (c_type == COMP_GT) ? " >" :
  1757.       ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
  1758.   printf ("%ld %s", our_pred->args.info.l_val,
  1759.       ctime (&our_pred->args.info.l_val));
  1760.   if (c_type == COMP_EQ)
  1761.     {
  1762.       our_pred->args.info.l_val += DAYSECS;
  1763.       printf ("                 <  %ld %s", our_pred->args.info.l_val,
  1764.           ctime (&our_pred->args.info.l_val));
  1765.       our_pred->args.info.l_val -= DAYSECS;
  1766.     }
  1767. #endif    /* DEBUG */
  1768.   return (true);
  1769. }
  1770.  
  1771. /* Get a number with comparision information.
  1772.    The sense of the comparision information is 'normal'; that is,
  1773.    '+' looks for inums or links > than the number and '-' less than.
  1774.    
  1775.    STR is the ASCII representation of the number.
  1776.    Set *NUM to the number.
  1777.    Set *COMP_TYPE to the kind of comparison that is requested.
  1778.  
  1779.    Return true if all okay, false if input error.
  1780.  
  1781.    Used by the -inum and -links predicate parsers. */
  1782.  
  1783. static boolean
  1784. get_num (str, num, comp_type)
  1785.      char *str;
  1786.      unsigned long *num;
  1787.      enum comparison_type *comp_type;
  1788. {
  1789.   int len_num;            /* Length of field. */
  1790.  
  1791.   if (str == NULL)
  1792.     return (false);
  1793.   switch (str[0])
  1794.     {
  1795.     case '+':
  1796.       *comp_type = COMP_GT;
  1797.       str++;
  1798.       break;
  1799.     case '-':
  1800.       *comp_type = COMP_LT;
  1801.       str++;
  1802.       break;
  1803.     case '0':
  1804.     case '1':
  1805.     case '2':
  1806.     case '3':
  1807.     case '4':
  1808.     case '5':
  1809.     case '6':
  1810.     case '7':
  1811.     case '8':
  1812.     case '9':
  1813.       *comp_type = COMP_EQ;
  1814.       break;
  1815.     default:
  1816.       return (false);
  1817.     }
  1818.  
  1819.   /* We know the first char has been reasonable.  Find the number of
  1820.      days to play with. */
  1821.   len_num = strspn (str, "0123456789");
  1822.   if ((len_num == 0) || (str[len_num] != '\0'))
  1823.     return (false);
  1824.   *num = (unsigned long) atol (str);
  1825.   return (true);
  1826. }
  1827.  
  1828. /* Insert a number predicate.
  1829.    ARGV is a pointer to the argument array.
  1830.    *ARG_PTR is an index into ARGV, incremented if all went well.
  1831.    *PRED is the predicate processor to insert.
  1832.  
  1833.    Return true if input is valid, false if error.
  1834.    
  1835.    A new predicate node is assigned, along with an argument node
  1836.    obtained with malloc.
  1837.  
  1838.    Used by -inum and -links parsers. */
  1839.  
  1840. static boolean
  1841. insert_num (argv, arg_ptr, pred)
  1842.      char *argv[];
  1843.      int *arg_ptr;
  1844.      PFB pred;
  1845. {
  1846.   struct predicate *our_pred;
  1847.   unsigned long num;
  1848.   enum comparison_type c_type;
  1849.  
  1850.   if ((argv == NULL) || (argv[*arg_ptr] == NULL))
  1851.     return (false);
  1852.   if (!get_num (argv[*arg_ptr], &num, &c_type))
  1853.     return (false);
  1854.   our_pred = insert_primary (pred);
  1855.   our_pred->args.info.kind = c_type;
  1856.   our_pred->args.info.l_val = num;
  1857.   (*arg_ptr)++;
  1858. #ifdef    DEBUG
  1859.   printf ("inserting %s\n", our_pred->p_name);
  1860.   printf ("    type: %s    %s  ",
  1861.       (c_type == COMP_GT) ? "gt" :
  1862.       ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
  1863.       (c_type == COMP_GT) ? " >" :
  1864.       ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
  1865.   printf ("%ld\n", our_pred->args.info.l_val);
  1866. #endif    /* DEBUG */
  1867.   return (true);
  1868. }
  1869.  
  1870. static FILE *
  1871. open_output_file (path)
  1872.      char *path;
  1873. {
  1874.   FILE *f;
  1875.  
  1876.   if (!strcmp (path, "/dev/stderr"))
  1877.     return (stderr);
  1878.   else if (!strcmp (path, "/dev/stdout"))
  1879.     return (stdout);
  1880.   f = fopen (path, "w");
  1881.   if (f == NULL)
  1882.     error (1, errno, "%s", path);
  1883.   return (f);
  1884. }
  1885.