home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / f / find12as.zip / PRED.C < prev    next >
C/C++ Source or Header  |  1992-02-22  |  19KB  |  797 lines

  1. /* The Predicates and associated routines for Find.
  2.    Copyright (C) 1987, 1990 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 1, 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. /* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  19.    This port is also distributed under the terms of the
  20.    GNU General Public License as published by the
  21.    Free Software Foundation.
  22.  
  23.    Please note that this file is not identical to the
  24.    original GNU release, you should have received this
  25.    code as patch to the official release.
  26.  
  27.    $Header: e:/gnu/find/RCS/pred.c 1.2.0.3 90/09/23 16:09:50 tho Exp $
  28.  */
  29.  
  30. #include <stdio.h>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <pwd.h>
  34. #ifndef MSDOS
  35. struct passwd *getpwuid ();
  36. #include <grp.h>
  37. struct group *getgrgid ();
  38. #endif /* not MSDOS */
  39. #ifndef USG
  40. #include <strings.h>
  41. #else
  42. #include <string.h>
  43. #define index strchr
  44. #define rindex strrchr
  45. #endif
  46. #include "defs.h"
  47.  
  48. #ifdef MSDOS
  49.  
  50. #include <time.h>
  51. #include <process.h>
  52.  
  53. extern void error (int status, int errnum, char *message, ...);
  54. extern char *basename (char *fname);
  55. extern char *filesystem_type (struct stat *statp);
  56. extern void list_file (char *name, struct stat *statp);
  57. extern int glob_match (char *pattern, char *text, int dot_special);
  58.  
  59. static char launch (struct pred_struct *pred_ptr);
  60.  
  61. #else /* not MSDOS */
  62.  
  63. int fork ();
  64. int wait ();
  65.  
  66. boolean pred_and ();
  67. boolean pred_atime ();
  68. boolean pred_close ();
  69. boolean pred_ctime ();
  70. /* no pred_depth */
  71. boolean pred_exec ();
  72. boolean pred_fstype ();
  73. /* no pred_fulldays */
  74. boolean pred_group ();
  75. boolean pred_inum ();
  76. boolean pred_links ();
  77. boolean pred_ls ();
  78. boolean pred_mtime ();
  79. boolean pred_name ();
  80. boolean pred_negate ();
  81. boolean pred_newer ();
  82. boolean pred_nogroup ();
  83. boolean pred_nouser ();
  84. boolean pred_ok ();
  85. boolean pred_open ();
  86. boolean pred_or ();
  87. boolean pred_perm ();
  88. boolean pred_permmask ();
  89. boolean pred_print ();
  90. boolean pred_prune ();
  91. boolean pred_regex ();
  92. boolean pred_size ();
  93. boolean pred_type ();
  94. boolean pred_user ();
  95. /* no pred_version */
  96. /* no pred_xdev */
  97.  
  98. boolean launch ();
  99. char *basename ();
  100. char *filesystem_type ();
  101. void list_file ();
  102.  
  103. #endif /* not MSDOS */
  104.  
  105. #ifdef    DEBUG
  106. struct pred_assoc
  107. {
  108. #ifdef MSDOS
  109.   PRED_FCT pred_func;
  110. #else
  111.   PFB pred_func;
  112. #endif
  113.   char *pred_name;
  114. };
  115.  
  116. struct pred_assoc pred_table[] =
  117. {
  118.   {pred_and, "and     "},
  119.   {pred_atime, "atime   "},
  120.   {pred_close, ")       "},
  121.   {pred_ctime, "ctime   "},
  122.   {pred_exec, "exec    "},
  123.   {pred_fstype, "fstype  "},
  124.   {pred_group, "group   "},
  125.   {pred_inum, "inum    "},
  126.   {pred_links, "links   "},
  127.   {pred_ls, "ls      "},
  128.   {pred_mtime, "mtime   "},
  129.   {pred_name, "name    "},
  130.   {pred_negate, "!       "},
  131.   {pred_newer, "newer   "},
  132.   {pred_nogroup, "nogroup "},
  133.   {pred_nouser, "nouser  "},
  134.   {pred_ok, "ok      "},
  135.   {pred_open, "(       "},
  136.   {pred_or, "or      "},
  137.   {pred_perm, "perm    "},
  138.   {pred_permmask, "permmask"},
  139.   {pred_print, "print   "},
  140.   {pred_prune, "prune   "},
  141.   {pred_regex, "regex   "},
  142.   {pred_size, "size    "},
  143.   {pred_type, "type    "},
  144.   {pred_user, "user    "},
  145.   {0, "none    "}
  146. };
  147.  
  148. struct op_assoc
  149. {
  150.   short type;
  151.   char *type_name;
  152. };
  153.  
  154. struct op_assoc type_table[] =
  155. {
  156.   {NO_TYPE, "no_type    "},
  157.   {VICTIM_TYPE, "victim_type    "},
  158.   {UNI_OP, "uni_op    "},
  159.   {BI_OP, "bi_op    "},
  160.   {OPEN_PAREN, "open_paren    "},
  161.   {CLOSE_PAREN, "close_paren    "},
  162.   {-1, "unknown    "}
  163. };
  164.  
  165. struct prec_assoc
  166. {
  167.   short prec;
  168.   char *prec_name;
  169. };
  170.  
  171. struct prec_assoc prec_table[] =
  172. {
  173.   {NO_PREC, "no_prec     "},
  174.   {OR_PREC, "or_prec     "},
  175.   {AND_PREC, "and_prec    "},
  176.   {NEGATE_PREC, "negate_prec "},
  177.   {MAX_PREC, "max_prec    "},
  178.   {-1, "unknown    "}
  179. };
  180. #endif    /* DEBUG */
  181.  
  182. /* Predicate processing routines.
  183.  
  184.    PATHNAME is the full pathname of the file being checked.
  185.    *STAT_BUF contains information about PATHNAME.
  186.    *PRED_PTR contains information for applying the predicate.
  187.  
  188.    Return true if the file passes this predicate, false if not. */
  189.  
  190. boolean
  191. pred_and (pathname, stat_buf, pred_ptr)
  192.      char *pathname;
  193.      struct stat *stat_buf;
  194.      struct pred_struct *pred_ptr;
  195. {
  196.   if ((*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
  197.                      pred_ptr->pred_left))
  198.     return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
  199.                         pred_ptr->pred_right));
  200.   else
  201.     return (false);
  202. }
  203.  
  204. boolean
  205. pred_atime (pathname, stat_buf, pred_ptr)
  206.      char *pathname;
  207.      struct stat *stat_buf;
  208.      struct pred_struct *pred_ptr;
  209. {
  210. #ifdef    DEBUG
  211.   printf ("pred_atime: checking %s %ld %s", pathname, stat_buf->st_atime,
  212.       ctime (&stat_buf->st_atime));
  213. #endif    /* DEBUG */
  214.   switch (pred_ptr->args.info.kind)
  215.     {
  216.     case COMP_GT:
  217.       if (stat_buf->st_atime > pred_ptr->args.info.l_val)
  218.     return (true);
  219.       break;
  220.     case COMP_LT:
  221.       if (stat_buf->st_atime < pred_ptr->args.info.l_val)
  222.     return (true);
  223.       break;
  224.     case COMP_EQ:
  225.       if ((stat_buf->st_atime >= pred_ptr->args.info.l_val)
  226.       && (stat_buf->st_atime < pred_ptr->args.info.l_val
  227.           + DAYSECS))
  228.     return (true);
  229.       break;
  230.     }
  231.   return (false);
  232. }
  233.  
  234. boolean
  235. pred_close (pathname, stat_buf, pred_ptr)
  236.      char *pathname;
  237.      struct stat *stat_buf;
  238.      struct pred_struct *pred_ptr;
  239. {
  240.   error (0, 0, "oops -- got into pred_close!");
  241.   return (true);
  242. }
  243.  
  244. boolean
  245. pred_ctime (pathname, stat_buf, pred_ptr)
  246.      char *pathname;
  247.      struct stat *stat_buf;
  248.      struct pred_struct *pred_ptr;
  249. {
  250.   switch (pred_ptr->args.info.kind)
  251.     {
  252.     case COMP_GT:
  253.       if (stat_buf->st_ctime > pred_ptr->args.info.l_val)
  254.     return (true);
  255.       break;
  256.     case COMP_LT:
  257.       if (stat_buf->st_ctime < pred_ptr->args.info.l_val)
  258.     return (true);
  259.       break;
  260.     case COMP_EQ:
  261.       if ((stat_buf->st_ctime >= pred_ptr->args.info.l_val)
  262.       && (stat_buf->st_ctime < pred_ptr->args.info.l_val
  263.           + DAYSECS))
  264.     return (true);
  265.       break;
  266.     }
  267.   return (false);
  268. }
  269.  
  270. boolean
  271. pred_exec (pathname, stat_buf, pred_ptr)
  272.      char *pathname;
  273.      struct stat *stat_buf;
  274.      struct pred_struct *pred_ptr;
  275. {
  276.   int i, path_pos;
  277.  
  278.   for (path_pos = 0, i = pred_ptr->args.exec_vec.path_loc[0];
  279.        i != -1;
  280.        path_pos++, i = pred_ptr->args.exec_vec.path_loc[path_pos])
  281.     pred_ptr->args.exec_vec.vec[i] = pathname;
  282.   return (launch (pred_ptr));
  283. }
  284.  
  285. boolean
  286. pred_fstype (pathname, stat_buf, pred_ptr)
  287.      char *pathname;
  288.      struct stat *stat_buf;
  289.      struct pred_struct *pred_ptr;
  290. {
  291.   char *fstype;
  292.  
  293.   fstype = filesystem_type (stat_buf);
  294.   if (fstype && strcmp (fstype, pred_ptr->args.str) == 0)
  295.     return (true);
  296.   return (false);
  297. }
  298.  
  299. boolean
  300. pred_group (pathname, stat_buf, pred_ptr)
  301.      char *pathname;
  302.      struct stat *stat_buf;
  303.      struct pred_struct *pred_ptr;
  304. {
  305.   if (pred_ptr->args.gid == stat_buf->st_gid)
  306.     return (true);
  307.   else
  308.     return (false);
  309. }
  310.  
  311. boolean
  312. pred_inum (pathname, stat_buf, pred_ptr)
  313.      char *pathname;
  314.      struct stat *stat_buf;
  315.      struct pred_struct *pred_ptr;
  316. {
  317.   switch (pred_ptr->args.info.kind)
  318.     {
  319.     case COMP_GT:
  320.       if (stat_buf->st_ino > pred_ptr->args.info.l_val)
  321.     return (true);
  322.       break;
  323.     case COMP_LT:
  324.       if (stat_buf->st_ino < pred_ptr->args.info.l_val)
  325.     return (true);
  326.       break;
  327.     case COMP_EQ:
  328.       if (stat_buf->st_ino == pred_ptr->args.info.l_val)
  329.     return (true);
  330.       break;
  331.     }
  332.   return (false);
  333. }
  334.  
  335. boolean
  336. pred_links (pathname, stat_buf, pred_ptr)
  337.      char *pathname;
  338.      struct stat *stat_buf;
  339.      struct pred_struct *pred_ptr;
  340. {
  341.   switch (pred_ptr->args.info.kind)
  342.     {
  343.     case COMP_GT:
  344.       if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
  345.     return (true);
  346.       break;
  347.     case COMP_LT:
  348.       if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
  349.     return (true);
  350.       break;
  351.     case COMP_EQ:
  352.       if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
  353.     return (true);
  354.       break;
  355.     }
  356.   return (false);
  357. }
  358.  
  359. boolean
  360. pred_ls (pathname, stat_buf, pred_ptr)
  361.      char *pathname;
  362.      struct stat *stat_buf;
  363.      struct pred_struct *pred_ptr;
  364. {
  365.   list_file (pathname, stat_buf);
  366.   return (true);
  367. }
  368.  
  369. boolean
  370. pred_mtime (pathname, stat_buf, pred_ptr)
  371.      char *pathname;
  372.      struct stat *stat_buf;
  373.      struct pred_struct *pred_ptr;
  374. {
  375.   switch (pred_ptr->args.info.kind)
  376.     {
  377.     case COMP_GT:
  378.       if (stat_buf->st_mtime > pred_ptr->args.info.l_val)
  379.     return (true);
  380.       break;
  381.     case COMP_LT:
  382.       if (stat_buf->st_mtime < pred_ptr->args.info.l_val)
  383.     return (true);
  384.       break;
  385.     case COMP_EQ:
  386.       if ((stat_buf->st_mtime >= pred_ptr->args.info.l_val)
  387.       && (stat_buf->st_mtime < pred_ptr->args.info.l_val
  388.           + DAYSECS))
  389.     return (true);
  390.       break;
  391.     }
  392.   return (false);
  393. }
  394.  
  395. boolean
  396. pred_name (pathname, stat_buf, pred_ptr)
  397.      char *pathname;
  398.      struct stat *stat_buf;
  399.      struct pred_struct *pred_ptr;
  400. {
  401.   char *just_fname;
  402.  
  403.   just_fname = basename (pathname);
  404.   if (glob_match (pred_ptr->args.str, just_fname, 1))
  405.     return (true);
  406.   return (false);
  407. }
  408.  
  409. boolean
  410. pred_negate (pathname, stat_buf, pred_ptr)
  411.      char *pathname;
  412.      struct stat *stat_buf;
  413.      struct pred_struct *pred_ptr;
  414. {
  415.   return (!(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
  416.                           pred_ptr->pred_left));
  417. }
  418.  
  419. boolean
  420. pred_newer (pathname, stat_buf, pred_ptr)
  421.      char *pathname;
  422.      struct stat *stat_buf;
  423.      struct pred_struct *pred_ptr;
  424. {
  425.   if (stat_buf->st_mtime > pred_ptr->args.time)
  426.     return (true);
  427.   return (false);
  428. }
  429.  
  430. boolean
  431. pred_nogroup (pathname, stat_buf, pred_ptr)
  432.      char *pathname;
  433.      struct stat *stat_buf;
  434.      struct pred_struct *pred_ptr;
  435. {
  436.   return getgrgid (stat_buf->st_gid) == NULL;
  437. }
  438.  
  439. boolean
  440. pred_nouser (pathname, stat_buf, pred_ptr)
  441.      char *pathname;
  442.      struct stat *stat_buf;
  443.      struct pred_struct *pred_ptr;
  444. {
  445.   return getpwuid (stat_buf->st_uid) == NULL;
  446. }
  447.  
  448. boolean
  449. pred_ok (pathname, stat_buf, pred_ptr)
  450.      char *pathname;
  451.      struct stat *stat_buf;
  452.      struct pred_struct *pred_ptr;
  453. {
  454.   int i, yes, path_pos;
  455.  
  456.   for (path_pos = 0, i = pred_ptr->args.exec_vec.path_loc[0];
  457.        i != -1;
  458.        path_pos++, i = pred_ptr->args.exec_vec.path_loc[path_pos])
  459.     pred_ptr->args.exec_vec.vec[i] = pathname;
  460.   fprintf (stderr, "< %s ... %s > ? ",
  461.        pred_ptr->args.exec_vec.vec[0], pathname);
  462.   fflush (stderr);
  463.   i = getchar ();
  464.   yes = (i == 'y' || i == 'Y');
  465.   while (i != EOF && i != '\n')
  466.     i = getchar ();
  467.   if (yes)
  468.     return (launch (pred_ptr));
  469.   else
  470.     return (false);
  471. }
  472.  
  473. boolean
  474. pred_open (pathname, stat_buf, pred_ptr)
  475.      char *pathname;
  476.      struct stat *stat_buf;
  477.      struct pred_struct *pred_ptr;
  478. {
  479.   error (0, 0, "oops -- got into pred_open!");
  480.   return (true);
  481. }
  482.  
  483. boolean
  484. pred_or (pathname, stat_buf, pred_ptr)
  485.      char *pathname;
  486.      struct stat *stat_buf;
  487.      struct pred_struct *pred_ptr;
  488. {
  489.   if (!(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
  490.                       pred_ptr->pred_left))
  491.     return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
  492.                         pred_ptr->pred_right));
  493.   else
  494.     return (true);
  495. }
  496.  
  497. boolean
  498. pred_perm (pathname, stat_buf, pred_ptr)
  499.      char *pathname;
  500.      struct stat *stat_buf;
  501.      struct pred_struct *pred_ptr;
  502. {
  503.   if (pred_ptr->args.perm & 010000)
  504.     {
  505.       /* Magic flag set in parse_perm: compare suid, sgid, sticky bits as well;
  506.      also, true if at least the given bits are set. */
  507.       if ((stat_buf->st_mode & 07777 & perm_mask & pred_ptr->args.perm)
  508.       == (pred_ptr->args.perm & 07777))
  509.     return (true);
  510.     }
  511.   else
  512.     {
  513.       if ((stat_buf->st_mode & 0777 & perm_mask) == pred_ptr->args.perm)
  514.     return (true);
  515.     }
  516.   return (false);
  517. }
  518.  
  519. boolean
  520. pred_permmask (pathname, stat_buf, pred_ptr)
  521.      char *pathname;
  522.      struct stat *stat_buf;
  523.      struct pred_struct *pred_ptr;
  524. {
  525.   perm_mask = pred_ptr->args.perm;
  526.   return (true);
  527. }
  528.  
  529. boolean
  530. pred_print (pathname, stat_buf, pred_ptr)
  531.      char *pathname;
  532.      struct stat *stat_buf;
  533.      struct pred_struct *pred_ptr;
  534. {
  535.   puts (pathname);
  536.   return (true);
  537. }
  538.  
  539. boolean
  540. pred_prune (pathname, stat_buf, pred_ptr)
  541.      char *pathname;
  542.      struct stat *stat_buf;
  543.      struct pred_struct *pred_ptr;
  544. {
  545.   stop_at_current_level = true;
  546.   return (do_dir_first);    /* This is what SunOS find seems to do. */
  547. }
  548.  
  549. boolean
  550. pred_regex (pathname, stat_buf, pred_ptr)
  551.      char *pathname;
  552.      struct stat *stat_buf;
  553.      struct pred_struct *pred_ptr;
  554. {
  555.   if (re_match (pred_ptr->args.regex, pathname, strlen (pathname), 0,
  556.         (struct re_registers *) NULL) != -1)
  557.     return (true);
  558.   return (false);
  559. }
  560.  
  561. boolean
  562. pred_size (pathname, stat_buf, pred_ptr)
  563.      char *pathname;
  564.      struct stat *stat_buf;
  565.      struct pred_struct *pred_ptr;
  566. {
  567.   unsigned long f_val;
  568.  
  569.   if (pred_ptr->args.size.block)
  570.     f_val = (stat_buf->st_size + BLKSIZE - 1) / BLKSIZE;
  571.   else
  572.     f_val = stat_buf->st_size;
  573.   switch (pred_ptr->args.size.kind)
  574.     {
  575.     case COMP_GT:
  576.       if (f_val > pred_ptr->args.size.size)
  577.     return (true);
  578.       break;
  579.     case COMP_LT:
  580.       if (f_val < pred_ptr->args.size.size)
  581.     return (true);
  582.       break;
  583.     case COMP_EQ:
  584.       if (f_val == pred_ptr->args.size.size)
  585.     return (true);
  586.       break;
  587.     }
  588.   return (false);
  589. }
  590.  
  591. boolean
  592. pred_type (pathname, stat_buf, pred_ptr)
  593.      char *pathname;
  594.      struct stat *stat_buf;
  595.      struct pred_struct *pred_ptr;
  596. {
  597.   if ((stat_buf->st_mode & S_IFMT) == pred_ptr->args.type)
  598.     return (true);
  599.   else
  600.     return (false);
  601. }
  602.  
  603. boolean
  604. pred_user (pathname, stat_buf, pred_ptr)
  605.      char *pathname;
  606.      struct stat *stat_buf;
  607.      struct pred_struct *pred_ptr;
  608. {
  609.   if (pred_ptr->args.uid == stat_buf->st_uid)
  610.     return (true);
  611.   else
  612.     return (false);
  613. }
  614.  
  615. boolean
  616. launch (pred_ptr)
  617.      struct pred_struct *pred_ptr;
  618. {
  619.   int status, wait_ret, child_pid;
  620.  
  621.   /*  1) fork to get a child; parent remembers the child pid
  622.       2) child execs the command requested
  623.       3) parent waits, with stat_loc non_zero
  624.       check for proper pid of child
  625.       Possible returns:
  626.    
  627.       ret    errno    status(h)   status(l)
  628.       pid    x    signal#        0177    stopped
  629.       pid    x    exit arg    0        term by exit or _exit
  630.       pid    x    0        signal #    term by signal
  631.       -1    EINTR                parent got signal
  632.       -1    other                some other kind of error
  633.       
  634.       Return true only if the pid matches, status(l) is
  635.       zero, and the exit arg (status high) is 0.
  636.       Otherwise return false, possibly printing an error message. */
  637.  
  638. #ifdef MSDOS
  639.  
  640.   status = spawnvp (P_WAIT, pred_ptr->args.exec_vec.vec[0],\
  641.             pred_ptr->args.exec_vec.vec);
  642.  
  643. #else /* not MSDOS */
  644.  
  645.   child_pid = fork ();
  646.   if (child_pid == -1)
  647.     error (1, errno, "cannot fork");
  648.   if (child_pid == 0)
  649.     {
  650.       /* We be the child. */
  651.       execvp (pred_ptr->args.exec_vec.vec[0], pred_ptr->args.exec_vec.vec);
  652.       error (1, errno, "%s", pred_ptr->args.exec_vec.vec[0]);
  653.     }
  654.   wait_ret = wait (&status);
  655.   if (wait_ret == -1)
  656.     {
  657.       error (0, errno, "error waiting for child process");
  658.       exit_status = 1;
  659.       return (false);
  660.     }
  661.   if (wait_ret != child_pid)
  662.     {
  663.       error (0, 0, "wait saw another child, pid %d", wait_ret);
  664.       error (0, 0, "expected child pid %d; status: %d %d",
  665.          child_pid, status >> 8, status & 0xff);
  666.       exit_status = 1;
  667.       return (false);
  668.     }
  669.   if (status & 0xff == 0177)
  670.     {
  671.       error (0, 0, "child stopped; status %d %d\n",
  672.          status >> 8, status & 0xff);
  673.       exit_status = 1;
  674.       return (false);
  675.     }
  676.  
  677. #endif /* not MSDOS */
  678.  
  679.   if (status & 0xff != 0)
  680.     {
  681.       error (0, 0, "child terminated abnormally; status %d %d",
  682.          status >> 8, status & 0xff);
  683.       exit_status = 1;
  684.       return (false);
  685.     }
  686.   return (!(status >> 8));
  687. }
  688.  
  689. #ifdef    DEBUG
  690. /* Return a pointer to the string representation of 
  691.    the predicate function PRED_FUNC. */
  692.  
  693. char *
  694. find_pred_name (pred_func)
  695. #ifdef MSDOS
  696.      PRED_FCT pred_func;
  697. #else
  698.      PFB pred_func;
  699. #endif
  700. {
  701.   int i;
  702.  
  703.   for (i = 0; pred_table[i].pred_func != 0; i++)
  704.     if (pred_table[i].pred_func == pred_func)
  705.       break;
  706.   return (pred_table[i].pred_name);
  707. }
  708.  
  709. char *
  710. type_name (type)
  711.      short type;
  712. {
  713.   int i;
  714.  
  715.   for (i = 0; type_table[i].type != (short) -1; i++)
  716.     if (type_table[i].type == type)
  717.       break;
  718.   return (type_table[i].type_name);
  719. }
  720.  
  721. char *
  722. prec_name (prec)
  723.      short prec;
  724. {
  725.   int i;
  726.  
  727.   for (i = 0; prec_table[i].prec != (short) -1; i++)
  728.     if (prec_table[i].prec == prec)
  729.       break;
  730.   return (prec_table[i].prec_name);
  731. }
  732.  
  733. /* Walk the expression tree NODE to stdout.
  734.    INDENT is the number of levels to indent the left margin. */
  735.  
  736. void
  737. print_tree (node, indent)
  738.      struct pred_struct *node;
  739.      int indent;
  740. {
  741.   int i;
  742.  
  743.   if (node == NULL)
  744.     return;
  745.   for (i = 0; i < indent; i++)
  746.     printf ("    ");
  747.   printf ("%s %s %s %x\n", find_pred_name (node->pred_func),
  748.       type_name (node->p_type), prec_name (node->p_prec), node);
  749.   for (i = 0; i < indent; i++)
  750.     printf ("    ");
  751.   printf ("left:\n");
  752.   print_tree (node->pred_left, indent + 1);
  753.   for (i = 0; i < indent; i++)
  754.     printf ("    ");
  755.   printf ("right:\n");
  756.   print_tree (node->pred_right, indent + 1);
  757. }
  758.  
  759. /* Copy STR into BUF and trim blanks from the end of BUF.
  760.    Return BUF. */
  761.  
  762. char *
  763. blank_rtrim (str, buf)
  764.      char *str;
  765.      char *buf;
  766. {
  767.   int i;
  768.  
  769.   if (str == NULL)
  770.     return (NULL);
  771.   strcpy (buf, str);
  772.   i = strlen (buf) - 1;
  773.   while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
  774.     i--;
  775.   buf[++i] = '\0';
  776.   return (buf);
  777. }
  778.  
  779. /* Print out the predicate list starting at NODE. */
  780.  
  781. void
  782. print_list (node)
  783.      struct pred_struct *node;
  784. {
  785.   struct pred_struct *cur;
  786.   char name[256];
  787.  
  788.   cur = node;
  789.   while (cur != NULL)
  790.     {
  791.       printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
  792.       cur = cur->pred_next;
  793.     }
  794.   printf ("\n");
  795. }
  796. #endif    /* DEBUG */
  797.