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 / pred.c < prev    next >
C/C++ Source or Header  |  1994-02-23  |  36KB  |  1,576 lines

  1. /* pred.c -- execute the 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 <stdio.h>
  19. #include <fnmatch.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22.  
  23. #ifdef HAVE_UNISTD_H
  24. #include <unistd.h>
  25. #endif
  26.  
  27. #include <pwd.h>
  28. #include <grp.h>
  29.  
  30. #ifndef _POSIX_VERSION
  31. struct passwd *getpwuid ();
  32. struct group *getgrgid ();
  33. #endif
  34. #include "defs.h"
  35. #include "modetype.h"
  36.  
  37. #include "wait.h"
  38.  
  39. #if defined(DIRENT) || defined(_POSIX_VERSION)
  40. #include <dirent.h>
  41. #define NLENGTH(direct) (strlen((direct)->d_name))
  42. #else /* not (DIRENT or _POSIX_VERSION) */
  43. #define dirent direct
  44. #define NLENGTH(direct) ((direct)->d_namlen)
  45. #ifdef SYSNDIR
  46. #include <sys/ndir.h>
  47. #endif /* SYSNDIR */
  48. #ifdef SYSDIR
  49. #include <sys/dir.h>
  50. #endif /* SYSDIR */
  51. #ifdef NDIR
  52. #include <ndir.h>
  53. #endif /* NDIR */
  54. #endif /* DIRENT or _POSIX_VERSION */
  55.  
  56. #ifdef VOID_CLOSEDIR
  57. /* Fake a return value. */
  58. #define CLOSEDIR(d) (closedir (d), 0)
  59. #else
  60. #define CLOSEDIR(d) closedir (d)
  61. #endif
  62.  
  63. #ifndef S_IFLNK
  64. #define lstat stat
  65. #endif
  66.  
  67. /* Extract or fake data from a `struct stat'.
  68.    ST_NBLOCKS: Number of 512-byte blocks in the file
  69.    (including indirect blocks). */
  70. #ifdef _POSIX_SOURCE
  71. #define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
  72. #else /* !_POSIX_SOURCE */
  73. #ifndef HAVE_ST_BLOCKS
  74. #define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
  75. #else /* HAVE_ST_BLOCKS */
  76. #if defined(hpux) || defined(__hpux__)
  77. /* HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
  78.    This loses when mixing HP-UX and 4BSD filesystems, though. */
  79. #define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
  80. #else /* !hpux */
  81. #define ST_NBLOCKS(statp) ((statp)->st_blocks)
  82. #endif /* !hpux */
  83. #endif /* HAVE_ST_BLOCKS */
  84. #endif /* !_POSIX_SOURCE */
  85.  
  86. boolean pred_amin ();
  87. boolean pred_and ();
  88. boolean pred_anewer ();
  89. boolean pred_atime ();
  90. boolean pred_close ();
  91. boolean pred_cmin ();
  92. boolean pred_cnewer ();
  93. boolean pred_comma ();
  94. boolean pred_ctime ();
  95. /* no pred_daystart */
  96. /* no pred_depth */
  97. boolean pred_empty ();
  98. boolean pred_exec ();
  99. boolean pred_false ();
  100. boolean pred_fprint ();
  101. boolean pred_fprint0 ();
  102. boolean pred_fprintf ();
  103. boolean pred_fstype ();
  104. boolean pred_gid ();
  105. boolean pred_group ();
  106. boolean pred_ilname ();
  107. boolean pred_iname ();
  108. boolean pred_inum ();
  109. boolean pred_ipath ();
  110. /* no pred_iregex */
  111. boolean pred_links ();
  112. boolean pred_lname ();
  113. boolean pred_ls ();
  114. boolean pred_mmin ();
  115. boolean pred_mtime ();
  116. boolean pred_name ();
  117. boolean pred_negate ();
  118. boolean pred_newer ();
  119. /* no pred_noleaf */
  120. boolean pred_nogroup ();
  121. boolean pred_nouser ();
  122. boolean pred_ok ();
  123. boolean pred_open ();
  124. boolean pred_or ();
  125. boolean pred_path ();
  126. boolean pred_perm ();
  127. boolean pred_print ();
  128. boolean pred_print0 ();
  129. /* no pred_printf */
  130. boolean pred_prune ();
  131. boolean pred_regex ();
  132. boolean pred_size ();
  133. boolean pred_true ();
  134. boolean pred_type ();
  135. boolean pred_uid ();
  136. boolean pred_used ();
  137. boolean pred_user ();
  138. /* no pred_version */
  139. /* no pred_xdev */
  140. boolean pred_xtype ();
  141.  
  142. int lstat ();
  143. int stat ();
  144.  
  145. boolean launch ();
  146. char *basename ();
  147. char *format_date ();
  148. char *filesystem_type ();
  149. char *stpcpy ();
  150. void list_file ();
  151.  
  152. static boolean insert_lname ();
  153.  
  154. #ifdef    DEBUG
  155. struct pred_assoc
  156. {
  157.   PFB pred_func;
  158.   char *pred_name;
  159. };
  160.  
  161. struct pred_assoc pred_table[] =
  162. {
  163.   {pred_amin, "amin    "},
  164.   {pred_and, "and     "},
  165.   {pred_anewer, "anewer  "},
  166.   {pred_atime, "atime   "},
  167.   {pred_close, ")       "},
  168.   {pred_amin, "cmin    "},
  169.   {pred_cnewer, "cnewer  "},
  170.   {pred_comma, ",       "},
  171.   {pred_ctime, "ctime   "},
  172.   {pred_empty, "empty   "},
  173.   {pred_exec, "exec    "},
  174.   {pred_false, "false   "},
  175.   {pred_fprint, "fprint  "},
  176.   {pred_fprint0, "fprint0 "},
  177.   {pred_fprintf, "fprintf "},
  178.   {pred_fstype, "fstype  "},
  179.   {pred_gid, "gid     "},
  180.   {pred_group, "group   "},
  181.   {pred_ilname, "ilname  "},
  182.   {pred_iname, "iname   "},
  183.   {pred_inum, "inum    "},
  184.   {pred_ipath, "ipath   "},
  185.   {pred_links, "links   "},
  186.   {pred_lname, "lname   "},
  187.   {pred_ls, "ls      "},
  188.   {pred_amin, "mmin    "},
  189.   {pred_mtime, "mtime   "},
  190.   {pred_name, "name    "},
  191.   {pred_negate, "not     "},
  192.   {pred_newer, "newer   "},
  193.   {pred_nogroup, "nogroup "},
  194.   {pred_nouser, "nouser  "},
  195.   {pred_ok, "ok      "},
  196.   {pred_open, "(       "},
  197.   {pred_or, "or      "},
  198.   {pred_path, "path    "},
  199.   {pred_perm, "perm    "},
  200.   {pred_print, "print   "},
  201.   {pred_print0, "print0  "},
  202.   {pred_prune, "prune   "},
  203.   {pred_regex, "regex   "},
  204.   {pred_size, "size    "},
  205.   {pred_true, "true    "},
  206.   {pred_type, "type    "},
  207.   {pred_uid, "uid     "},
  208.   {pred_used, "used    "},
  209.   {pred_user, "user    "},
  210.   {pred_xtype, "xtype   "},
  211.   {0, "none    "}
  212. };
  213.  
  214. struct op_assoc
  215. {
  216.   short type;
  217.   char *type_name;
  218. };
  219.  
  220. struct op_assoc type_table[] =
  221. {
  222.   {NO_TYPE, "no          "},
  223.   {VICTIM_TYPE, "victim      "},
  224.   {UNI_OP, "uni_op      "},
  225.   {BI_OP, "bi_op       "},
  226.   {OPEN_PAREN, "open_paren  "},
  227.   {CLOSE_PAREN, "close_paren "},
  228.   {-1, "unknown     "}
  229. };
  230.  
  231. struct prec_assoc
  232. {
  233.   short prec;
  234.   char *prec_name;
  235. };
  236.  
  237. struct prec_assoc prec_table[] =
  238. {
  239.   {NO_PREC, "no      "},
  240.   {COMMA_PREC, "comma   "},
  241.   {OR_PREC, "or      "},
  242.   {AND_PREC, "and     "},
  243.   {NEGATE_PREC, "negate  "},
  244.   {MAX_PREC, "max     "},
  245.   {-1, "unknown "}
  246. };
  247. #endif    /* DEBUG */
  248.  
  249. /* Predicate processing routines.
  250.  
  251.    PATHNAME is the full pathname of the file being checked.
  252.    *STAT_BUF contains information about PATHNAME.
  253.    *PRED_PTR contains information for applying the predicate.
  254.  
  255.    Return true if the file passes this predicate, false if not. */
  256.  
  257. boolean
  258. pred_amin (pathname, stat_buf, pred_ptr)
  259.      char *pathname;
  260.      struct stat *stat_buf;
  261.      struct predicate *pred_ptr;
  262. {
  263.   switch (pred_ptr->args.info.kind)
  264.     {
  265.     case COMP_GT:
  266.       if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
  267.     return (true);
  268.       break;
  269.     case COMP_LT:
  270.       if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
  271.     return (true);
  272.       break;
  273.     case COMP_EQ:
  274.       if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
  275.       && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val + 60))
  276.     return (true);
  277.       break;
  278.     }
  279.   return (false);
  280. }
  281.  
  282. boolean
  283. pred_and (pathname, stat_buf, pred_ptr)
  284.      char *pathname;
  285.      struct stat *stat_buf;
  286.      struct predicate *pred_ptr;
  287. {
  288.   if (pred_ptr->pred_left == NULL
  289.       || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
  290.                         pred_ptr->pred_left))
  291.     {
  292.       /* Check whether we need a stat here. */
  293.       if (pred_ptr->need_stat)
  294.     {
  295.       if (!have_stat && (*xstat) (pathname, stat_buf) != 0)
  296.         {
  297.           fflush (stdout);
  298.           error (0, errno, "%s", pathname);
  299.           exit_status = 1;
  300.           return (false);
  301.         }
  302.       have_stat = true;
  303.     }
  304.       return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
  305.                           pred_ptr->pred_right));
  306.     }
  307.   else
  308.     return (false);
  309. }
  310.  
  311. boolean
  312. pred_anewer (pathname, stat_buf, pred_ptr)
  313.      char *pathname;
  314.      struct stat *stat_buf;
  315.      struct predicate *pred_ptr;
  316. {
  317.   if (stat_buf->st_atime > pred_ptr->args.time)
  318.     return (true);
  319.   return (false);
  320. }
  321.  
  322. boolean
  323. pred_atime (pathname, stat_buf, pred_ptr)
  324.      char *pathname;
  325.      struct stat *stat_buf;
  326.      struct predicate *pred_ptr;
  327. {
  328.   switch (pred_ptr->args.info.kind)
  329.     {
  330.     case COMP_GT:
  331.       if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
  332.     return (true);
  333.       break;
  334.     case COMP_LT:
  335.       if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
  336.     return (true);
  337.       break;
  338.     case COMP_EQ:
  339.       if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
  340.       && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val
  341.           + DAYSECS))
  342.     return (true);
  343.       break;
  344.     }
  345.   return (false);
  346. }
  347.  
  348. boolean
  349. pred_close (pathname, stat_buf, pred_ptr)
  350.      char *pathname;
  351.      struct stat *stat_buf;
  352.      struct predicate *pred_ptr;
  353. {
  354.   return (true);
  355. }
  356.  
  357. boolean
  358. pred_cmin (pathname, stat_buf, pred_ptr)
  359.      char *pathname;
  360.      struct stat *stat_buf;
  361.      struct predicate *pred_ptr;
  362. {
  363.   switch (pred_ptr->args.info.kind)
  364.     {
  365.     case COMP_GT:
  366.       if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
  367.     return (true);
  368.       break;
  369.     case COMP_LT:
  370.       if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
  371.     return (true);
  372.       break;
  373.     case COMP_EQ:
  374.       if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
  375.       && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val + 60))
  376.     return (true);
  377.       break;
  378.     }
  379.   return (false);
  380. }
  381.  
  382. boolean
  383. pred_cnewer (pathname, stat_buf, pred_ptr)
  384.      char *pathname;
  385.      struct stat *stat_buf;
  386.      struct predicate *pred_ptr;
  387. {
  388.   if (stat_buf->st_ctime > pred_ptr->args.time)
  389.     return (true);
  390.   return (false);
  391. }
  392.  
  393. boolean
  394. pred_comma (pathname, stat_buf, pred_ptr)
  395.      char *pathname;
  396.      struct stat *stat_buf;
  397.      struct predicate *pred_ptr;
  398. {
  399.   if (pred_ptr->pred_left != NULL)
  400.     (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
  401.                        pred_ptr->pred_left);
  402.   /* Check whether we need a stat here. */
  403.   if (pred_ptr->need_stat)
  404.     {
  405.       if (!have_stat && (*xstat) (pathname, stat_buf) != 0)
  406.     {
  407.       fflush (stdout);
  408.       error (0, errno, "%s", pathname);
  409.       exit_status = 1;
  410.       return (false);
  411.     }
  412.       have_stat = true;
  413.     }
  414.   return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
  415.                           pred_ptr->pred_right));
  416. }
  417.  
  418. boolean
  419. pred_ctime (pathname, stat_buf, pred_ptr)
  420.      char *pathname;
  421.      struct stat *stat_buf;
  422.      struct predicate *pred_ptr;
  423. {
  424.   switch (pred_ptr->args.info.kind)
  425.     {
  426.     case COMP_GT:
  427.       if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
  428.     return (true);
  429.       break;
  430.     case COMP_LT:
  431.       if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
  432.     return (true);
  433.       break;
  434.     case COMP_EQ:
  435.       if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
  436.       && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val
  437.           + DAYSECS))
  438.     return (true);
  439.       break;
  440.     }
  441.   return (false);
  442. }
  443.  
  444. boolean
  445. pred_empty (pathname, stat_buf, pred_ptr)
  446.      char *pathname;
  447.      struct stat *stat_buf;
  448.      struct predicate *pred_ptr;
  449. {
  450.   if (S_ISDIR (stat_buf->st_mode))
  451.     {
  452.       DIR *d;
  453.       struct dirent *dp;
  454.       boolean empty = true;
  455.  
  456.       errno = 0;
  457.       d = opendir (pathname);
  458.       if (d == NULL)
  459.     {
  460.       fflush (stdout);
  461.       error (0, errno, "%s", pathname);
  462.       exit_status = 1;
  463.       return (false);
  464.     }
  465.       for (dp = readdir (d); dp; dp = readdir (d))
  466.     {
  467.       if (dp->d_name[0] != '.'
  468.           || (dp->d_name[1] != '\0'
  469.           && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
  470.         {
  471.           empty = false;
  472.           break;
  473.         }
  474.     }
  475.       if (CLOSEDIR (d))
  476.     {
  477.       fflush (stdout);
  478.       error (0, errno, "%s", pathname);
  479.       exit_status = 1;
  480.       return (false);
  481.     }
  482.       return (empty);
  483.     }
  484.   else if (S_ISREG (stat_buf->st_mode))
  485.     return (stat_buf->st_size == 0);
  486.   else
  487.     return (false);
  488. }
  489.  
  490. boolean
  491. pred_exec (pathname, stat_buf, pred_ptr)
  492.      char *pathname;
  493.      struct stat *stat_buf;
  494.      struct predicate *pred_ptr;
  495. {
  496.   int i;
  497.   int path_pos;
  498.   struct exec_val *execp;    /* Pointer for efficiency. */
  499.  
  500.   execp = &pred_ptr->args.exec_vec;
  501.  
  502.   /* Replace "{}" with the real path in each affected arg. */
  503.   for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
  504.     {
  505.       register char *from, *to;
  506.  
  507.       i = execp->paths[path_pos].offset;
  508.       execp->vec[i] =
  509.     xmalloc (strlen (execp->paths[path_pos].origarg) + 1
  510.          + (strlen (pathname) - 2) * execp->paths[path_pos].count);
  511.       for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
  512.     if (from[0] == '{' && from[1] == '}')
  513.       {
  514.         to = stpcpy (to, pathname);
  515.         from += 2;
  516.       }
  517.     else
  518.       *to++ = *from++;
  519.       *to = *from;        /* Copy null. */
  520.     }
  521.  
  522.   i = launch (pred_ptr);
  523.  
  524.   /* Free the temporary args. */
  525.   for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
  526.     free (execp->vec[execp->paths[path_pos].offset]);
  527.  
  528.   return (i);
  529. }
  530.  
  531. boolean
  532. pred_false (pathname, stat_buf, pred_ptr)
  533.      char *pathname;
  534.      struct stat *stat_buf;
  535.      struct predicate *pred_ptr;
  536. {
  537.   return (false);
  538. }
  539.  
  540. boolean
  541. pred_fprint (pathname, stat_buf, pred_ptr)
  542.      char *pathname;
  543.      struct stat *stat_buf;
  544.      struct predicate *pred_ptr;
  545. {
  546.   fputs (pathname, pred_ptr->args.stream);
  547.   putc ('\n', pred_ptr->args.stream);
  548.   return (true);
  549. }
  550.  
  551. boolean
  552. pred_fprint0 (pathname, stat_buf, pred_ptr)
  553.      char *pathname;
  554.      struct stat *stat_buf;
  555.      struct predicate *pred_ptr;
  556. {
  557.   fputs (pathname, pred_ptr->args.stream);
  558.   putc (0, pred_ptr->args.stream);
  559.   return (true);
  560. }
  561.  
  562. boolean
  563. pred_fprintf (pathname, stat_buf, pred_ptr)
  564.      char *pathname;
  565.      struct stat *stat_buf;
  566.      struct predicate *pred_ptr;
  567. {
  568.   FILE *fp = pred_ptr->args.printf_vec.stream;
  569.   struct segment *segment;
  570.   char *cp;
  571.  
  572.   for (segment = pred_ptr->args.printf_vec.segment; segment;
  573.        segment = segment->next)
  574.     {
  575.       if (segment->kind & 0xff00) /* Component of date. */
  576.     {
  577.       time_t t;
  578.  
  579.       switch (segment->kind & 0xff)
  580.         {
  581.         case 'A':
  582.           t = stat_buf->st_atime;
  583.           break;
  584.         case 'C':
  585.           t = stat_buf->st_ctime;
  586.           break;
  587.         case 'T':
  588.           t = stat_buf->st_mtime;
  589.           break;
  590.         }
  591.       fprintf (fp, segment->text,
  592.            format_date (t, (segment->kind >> 8) & 0xff));
  593.       continue;
  594.     }
  595.  
  596.       switch (segment->kind)
  597.     {
  598.     case KIND_PLAIN:    /* Plain text string (no % conversion). */
  599.       fwrite (segment->text, 1, segment->text_len, fp);
  600.       break;
  601.     case KIND_STOP:        /* Terminate argument (no newline). */
  602.       fwrite (segment->text, 1, segment->text_len, fp);
  603.       return (true);
  604.     case 'a':        /* atime in `ctime' format. */
  605.       cp = ctime (&stat_buf->st_atime);
  606.       cp[24] = '\0';
  607.       fprintf (fp, segment->text, cp);
  608.       break;
  609.     case 'b':        /* size in 512-byte blocks */
  610.       fprintf (fp, segment->text, ST_NBLOCKS (stat_buf));
  611.       break;
  612.     case 'c':        /* ctime in `ctime' format */
  613.       cp = ctime (&stat_buf->st_ctime);
  614.       cp[24] = '\0';
  615.       fprintf (fp, segment->text, cp);
  616.       break;
  617.     case 'd':        /* depth in search tree */
  618.       fprintf (fp, segment->text, curdepth);
  619.       break;
  620.     case 'f':        /* basename of path */
  621.       cp = rindex (pathname, '/');
  622.       if (cp)
  623.         cp++;
  624.       else
  625.         cp = pathname;
  626.       fprintf (fp, segment->text, cp);
  627.       break;
  628.     case 'F':        /* filesystem type */
  629.       fprintf (fp, segment->text, filesystem_type (pathname, stat_buf));
  630.       break;
  631.     case 'g':        /* group name */
  632.       {
  633.         struct group *g;
  634.  
  635.         g = getgrgid (stat_buf->st_gid);
  636.         if (g)
  637.           {
  638.         segment->text[segment->text_len] = 's';
  639.         fprintf (fp, segment->text, g->gr_name);
  640.         break;
  641.           }
  642.         /* else fallthru */
  643.       }
  644.     case 'G':        /* GID number */
  645.       segment->text[segment->text_len] = 'u';
  646.       fprintf (fp, segment->text, stat_buf->st_gid);
  647.       break;
  648.     case 'h':        /* leading directories part of path */
  649.       {
  650.         char cc;
  651.  
  652.         cp = rindex (pathname, '/');
  653.         if (cp == NULL)    /* No leading directories. */
  654.           break;
  655.         cc = *cp;
  656.         *cp = '\0';
  657.         fprintf (fp, segment->text, pathname);
  658.         *cp = cc;
  659.         break;
  660.       }
  661.     case 'H':        /* ARGV element file was found under */
  662.       {
  663.         char cc = pathname[path_length];
  664.  
  665.         pathname[path_length] = '\0';
  666.         fprintf (fp, segment->text, pathname);
  667.         pathname[path_length] = cc;
  668.         break;
  669.       }
  670.     case 'i':        /* inode number */
  671.       fprintf (fp, segment->text, stat_buf->st_ino);
  672.       break;
  673.     case 'k':        /* size in 1K blocks */
  674.       fprintf (fp, segment->text, (ST_NBLOCKS (stat_buf) + 1) / 2);
  675.       break;
  676.     case 'l':        /* object of symlink */
  677. #ifdef S_ISLNK
  678.       {
  679.         int linklen;
  680.         char *linkname;
  681.  
  682.         if (!S_ISLNK (stat_buf->st_mode))
  683.           break;
  684. #ifdef _AIX
  685. #define LINK_BUF PATH_MAX
  686. #else
  687. #define LINK_BUF stat_buf->st_size
  688. #endif
  689.         linkname = (char *) xmalloc (LINK_BUF + 1);
  690.         linklen = readlink (pathname, linkname, LINK_BUF);
  691.         if (linklen < 0)
  692.           {
  693.         fflush (stdout);
  694.         error (0, "%s", pathname);
  695.         exit_status = 1;
  696.         free (linkname);
  697.         break;
  698.           }
  699.         linkname[linklen] = '\0';
  700.         fprintf (fp, segment->text, linkname);
  701.         free (linkname);
  702.       }
  703. #endif                /* S_ISLNK */
  704.       break;
  705.     case 'm':        /* mode as octal number (perms only) */
  706.       fprintf (fp, segment->text, stat_buf->st_mode & 07777);
  707.       break;
  708.     case 'n':        /* number of links */
  709.       fprintf (fp, segment->text, stat_buf->st_nlink);
  710.       break;
  711.     case 'p':        /* pathname */
  712.       fprintf (fp, segment->text, pathname);
  713.       break;
  714.     case 'P':        /* pathname with ARGV element stripped */
  715.       if (curdepth)
  716.         {
  717.           cp = pathname + path_length;
  718.           if (*cp == '/')
  719.         /* Move past the slash between the ARGV element
  720.            and the rest of the pathname.  But if the ARGV element
  721.            ends in a slash, we didn't add another, so we've
  722.            already skipped past it.  */
  723.         cp++;
  724.           fprintf (fp, segment->text, cp);
  725.         }
  726.       break;
  727.     case 's':        /* size in bytes */
  728.       fprintf (fp, segment->text, stat_buf->st_size);
  729.       break;
  730.     case 't':        /* mtime in `ctime' format */
  731.       cp = ctime (&stat_buf->st_mtime);
  732.       cp[24] = '\0';
  733.       fprintf (fp, segment->text, cp);
  734.       break;
  735.     case 'u':        /* user name */
  736.       {
  737.         struct passwd *p;
  738.  
  739.         p = getpwuid (stat_buf->st_uid);
  740.         if (p)
  741.           {
  742.         segment->text[segment->text_len] = 's';
  743.         fprintf (fp, segment->text, p->pw_name);
  744.         break;
  745.           }
  746.         /* else fallthru */
  747.       }
  748.     case 'U':        /* UID number */
  749.       segment->text[segment->text_len] = 'u';
  750.       fprintf (fp, segment->text, stat_buf->st_uid);
  751.       break;
  752.     }
  753.     }
  754.   return (true);
  755. }
  756.  
  757. boolean
  758. pred_fstype (pathname, stat_buf, pred_ptr)
  759.      char *pathname;
  760.      struct stat *stat_buf;
  761.      struct predicate *pred_ptr;
  762. {
  763.   if (strcmp (filesystem_type (pathname, stat_buf), pred_ptr->args.str) == 0)
  764.     return (true);
  765.   return (false);
  766. }
  767.  
  768. boolean
  769. pred_gid (pathname, stat_buf, pred_ptr)
  770.      char *pathname;
  771.      struct stat *stat_buf;
  772.      struct predicate *pred_ptr;
  773. {
  774.   switch (pred_ptr->args.info.kind)
  775.     {
  776.     case COMP_GT:
  777.       if (stat_buf->st_gid > pred_ptr->args.info.l_val)
  778.     return (true);
  779.       break;
  780.     case COMP_LT:
  781.       if (stat_buf->st_gid < pred_ptr->args.info.l_val)
  782.     return (true);
  783.       break;
  784.     case COMP_EQ:
  785.       if (stat_buf->st_gid == pred_ptr->args.info.l_val)
  786.     return (true);
  787.       break;
  788.     }
  789.   return (false);
  790. }
  791.  
  792. boolean
  793. pred_group (pathname, stat_buf, pred_ptr)
  794.      char *pathname;
  795.      struct stat *stat_buf;
  796.      struct predicate *pred_ptr;
  797. {
  798.   if (pred_ptr->args.gid == stat_buf->st_gid)
  799.     return (true);
  800.   else
  801.     return (false);
  802. }
  803.  
  804. boolean
  805. pred_ilname (pathname, stat_buf, pred_ptr)
  806.      char *pathname;
  807.      struct stat *stat_buf;
  808.      struct predicate *pred_ptr;
  809. {
  810.   return insert_lname (pathname, stat_buf, pred_ptr, true);
  811. }
  812.  
  813. boolean
  814. pred_iname (pathname, stat_buf, pred_ptr)
  815.      char *pathname;
  816.      struct stat *stat_buf;
  817.      struct predicate *pred_ptr;
  818. {
  819.   char *base;
  820.  
  821.   base = basename (pathname);
  822.   if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD | FNM_CASEFOLD) == 0)
  823.     return (true);
  824.   return (false);
  825. }
  826.  
  827. boolean
  828. pred_inum (pathname, stat_buf, pred_ptr)
  829.      char *pathname;
  830.      struct stat *stat_buf;
  831.      struct predicate *pred_ptr;
  832. {
  833.   switch (pred_ptr->args.info.kind)
  834.     {
  835.     case COMP_GT:
  836.       if (stat_buf->st_ino > pred_ptr->args.info.l_val)
  837.     return (true);
  838.       break;
  839.     case COMP_LT:
  840.       if (stat_buf->st_ino < pred_ptr->args.info.l_val)
  841.     return (true);
  842.       break;
  843.     case COMP_EQ:
  844.       if (stat_buf->st_ino == pred_ptr->args.info.l_val)
  845.     return (true);
  846.       break;
  847.     }
  848.   return (false);
  849. }
  850.  
  851. boolean
  852. pred_ipath (pathname, stat_buf, pred_ptr)
  853.      char *pathname;
  854.      struct stat *stat_buf;
  855.      struct predicate *pred_ptr;
  856. {
  857.   if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
  858.     return (true);
  859.   return (false);
  860. }
  861.  
  862. boolean
  863. pred_links (pathname, stat_buf, pred_ptr)
  864.      char *pathname;
  865.      struct stat *stat_buf;
  866.      struct predicate *pred_ptr;
  867. {
  868.   switch (pred_ptr->args.info.kind)
  869.     {
  870.     case COMP_GT:
  871.       if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
  872.     return (true);
  873.       break;
  874.     case COMP_LT:
  875.       if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
  876.     return (true);
  877.       break;
  878.     case COMP_EQ:
  879.       if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
  880.     return (true);
  881.       break;
  882.     }
  883.   return (false);
  884. }
  885.  
  886. boolean
  887. pred_lname (pathname, stat_buf, pred_ptr)
  888.      char *pathname;
  889.      struct stat *stat_buf;
  890.      struct predicate *pred_ptr;
  891. {
  892.   return insert_lname (pathname, stat_buf, pred_ptr, false);
  893. }
  894.  
  895. static boolean
  896. insert_lname (pathname, stat_buf, pred_ptr, ignore_case)
  897.      char *pathname;
  898.      struct stat *stat_buf;
  899.      struct predicate *pred_ptr;
  900.      boolean ignore_case;
  901. {
  902.   boolean ret = false;
  903. #ifdef S_ISLNK
  904.   int linklen;
  905.   char *linkname;
  906.  
  907.   if (S_ISLNK (stat_buf->st_mode))
  908.     {
  909.       linkname = (char *) xmalloc (LINK_BUF + 1);
  910.       linklen = readlink (pathname, linkname, LINK_BUF);
  911.       if (linklen < 0)
  912.     {
  913.       fflush (stdout);
  914.       error (0, "can't read link %s", pathname);
  915.     }
  916.       else
  917.     {
  918.       linkname[linklen] = '\0';
  919.       if (fnmatch (pred_ptr->args.str, linkname,
  920.                ignore_case ? FNM_CASEFOLD : 0) == 0)
  921.         ret = true;
  922.     }
  923.       free (linkname);
  924.     }
  925. #endif /* S_ISLNK */
  926.   return (ret);
  927. }
  928.  
  929. boolean
  930. pred_ls (pathname, stat_buf, pred_ptr)
  931.      char *pathname;
  932.      struct stat *stat_buf;
  933.      struct predicate *pred_ptr;
  934. {
  935.   list_file (pathname, stat_buf);
  936.   return (true);
  937. }
  938.  
  939. boolean
  940. pred_mmin (pathname, stat_buf, pred_ptr)
  941.      char *pathname;
  942.      struct stat *stat_buf;
  943.      struct predicate *pred_ptr;
  944. {
  945.   switch (pred_ptr->args.info.kind)
  946.     {
  947.     case COMP_GT:
  948.       if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
  949.     return (true);
  950.       break;
  951.     case COMP_LT:
  952.       if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
  953.     return (true);
  954.       break;
  955.     case COMP_EQ:
  956.       if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
  957.       && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val + 60))
  958.     return (true);
  959.       break;
  960.     }
  961.   return (false);
  962. }
  963.  
  964. boolean
  965. pred_mtime (pathname, stat_buf, pred_ptr)
  966.      char *pathname;
  967.      struct stat *stat_buf;
  968.      struct predicate *pred_ptr;
  969. {
  970.   switch (pred_ptr->args.info.kind)
  971.     {
  972.     case COMP_GT:
  973.       if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
  974.     return (true);
  975.       break;
  976.     case COMP_LT:
  977.       if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
  978.     return (true);
  979.       break;
  980.     case COMP_EQ:
  981.       if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
  982.       && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val
  983.           + DAYSECS))
  984.     return (true);
  985.       break;
  986.     }
  987.   return (false);
  988. }
  989.  
  990. boolean
  991. pred_name (pathname, stat_buf, pred_ptr)
  992.      char *pathname;
  993.      struct stat *stat_buf;
  994.      struct predicate *pred_ptr;
  995. {
  996.   char *base;
  997.  
  998.   base = basename (pathname);
  999.   if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD) == 0)
  1000.     return (true);
  1001.   return (false);
  1002. }
  1003.  
  1004. boolean
  1005. pred_negate (pathname, stat_buf, pred_ptr)
  1006.      char *pathname;
  1007.      struct stat *stat_buf;
  1008.      struct predicate *pred_ptr;
  1009. {
  1010.   /* Check whether we need a stat here. */
  1011.   if (pred_ptr->need_stat)
  1012.     {
  1013.       if (!have_stat && (*xstat) (pathname, stat_buf) != 0)
  1014.     {
  1015.       fflush (stdout);
  1016.       error (0, errno, "%s", pathname);
  1017.       exit_status = 1;
  1018.       return (false);
  1019.     }
  1020.       have_stat = true;
  1021.     }
  1022.   return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
  1023.                           pred_ptr->pred_right));
  1024. }
  1025.  
  1026. boolean
  1027. pred_newer (pathname, stat_buf, pred_ptr)
  1028.      char *pathname;
  1029.      struct stat *stat_buf;
  1030.      struct predicate *pred_ptr;
  1031. {
  1032.   if (stat_buf->st_mtime > pred_ptr->args.time)
  1033.     return (true);
  1034.   return (false);
  1035. }
  1036.  
  1037. boolean
  1038. pred_nogroup (pathname, stat_buf, pred_ptr)
  1039.      char *pathname;
  1040.      struct stat *stat_buf;
  1041.      struct predicate *pred_ptr;
  1042. {
  1043. #ifdef CACHE_IDS
  1044.   extern char *gid_unused;
  1045.  
  1046.   return gid_unused[(unsigned) stat_buf->st_gid];
  1047. #else
  1048.   return getgrgid (stat_buf->st_gid) == NULL;
  1049. #endif
  1050. }
  1051.  
  1052. boolean
  1053. pred_nouser (pathname, stat_buf, pred_ptr)
  1054.      char *pathname;
  1055.      struct stat *stat_buf;
  1056.      struct predicate *pred_ptr;
  1057. {
  1058. #ifdef CACHE_IDS
  1059.   extern char *uid_unused;
  1060.  
  1061.   return uid_unused[(unsigned) stat_buf->st_uid];
  1062. #else
  1063.   return getpwuid (stat_buf->st_uid) == NULL;
  1064. #endif
  1065. }
  1066.  
  1067. boolean
  1068. pred_ok (pathname, stat_buf, pred_ptr)
  1069.      char *pathname;
  1070.      struct stat *stat_buf;
  1071.      struct predicate *pred_ptr;
  1072. {
  1073.   int i, yes;
  1074.   
  1075.   fflush (stdout);
  1076.   fprintf (stderr, "< %s ... %s > ? ",
  1077.        pred_ptr->args.exec_vec.vec[0], pathname);
  1078.   fflush (stderr);
  1079.   i = getchar ();
  1080.   yes = (i == 'y' || i == 'Y');
  1081.   while (i != EOF && i != '\n')
  1082.     i = getchar ();
  1083.   if (!yes)
  1084.     return (false);
  1085.   return pred_exec (pathname, stat_buf, pred_ptr);
  1086. }
  1087.  
  1088. boolean
  1089. pred_open (pathname, stat_buf, pred_ptr)
  1090.      char *pathname;
  1091.      struct stat *stat_buf;
  1092.      struct predicate *pred_ptr;
  1093. {
  1094.   return (true);
  1095. }
  1096.  
  1097. boolean
  1098. pred_or (pathname, stat_buf, pred_ptr)
  1099.      char *pathname;
  1100.      struct stat *stat_buf;
  1101.      struct predicate *pred_ptr;
  1102. {
  1103.   if (pred_ptr->pred_left == NULL
  1104.       || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
  1105.                          pred_ptr->pred_left))
  1106.     {
  1107.       /* Check whether we need a stat here. */
  1108.       if (pred_ptr->need_stat)
  1109.     {
  1110.       if (!have_stat && (*xstat) (pathname, stat_buf) != 0)
  1111.         {
  1112.           fflush (stdout);
  1113.           error (0, errno, "%s", pathname);
  1114.           exit_status = 1;
  1115.           return (false);
  1116.         }
  1117.       have_stat = true;
  1118.     }
  1119.       return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
  1120.                           pred_ptr->pred_right));
  1121.     }
  1122.   else
  1123.     return (true);
  1124. }
  1125.  
  1126. boolean
  1127. pred_path (pathname, stat_buf, pred_ptr)
  1128.      char *pathname;
  1129.      struct stat *stat_buf;
  1130.      struct predicate *pred_ptr;
  1131. {
  1132.   if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
  1133.     return (true);
  1134.   return (false);
  1135. }
  1136.  
  1137. boolean
  1138. pred_perm (pathname, stat_buf, pred_ptr)
  1139.      char *pathname;
  1140.      struct stat *stat_buf;
  1141.      struct predicate *pred_ptr;
  1142. {
  1143.   if (pred_ptr->args.perm & 010000)
  1144.     {
  1145.       /* Magic flag set in parse_perm:
  1146.      true if at least the given bits are set. */
  1147.       if ((stat_buf->st_mode & 07777 & pred_ptr->args.perm)
  1148.       == (pred_ptr->args.perm & 07777))
  1149.     return (true);
  1150.     }
  1151.   else if (pred_ptr->args.perm & 020000)
  1152.     {
  1153.       /* Magic flag set in parse_perm:
  1154.      true if any of the given bits are set. */
  1155.       if ((stat_buf->st_mode & 07777) & pred_ptr->args.perm)
  1156.     return (true);
  1157.     }
  1158.   else
  1159.     {
  1160.       /* True if exactly the given bits are set. */
  1161.       if ((stat_buf->st_mode & 07777) == pred_ptr->args.perm)
  1162.     return (true);
  1163.     }
  1164.   return (false);
  1165. }
  1166.  
  1167. boolean
  1168. pred_print (pathname, stat_buf, pred_ptr)
  1169.      char *pathname;
  1170.      struct stat *stat_buf;
  1171.      struct predicate *pred_ptr;
  1172. {
  1173.   puts (pathname);
  1174.   return (true);
  1175. }
  1176.  
  1177. boolean
  1178. pred_print0 (pathname, stat_buf, pred_ptr)
  1179.      char *pathname;
  1180.      struct stat *stat_buf;
  1181.      struct predicate *pred_ptr;
  1182. {
  1183.   fputs (pathname, stdout);
  1184.   putc (0, stdout);
  1185.   return (true);
  1186. }
  1187.  
  1188. boolean
  1189. pred_prune (pathname, stat_buf, pred_ptr)
  1190.      char *pathname;
  1191.      struct stat *stat_buf;
  1192.      struct predicate *pred_ptr;
  1193. {
  1194.   stop_at_current_level = true;
  1195.   return (do_dir_first);    /* This is what SunOS find seems to do. */
  1196. }
  1197.  
  1198. boolean
  1199. pred_regex (pathname, stat_buf, pred_ptr)
  1200.      char *pathname;
  1201.      struct stat *stat_buf;
  1202.      struct predicate *pred_ptr;
  1203. {
  1204.   if (re_match (pred_ptr->args.regex, pathname, strlen (pathname), 0,
  1205.         (struct re_registers *) NULL) != -1)
  1206.     return (true);
  1207.   return (false);
  1208. }
  1209.  
  1210. boolean
  1211. pred_size (pathname, stat_buf, pred_ptr)
  1212.      char *pathname;
  1213.      struct stat *stat_buf;
  1214.      struct predicate *pred_ptr;
  1215. {
  1216.   unsigned long f_val;
  1217.  
  1218.   f_val = (stat_buf->st_size + pred_ptr->args.size.blocksize - 1)
  1219.     / pred_ptr->args.size.blocksize;
  1220.   switch (pred_ptr->args.size.kind)
  1221.     {
  1222.     case COMP_GT:
  1223.       if (f_val > pred_ptr->args.size.size)
  1224.     return (true);
  1225.       break;
  1226.     case COMP_LT:
  1227.       if (f_val < pred_ptr->args.size.size)
  1228.     return (true);
  1229.       break;
  1230.     case COMP_EQ:
  1231.       if (f_val == pred_ptr->args.size.size)
  1232.     return (true);
  1233.       break;
  1234.     }
  1235.   return (false);
  1236. }
  1237.  
  1238. boolean
  1239. pred_true (pathname, stat_buf, pred_ptr)
  1240.      char *pathname;
  1241.      struct stat *stat_buf;
  1242.      struct predicate *pred_ptr;
  1243. {
  1244.   return (true);
  1245. }
  1246.  
  1247. boolean
  1248. pred_type (pathname, stat_buf, pred_ptr)
  1249.      char *pathname;
  1250.      struct stat *stat_buf;
  1251.      struct predicate *pred_ptr;
  1252. {
  1253.   unsigned long mode = stat_buf->st_mode;
  1254.   unsigned long type = pred_ptr->args.type;
  1255.  
  1256. #ifndef S_IFMT
  1257.   /* POSIX system; check `mode' the slow way. */
  1258.   if ((S_ISBLK (mode) && type == S_IFBLK)
  1259.       || (S_ISCHR (mode) && type == S_IFCHR)
  1260.       || (S_ISDIR (mode) && type == S_IFDIR)
  1261.       || (S_ISREG (mode) && type == S_IFREG)
  1262. #ifdef S_IFLNK
  1263.       || (S_ISLNK (mode) && type == S_IFLNK)
  1264. #endif
  1265. #ifdef S_IFIFO
  1266.       || (S_ISFIFO (mode) && type == S_IFIFO)
  1267. #endif
  1268. #ifdef S_IFSOCK
  1269.       || (S_ISSOCK (mode) && type == S_IFSOCK)
  1270. #endif
  1271.       )
  1272. #else /* S_IFMT */
  1273.   /* Unix system; check `mode' the fast way. */
  1274.   if ((mode & S_IFMT) == type)
  1275. #endif /* S_IFMT */
  1276.     return (true);
  1277.   else
  1278.     return (false);
  1279. }
  1280.  
  1281. boolean
  1282. pred_uid (pathname, stat_buf, pred_ptr)
  1283.      char *pathname;
  1284.      struct stat *stat_buf;
  1285.      struct predicate *pred_ptr;
  1286. {
  1287.   switch (pred_ptr->args.info.kind)
  1288.     {
  1289.     case COMP_GT:
  1290.       if (stat_buf->st_uid > pred_ptr->args.info.l_val)
  1291.     return (true);
  1292.       break;
  1293.     case COMP_LT:
  1294.       if (stat_buf->st_uid < pred_ptr->args.info.l_val)
  1295.     return (true);
  1296.       break;
  1297.     case COMP_EQ:
  1298.       if (stat_buf->st_uid == pred_ptr->args.info.l_val)
  1299.     return (true);
  1300.       break;
  1301.     }
  1302.   return (false);
  1303. }
  1304.  
  1305. boolean
  1306. pred_used (pathname, stat_buf, pred_ptr)
  1307.      char *pathname;
  1308.      struct stat *stat_buf;
  1309.      struct predicate *pred_ptr;
  1310. {
  1311.   time_t delta;
  1312.  
  1313.   delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
  1314.   switch (pred_ptr->args.info.kind)
  1315.     {
  1316.     case COMP_GT:
  1317.       if (delta > (time_t) pred_ptr->args.info.l_val)
  1318.     return (true);
  1319.       break;
  1320.     case COMP_LT:
  1321.       if (delta < (time_t) pred_ptr->args.info.l_val)
  1322.     return (true);
  1323.       break;
  1324.     case COMP_EQ:
  1325.       if ((delta >= (time_t) pred_ptr->args.info.l_val)
  1326.       && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
  1327.     return (true);
  1328.       break;
  1329.     }
  1330.   return (false);
  1331. }
  1332.  
  1333. boolean
  1334. pred_user (pathname, stat_buf, pred_ptr)
  1335.      char *pathname;
  1336.      struct stat *stat_buf;
  1337.      struct predicate *pred_ptr;
  1338. {
  1339.   if (pred_ptr->args.uid == stat_buf->st_uid)
  1340.     return (true);
  1341.   else
  1342.     return (false);
  1343. }
  1344.  
  1345. boolean
  1346. pred_xtype (pathname, stat_buf, pred_ptr)
  1347.      char *pathname;
  1348.      struct stat *stat_buf;
  1349.      struct predicate *pred_ptr;
  1350. {
  1351.   struct stat sbuf;
  1352.   int (*ystat) ();
  1353.  
  1354.   ystat = xstat == lstat ? stat : lstat;
  1355.   if ((*ystat) (pathname, &sbuf) != 0)
  1356.     {
  1357.       if (ystat == stat && errno == ENOENT)
  1358.     /* Mimic behavior of ls -lL. */
  1359.     return (pred_type (pathname, stat_buf, pred_ptr));
  1360.       fflush (stdout);
  1361.       error (0, errno, "%s", pathname);
  1362.       exit_status = 1;
  1363.       return (false);
  1364.     }
  1365.   return (pred_type (pathname, &sbuf, pred_ptr));
  1366. }
  1367.  
  1368. /*  1) fork to get a child; parent remembers the child pid
  1369.     2) child execs the command requested
  1370.     3) parent waits for child; checks for proper pid of child
  1371.  
  1372.     Possible returns:
  1373.  
  1374.     ret        errno    status(h)   status(l)
  1375.  
  1376.     pid        x    signal#        0177    stopped
  1377.     pid        x    exit arg    0        term by _exit
  1378.     pid        x    0        signal #    term by signal
  1379.     -1        EINTR                parent got signal
  1380.     -1        other                some other kind of error
  1381.  
  1382.     Return true only if the pid matches, status(l) is
  1383.     zero, and the exit arg (status high) is 0.
  1384.     Otherwise return false, possibly printing an error message. */
  1385.  
  1386. boolean
  1387. launch (pred_ptr)
  1388.      struct predicate *pred_ptr;
  1389. {
  1390.   int status, wait_ret, child_pid;
  1391.   struct exec_val *execp;    /* Pointer for efficiency. */
  1392.  
  1393.   execp = &pred_ptr->args.exec_vec;
  1394.  
  1395.   /* Make sure output of command doesn't get mixed with find output. */
  1396.   fflush (stdout);
  1397.   fflush (stderr);
  1398.  
  1399.   child_pid = vfork ();
  1400.   if (child_pid == -1)
  1401.     error (1, errno, "cannot fork");
  1402.   if (child_pid == 0)
  1403.     {
  1404.       /* We be the child. */
  1405.       execvp (execp->vec[0], execp->vec);
  1406.       error (0, errno, "%s", execp->vec[0]);
  1407.       _exit (1);
  1408.     }
  1409.  
  1410.   wait_ret = wait (&status);
  1411.   if (wait_ret == -1)
  1412.     {
  1413.       fflush (stdout);
  1414.       error (0, errno, "error waiting for %s", execp->vec[0]);
  1415.       exit_status = 1;
  1416.       return (false);
  1417.     }
  1418.   if (wait_ret != child_pid)
  1419.     {
  1420.       fflush (stdout);
  1421.       error (0, 0, "wait got pid %d, expected pid %d", wait_ret, child_pid);
  1422.       exit_status = 1;
  1423.       return (false);
  1424.     }
  1425.   if (WIFSTOPPED (status))
  1426.     {
  1427.       fflush (stdout);
  1428.       error (0, 0, "%s stopped by signal %d", 
  1429.          execp->vec[0], WSTOPSIG (status));
  1430.       exit_status = 1;
  1431.       return (false);
  1432.     }
  1433.   if (WIFSIGNALED (status))
  1434.     {
  1435.       fflush (stdout);
  1436.       error (0, 0, "%s terminated by signal %d",
  1437.          execp->vec[0], WTERMSIG (status));
  1438.       exit_status = 1;
  1439.       return (false);
  1440.     }
  1441.   return (!WEXITSTATUS (status));
  1442. }
  1443.  
  1444. /* Return a static string formatting the time WHEN according to the
  1445.    strftime format character KIND.  */
  1446.  
  1447. char *
  1448. format_date (when, kind)
  1449.      time_t when;
  1450.      int kind;
  1451. {
  1452.   static char fmt[3];
  1453.   static char buf[64];        /* More than enough space. */
  1454.  
  1455.   if (kind == '@')
  1456.     {
  1457.       sprintf (buf, "%ld", when);
  1458.       return (buf);
  1459.     }
  1460.   else
  1461.     {
  1462.       fmt[0] = '%';
  1463.       fmt[1] = kind;
  1464.       fmt[2] = '\0';
  1465.       if (strftime (buf, sizeof (buf), fmt, localtime (&when)))
  1466.     return (buf);
  1467.     }
  1468.   return "";
  1469. }
  1470.  
  1471. #ifdef    DEBUG
  1472. /* Return a pointer to the string representation of 
  1473.    the predicate function PRED_FUNC. */
  1474.  
  1475. char *
  1476. find_pred_name (pred_func)
  1477.      PFB pred_func;
  1478. {
  1479.   int i;
  1480.  
  1481.   for (i = 0; pred_table[i].pred_func != 0; i++)
  1482.     if (pred_table[i].pred_func == pred_func)
  1483.       break;
  1484.   return (pred_table[i].pred_name);
  1485. }
  1486.  
  1487. char *
  1488. type_name (type)
  1489.      short type;
  1490. {
  1491.   int i;
  1492.  
  1493.   for (i = 0; type_table[i].type != (short) -1; i++)
  1494.     if (type_table[i].type == type)
  1495.       break;
  1496.   return (type_table[i].type_name);
  1497. }
  1498.  
  1499. char *
  1500. prec_name (prec)
  1501.      short prec;
  1502. {
  1503.   int i;
  1504.  
  1505.   for (i = 0; prec_table[i].prec != (short) -1; i++)
  1506.     if (prec_table[i].prec == prec)
  1507.       break;
  1508.   return (prec_table[i].prec_name);
  1509. }
  1510.  
  1511. /* Walk the expression tree NODE to stdout.
  1512.    INDENT is the number of levels to indent the left margin. */
  1513.  
  1514. void
  1515. print_tree (node, indent)
  1516.      struct predicate *node;
  1517.      int indent;
  1518. {
  1519.   int i;
  1520.  
  1521.   if (node == NULL)
  1522.     return;
  1523.   for (i = 0; i < indent; i++)
  1524.     printf ("    ");
  1525.   printf ("pred = %s type = %s prec = %s addr = %x\n",
  1526.       find_pred_name (node->pred_func),
  1527.       type_name (node->p_type), prec_name (node->p_prec), node);
  1528.   for (i = 0; i < indent; i++)
  1529.     printf ("    ");
  1530.   printf ("left:\n");
  1531.   print_tree (node->pred_left, indent + 1);
  1532.   for (i = 0; i < indent; i++)
  1533.     printf ("    ");
  1534.   printf ("right:\n");
  1535.   print_tree (node->pred_right, indent + 1);
  1536. }
  1537.  
  1538. /* Copy STR into BUF and trim blanks from the end of BUF.
  1539.    Return BUF. */
  1540.  
  1541. char *
  1542. blank_rtrim (str, buf)
  1543.      char *str;
  1544.      char *buf;
  1545. {
  1546.   int i;
  1547.  
  1548.   if (str == NULL)
  1549.     return (NULL);
  1550.   strcpy (buf, str);
  1551.   i = strlen (buf) - 1;
  1552.   while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
  1553.     i--;
  1554.   buf[++i] = '\0';
  1555.   return (buf);
  1556. }
  1557.  
  1558. /* Print out the predicate list starting at NODE. */
  1559.  
  1560. void
  1561. print_list (node)
  1562.      struct predicate *node;
  1563. {
  1564.   struct predicate *cur;
  1565.   char name[256];
  1566.  
  1567.   cur = node;
  1568.   while (cur != NULL)
  1569.     {
  1570.       printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
  1571.       cur = cur->pred_next;
  1572.     }
  1573.   printf ("\n");
  1574. }
  1575. #endif    /* DEBUG */
  1576.