home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / find-3.8-src.lha / src / amiga / find-3.8 / find / parser.c < prev    next >
C/C++ Source or Header  |  1993-03-26  |  44KB  |  1,872 lines

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