home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / ircd4652.zip / ircd-df-4.6.5-os2 / src / crule.c < prev    next >
C/C++ Source or Header  |  1997-12-28  |  19KB  |  776 lines

  1. /*
  2.  * SmartRoute phase 1
  3.  * connection rule patch
  4.  * by Tony Vencill (Tonto on IRC) <vencill@bga.com>
  5.  *
  6.  * The majority of this file is a recusive descent parser used to convert
  7.  * connection rules into expression trees when the conf file is read.
  8.  * All parsing structures and types are hidden in the interest of good
  9.  * programming style and to make possible future data structure changes
  10.  * without affecting the interface between this patch and the rest of the
  11.  * server.  The only functions accessible externally are crule_parse,
  12.  * crule_free, and crule_eval.  Prototypes for these functions can be
  13.  * found in h.h.
  14.  *
  15.  * Please direct any connection rule or SmartRoute questions to Tonto on
  16.  * IRC or by email to vencill@bga.com.
  17.  *
  18.  * For parser testing, defining CR_DEBUG generates a stand-alone parser
  19.  * that takes rules from stdin and prints out memory allocation
  20.  * information and the parsed rule.  This stand alone parser is ignorant
  21.  * of the irc server and thus cannot do rule evaluation.  Do not define
  22.  * this flag when compiling the server!  If you wish to generate the
  23.  * test parser, compile from the ircd directory with a line similar to
  24.  * cc -o parser -DCR_DEBUG crule.c
  25.  *
  26.  * The define CR_CHKCONF is provided to generate routines needed in
  27.  * chkconf.  These consist of the parser, a different crule_parse that
  28.  * prints errors to stderr, and crule_free (just for good style and to
  29.  * more closely simulate the actual ircd environment).  crule_eval and
  30.  * the rule functions are made empty functions as in the stand-alone
  31.  * test parser.
  32.  */
  33.  
  34. #ifndef CR_DEBUG
  35. /* ircd functions and types we need */
  36. #include "struct.h"
  37. #include "common.h"
  38. #include "sys.h"
  39. #include "h.h"
  40. char *collapse PROTO((char *pattern));
  41. extern aClient *client, *local[];
  42.  
  43. #else
  44. /* includes and defines to make the stand-alone test parser */
  45. #include <stdio.h>
  46. #include <string.h>
  47. #define BadPtr(x) (!(x) || (*(x) == '\0'))
  48. #define DupString(x,y) do{x=(char *)MyMalloc(strlen(y)+1);(void)strcpy(x,y);}while(0)
  49. #define mycmp strcasecmp
  50. #endif
  51.  
  52. #ifndef PROTO
  53. #if __STDC__
  54. #       define PROTO(x) x
  55. #else
  56. #       define PROTO(x) ()
  57. #endif
  58. #endif
  59. #if defined(CR_DEBUG) || defined(CR_CHKCONF)
  60. #define MyMalloc malloc
  61. #undef MyFree
  62. #undef free
  63. #define MyFree free
  64. #endif
  65.  
  66. /* some constants and shared data types */
  67. #define CR_MAXARGLEN 80  /* why 80? why not? it's > hostname lengths */
  68. #define CR_MAXARGS 3     /* there's a better way to do this, but not now */
  69.  
  70. /* some symbols for easy reading */
  71. enum crule_token
  72. {CR_UNKNOWN, CR_END, CR_AND, CR_OR, CR_NOT, CR_OPENPAREN, CR_CLOSEPAREN,
  73.    CR_COMMA, CR_WORD};
  74. enum crule_errcode
  75. {CR_NOERR, CR_UNEXPCTTOK, CR_UNKNWTOK, CR_EXPCTAND, CR_EXPCTOR,
  76.    CR_EXPCTPRIM, CR_EXPCTOPEN, CR_EXPCTCLOSE, CR_UNKNWFUNC, CR_ARGMISMAT};
  77.  
  78. /* expression tree structure, function pointer, and tree pointer */
  79. /* local! */
  80. typedef int (*crule_funcptr) PROTO((int, void **));
  81. struct crule_treestruct
  82. {
  83.   crule_funcptr funcptr;
  84.   int numargs;
  85.   void *arg[CR_MAXARGS];   /* for operators arg points to a tree element;
  86.                   for functions arg points to a char string */
  87. };
  88. typedef struct crule_treestruct crule_treeelem;
  89. typedef crule_treeelem *crule_treeptr;
  90.  
  91. /* rule function prototypes - local! */
  92. int crule_connected PROTO((int, void **));
  93. int crule_directcon PROTO((int, void **));
  94. int crule_via PROTO((int, void **));
  95. int crule_directop PROTO((int, void **));
  96. int crule__andor PROTO((int, void **));
  97. int crule__not PROTO((int, void **));
  98.  
  99. /* parsing function prototypes - local! */
  100. int crule_gettoken PROTO((int *, char **));
  101. void crule_getword PROTO((char *, int *, int, char **));
  102. int crule_parseandexpr PROTO((crule_treeptr *, int *, char **));
  103. int crule_parseorexpr PROTO((crule_treeptr *, int *, char **));
  104. int crule_parseprimary PROTO((crule_treeptr *, int *, char **));
  105. int crule_parsefunction PROTO((crule_treeptr *, int *, char **));
  106. int crule_parsearglist PROTO((crule_treeptr, int *, char **));
  107.  
  108. #if defined(CR_DEBUG) || defined(CR_CHKCONF)
  109. /* prototypes for the test parser; if not debugging, these are
  110.  * defined in h.h */
  111. char *crule_parse PROTO((char *));
  112. void crule_free PROTO((char **));
  113. #ifdef CR_DEBUG
  114. void print_tree PROTO((crule_treeptr));
  115. #endif
  116. #endif
  117.  
  118. /* error messages */
  119. char *crule_errstr[] =
  120. {
  121.   "Unknown error",     /* NOERR? - for completeness */
  122.   "Unexpected token",  /* UNEXPCTTOK */
  123.   "Unknown token",     /* UNKNWTOK */
  124.   "And expr expected", /* EXPCTAND */
  125.   "Or expr expected",  /* EXPCTOR */
  126.   "Primary expected",  /* EXPCTPRIM */
  127.   "( expected",        /* EXPCTOPEN */
  128.   ") expected",        /* EXPCTCLOSE */
  129.   "Unknown function",  /* UNKNWFUNC */
  130.   "Argument mismatch"  /* ARGMISMAT */
  131. };
  132.  
  133. /* function table - null terminated */
  134. struct crule_funclistent
  135. {
  136.   char name[15];  /* MAXIMUM FUNCTION NAME LENGTH IS 14 CHARS!! */
  137.   int reqnumargs;
  138.   crule_funcptr funcptr;
  139. };
  140. struct crule_funclistent crule_funclist[] =
  141. {
  142.   /* maximum function name length is 14 chars */
  143.   {"connected", 1, crule_connected},
  144.   {"directcon", 1, crule_directcon},
  145.   {"via",       2, crule_via},
  146.   {"directop",  0, crule_directop},
  147.   {"",          0, NULL}  /* this must be here to mark end of list */
  148. };
  149.  
  150. int crule_connected (numargs, crulearg)
  151. int numargs;
  152. void *crulearg[];
  153. {
  154. #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
  155.   aClient *acptr;
  156.  
  157.   /* taken from m_links */
  158.   for (acptr = client; acptr; acptr = acptr->next)
  159.     {
  160.       if (!IsServer(acptr) && !IsMe(acptr))
  161.     continue;
  162.       if (match((char *) crulearg[0], acptr->name))
  163.     continue;
  164.       return (1);
  165.     }
  166.   return (0);
  167. #endif
  168. }
  169.  
  170. int crule_directcon (numargs, crulearg)
  171. int numargs;
  172. void *crulearg[];
  173. {
  174. #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
  175.   int i;
  176.   aClient *acptr;
  177.  
  178.   /* adapted from m_trace and exit_one_client */
  179.   for (i = 0; i <= highest_fd; i++)
  180.     {
  181.       if (!(acptr = local[i]) || !IsServer(acptr))
  182.     continue;
  183.       if (match((char *) crulearg[0], acptr->name))
  184.     continue;
  185.       return (1);
  186.     }
  187.   return (0);
  188. #endif
  189. }
  190.  
  191. int crule_via (numargs, crulearg)
  192. int numargs;
  193. void *crulearg[];
  194. {
  195. #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
  196.   aClient *acptr;
  197.  
  198.   /* adapted from m_links */
  199.   for (acptr = client; acptr; acptr = acptr->next)
  200.     {
  201.       if (!IsServer(acptr) && !IsMe(acptr))
  202.     continue;
  203.       if (match((char *) crulearg[1], acptr->name))
  204.     continue;
  205.       if (match((char *) crulearg[0], (local[acptr->fd])->name))
  206.     continue;
  207.       return (1);
  208.     }
  209.   return (0);
  210. #endif
  211. }
  212.  
  213. int crule_directop (numargs, crulearg)
  214. int numargs;
  215. void *crulearg[];
  216. {
  217. #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
  218.   int i;
  219.   aClient *acptr;
  220.  
  221.   /* adapted from m_trace */
  222.   for (i = 0; i <= highest_fd; i++)
  223.     {
  224.       if (!(acptr = local[i]) || !IsAnOper(acptr))
  225.     continue;
  226.       return (1);
  227.     }
  228.   return (0);
  229. #endif
  230. }
  231.  
  232. int crule__andor (numargs, crulearg)
  233. int numargs;
  234. void *crulearg[];
  235. {
  236.   int result1;
  237.  
  238.   result1 = ((crule_treeptr) crulearg[0])->funcptr
  239.     (((crule_treeptr) crulearg[0])->numargs,
  240.      (void *) ((crule_treeptr) crulearg[0])->arg);
  241.   if (crulearg[2]) /* or */
  242.     return (result1 ||
  243.         ((crule_treeptr) crulearg[1])->funcptr
  244.         (((crule_treeptr) crulearg[1])->numargs,
  245.          (void *) ((crule_treeptr) crulearg[1])->arg));
  246.   else
  247.     return (result1 &&
  248.         ((crule_treeptr) crulearg[1])->funcptr
  249.         (((crule_treeptr) crulearg[1])->numargs,
  250.          (void *) ((crule_treeptr) crulearg[1])->arg));
  251. }
  252.  
  253. int crule__not (numargs, crulearg)
  254. int numargs;
  255. void *crulearg[];
  256. {
  257.   return (!((crule_treeptr) crulearg[0])->funcptr
  258.       (((crule_treeptr) crulearg[0])->numargs,
  259.        (void *) ((crule_treeptr) crulearg[0])->arg));
  260. }
  261.  
  262. #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
  263. int crule_eval (rule)
  264. char *rule;
  265. {
  266.   return (((crule_treeptr) rule)->funcptr
  267.       (((crule_treeptr) rule)->numargs,
  268.        ((crule_treeptr) rule)->arg));
  269. }
  270. #endif
  271.  
  272. int crule_gettoken (next_tokp, ruleptr)
  273. int *next_tokp;
  274. char **ruleptr;
  275. {
  276.   char pending = '\0';
  277.  
  278.   *next_tokp = CR_UNKNOWN;
  279.   while (*next_tokp == CR_UNKNOWN)
  280.     switch (*(*ruleptr)++)
  281.       {
  282.       case ' ': case '\t':
  283.     break;
  284.       case '&':
  285.     if (pending == '\0')
  286.       pending = '&';
  287.     else if (pending == '&')
  288.       *next_tokp = CR_AND;
  289.     else
  290.       return (CR_UNKNWTOK);
  291.     break;
  292.       case '|':
  293.     if (pending == '\0')
  294.       pending = '|';
  295.     else if (pending == '|')
  296.       *next_tokp = CR_OR;
  297.     else
  298.       return (CR_UNKNWTOK);
  299.     break;
  300.       case '!':
  301.     *next_tokp = CR_NOT;
  302.     break;
  303.       case '(':
  304.     *next_tokp = CR_OPENPAREN;
  305.     break;
  306.       case ')':
  307.     *next_tokp = CR_CLOSEPAREN;
  308.     break;
  309.       case ',':
  310.     *next_tokp = CR_COMMA;
  311.     break;
  312.       case '\0':
  313.     (*ruleptr)--;
  314.     *next_tokp = CR_END;
  315.     break;
  316.       case ':':
  317.     *next_tokp = CR_END;
  318.     break;
  319.       default:
  320.     if ((isalpha (*(--(*ruleptr)))) || (**ruleptr == '*') ||
  321.         (**ruleptr == '?') || (**ruleptr == '.'))
  322.       *next_tokp = CR_WORD;
  323.     else
  324.       return (CR_UNKNWTOK);
  325.     break;
  326.       }
  327.   return CR_NOERR;
  328. }
  329.  
  330. void crule_getword (word, wordlenp, maxlen, ruleptr)
  331. char *word;
  332. int *wordlenp;
  333. int maxlen;
  334. char **ruleptr;
  335. {
  336.   char *word_ptr;
  337.  
  338.   word_ptr = word;
  339.   while ((isalnum (**ruleptr)) || (**ruleptr == '*') ||
  340.          (**ruleptr == '?') || (**ruleptr == '.'))
  341.     *word_ptr++ = *(*ruleptr)++;
  342.   *word_ptr = '\0';
  343.   *wordlenp = word_ptr - word;
  344. }
  345.  
  346. /*
  347.  * Grammar
  348.  *   rule:
  349.  *     orexpr END          END is end of input or :
  350.  *   orexpr:
  351.  *     andexpr
  352.  *     andexpr || orexpr
  353.  *   andexpr:
  354.  *     primary
  355.  *     primary && andexpr
  356.  *  primary:
  357.  *    function
  358.  *    ! primary
  359.  *    ( orexpr )
  360.  *  function:
  361.  *    word ( )             word is alphanumeric string, first character
  362.  *    word ( arglist )       must be a letter
  363.  *  arglist:
  364.  *    word
  365.  *    word , arglist
  366.  */
  367.  
  368. char *crule_parse (rule)
  369. char *rule;
  370. {
  371.   char *ruleptr = rule;
  372.   int next_tok;
  373.   crule_treeptr ruleroot = NULL;
  374.   int errcode = CR_NOERR;
  375.  
  376.   if ((errcode = crule_gettoken (&next_tok, &ruleptr)) == CR_NOERR)
  377.     if ((errcode = crule_parseorexpr (&ruleroot, &next_tok,
  378.                       &ruleptr)) == CR_NOERR)
  379.       if (ruleroot != NULL)
  380.     if (next_tok == CR_END)
  381.       return ((char *) ruleroot);
  382.     else
  383.       errcode = CR_UNEXPCTTOK;
  384.       else
  385.     errcode = CR_EXPCTOR;
  386.   if (ruleroot != NULL)
  387.     crule_free ((char **) &ruleroot);
  388. #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
  389.   Debug ((DEBUG_ERROR, "%s in rule: %s", crule_errstr[errcode], rule));
  390. #else
  391.   (void) fprintf (stderr, "%s in rule: %s\n", crule_errstr[errcode], rule);
  392. #endif
  393.   return NULL;
  394. }
  395.  
  396. int crule_parseorexpr (orrootp, next_tokp, ruleptr)
  397. crule_treeptr *orrootp;
  398. int *next_tokp;
  399. char **ruleptr;
  400. {
  401.   int errcode = CR_NOERR;
  402.   crule_treeptr andexpr;
  403.   crule_treeptr orptr;
  404.  
  405.   *orrootp = NULL;
  406.   while (errcode == CR_NOERR)
  407.     {
  408.       errcode = crule_parseandexpr (&andexpr, next_tokp, ruleptr);
  409.       if ((errcode == CR_NOERR) && (*next_tokp == CR_OR))
  410.     {
  411.       orptr = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
  412. #ifdef CR_DEBUG
  413.       (void) fprintf (stderr, "allocating or element at %ld\n", orptr);
  414. #endif
  415.       orptr->funcptr = crule__andor;
  416.       orptr->numargs = 3;
  417.       orptr->arg[2] = (void *) 1;
  418.       if (*orrootp != NULL)
  419.         {
  420.           (*orrootp)->arg[1] = andexpr;
  421.           orptr->arg[0] = *orrootp;
  422.         }
  423.       else
  424.         orptr->arg[0] = andexpr;
  425.       *orrootp = orptr;
  426.     }
  427.       else
  428.     {
  429.       if (*orrootp != NULL)
  430.         if (andexpr != NULL)
  431.           {
  432.         (*orrootp)->arg[1] = andexpr;
  433.         return (errcode);
  434.           }
  435.         else
  436.           {
  437.         (*orrootp)->arg[1] = NULL; /* so free doesn't seg fault */
  438.         return (CR_EXPCTAND);
  439.           }
  440.       else
  441.         {
  442.           *orrootp = andexpr;
  443.           return (errcode);
  444.         }
  445.     }
  446.       if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
  447.     return (errcode);
  448.     }
  449.   return (errcode);
  450. }
  451.  
  452. int crule_parseandexpr (androotp, next_tokp, ruleptr)
  453. crule_treeptr *androotp;
  454. int *next_tokp;
  455. char **ruleptr;
  456. {
  457.   int errcode = CR_NOERR;
  458.   crule_treeptr primary;
  459.   crule_treeptr andptr;
  460.  
  461.   *androotp = NULL;
  462.   while (errcode == CR_NOERR)
  463.     {
  464.       errcode = crule_parseprimary (&primary, next_tokp, ruleptr);
  465.       if ((errcode == CR_NOERR) && (*next_tokp == CR_AND))
  466.     {
  467.       andptr = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
  468. #ifdef CR_DEBUG
  469.       (void) fprintf (stderr, "allocating and element at %ld\n", andptr);
  470. #endif
  471.       andptr->funcptr = crule__andor;
  472.       andptr->numargs = 3;
  473.       andptr->arg[2] = (void *) 0;
  474.       if (*androotp != NULL)
  475.         {
  476.           (*androotp)->arg[1] = primary;
  477.           andptr->arg[0] = *androotp;
  478.         }
  479.       else
  480.         andptr->arg[0] = primary;
  481.       *androotp = andptr;
  482.     }
  483.       else
  484.     {
  485.       if (*androotp != NULL)
  486.             if (primary != NULL)
  487.           {
  488.         (*androotp)->arg[1] = primary;
  489.         return (errcode);
  490.           }
  491.             else
  492.           {
  493.         (*androotp)->arg[1] = NULL; /* so free doesn't seg fault */
  494.         return (CR_EXPCTPRIM);
  495.           }
  496.       else
  497.         {
  498.           *androotp = primary;
  499.           return (errcode);
  500.         }
  501.     }
  502.       if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
  503.     return (errcode);
  504.     }
  505.   return (errcode);
  506. }
  507.  
  508. int crule_parseprimary (primrootp, next_tokp, ruleptr)
  509. crule_treeptr *primrootp;
  510. int *next_tokp;
  511. char **ruleptr;
  512. {
  513.   crule_treeptr *insertionp;
  514.   int errcode = CR_NOERR;
  515.  
  516.   *primrootp = NULL;
  517.   insertionp = primrootp;
  518.   while (errcode == CR_NOERR)
  519.     {
  520.       switch (*next_tokp)
  521.     {
  522.     case CR_OPENPAREN:
  523.       if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
  524.         break;
  525.       if ((errcode = crule_parseorexpr (insertionp, next_tokp,
  526.                          ruleptr)) != CR_NOERR)
  527.         break;
  528.       if (*insertionp == NULL)
  529.         {
  530.           errcode = CR_EXPCTAND;
  531.           break;
  532.         }
  533.       if (*next_tokp != CR_CLOSEPAREN)
  534.         {
  535.           errcode = CR_EXPCTCLOSE;
  536.           break;
  537.         }
  538.       errcode = crule_gettoken (next_tokp, ruleptr);
  539.       break;
  540.     case CR_NOT:
  541.       *insertionp = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
  542. #ifdef CR_DEBUG
  543.       (void) fprintf (stderr,
  544.               "allocating primary element at %ld\n", *insertionp);
  545. #endif
  546.       (*insertionp)->funcptr = crule__not;
  547.       (*insertionp)->numargs = 1;
  548.       (*insertionp)->arg[0] = NULL;
  549.       insertionp = (crule_treeptr *) &((*insertionp)->arg[0]);
  550.       if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
  551.         break;
  552.       continue;
  553.     case CR_WORD:
  554.       errcode = crule_parsefunction (insertionp, next_tokp, ruleptr);
  555.       break;
  556.     default:
  557.           if (*primrootp == NULL)
  558.             errcode = CR_NOERR;
  559.           else
  560.         errcode = CR_EXPCTPRIM;
  561.       break;
  562.     }
  563.       return (errcode);
  564.     }
  565.   return (errcode);
  566. }
  567.  
  568. int crule_parsefunction (funcrootp, next_tokp, ruleptr)
  569. crule_treeptr *funcrootp;
  570. int *next_tokp;
  571. char **ruleptr;
  572. {
  573.   int errcode = CR_NOERR;
  574.   char funcname[CR_MAXARGLEN];
  575.   int namelen;
  576.   int funcnum;
  577.  
  578.   *funcrootp = NULL;
  579.   crule_getword (funcname, &namelen, CR_MAXARGLEN, ruleptr);
  580.   if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
  581.     return (errcode);
  582.   if (*next_tokp == CR_OPENPAREN)
  583.     {
  584.       for (funcnum = 0; ; funcnum++)
  585.     {
  586.       if (mycmp (crule_funclist[funcnum].name, funcname) == 0)
  587.         break;
  588.       if (crule_funclist[funcnum].name[0] == '\0')
  589.         return (CR_UNKNWFUNC);
  590.     }
  591.       if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
  592.     return (errcode);
  593.       *funcrootp = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
  594. #ifdef CR_DEBUG
  595.       (void) fprintf (stderr, "allocating function element at %ld\n",
  596.               *funcrootp);
  597. #endif
  598.       (*funcrootp)->funcptr = NULL; /* for freeing aborted trees */
  599.       if ((errcode = crule_parsearglist (*funcrootp, next_tokp,
  600.                      ruleptr)) != CR_NOERR)
  601.     return (errcode);
  602.       if (*next_tokp != CR_CLOSEPAREN)
  603.     return (CR_EXPCTCLOSE);
  604.       if ((crule_funclist[funcnum].reqnumargs != (*funcrootp)->numargs) &&
  605.       (crule_funclist[funcnum].reqnumargs != -1))
  606.     return (CR_ARGMISMAT);
  607.       if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
  608.     return (errcode);
  609.       (*funcrootp)->funcptr = crule_funclist[funcnum].funcptr;
  610.       return (CR_NOERR);
  611.     }
  612.   else
  613.     return (CR_EXPCTOPEN);
  614. }
  615.  
  616. int crule_parsearglist (argrootp, next_tokp, ruleptr)
  617. crule_treeptr argrootp;
  618. int *next_tokp;
  619. char **ruleptr;
  620. {
  621.   int errcode = CR_NOERR;
  622.   char *argelemp = NULL;
  623.   char currarg[CR_MAXARGLEN];
  624.   int arglen = 0;
  625.   char word[CR_MAXARGLEN];
  626.   int wordlen = 0;
  627.  
  628.   argrootp->numargs = 0;
  629.   currarg[0] = '\0';
  630.   while (errcode == CR_NOERR)
  631.     {
  632.       switch (*next_tokp)
  633.     {
  634.     case CR_WORD:
  635.       crule_getword (word, &wordlen, CR_MAXARGLEN, ruleptr);
  636.       if (currarg[0] != '\0')
  637.         {
  638.           if ((arglen + wordlen) < (CR_MAXARGLEN - 1))
  639.         {
  640.           strcat (currarg, " ");
  641.           strcat (currarg, word);
  642.           arglen += wordlen + 1;
  643.         }
  644.         }
  645.       else
  646.         {
  647.           strcpy (currarg, word);
  648.           arglen = wordlen;
  649.         }
  650.       errcode = crule_gettoken (next_tokp, ruleptr);
  651.       break;
  652.     default:
  653. #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
  654.       (void) collapse (currarg);
  655. #endif
  656.       if (!BadPtr (currarg))
  657.         {
  658.           DupString (argelemp, currarg);
  659.           argrootp->arg[argrootp->numargs++] = (void *) argelemp;
  660.         }
  661.       if (*next_tokp != CR_COMMA)
  662.         return (CR_NOERR);
  663.       currarg[0] = '\0';
  664.       errcode = crule_gettoken (next_tokp, ruleptr);
  665.       break;
  666.     }
  667.     }
  668.   return (errcode);
  669. }
  670.  
  671. /*
  672.  * this function is recursive..  i wish i knew a nonrecursive way but
  673.  * i dont.  anyway, recursion is fun..  :)
  674.  * DO NOT CALL THIS FUNTION WITH A POINTER TO A NULL POINTER
  675.  * (ie: if *elem is NULL, you're doing it wrong - seg fault)
  676.  */
  677. void crule_free (elem)
  678. char **elem;
  679. {
  680.   int arg, numargs;
  681.  
  682.   if ((*((crule_treeptr *) elem))->funcptr == crule__not)
  683.     {
  684.       /* type conversions and ()'s are fun! ;)  here have an asprin.. */
  685.       if ((*((crule_treeptr *)elem))->arg[0] != NULL)
  686.     crule_free ((char **) &((*((crule_treeptr *) elem))->arg[0]));
  687.     }
  688.   else if ((*((crule_treeptr *)elem))->funcptr == crule__andor)
  689.     {
  690.       crule_free ((char **) &((*((crule_treeptr *) elem))->arg[0]));
  691.       if ((*((crule_treeptr *)elem))->arg[1] != NULL)
  692.     crule_free ((char **) &((*((crule_treeptr *) elem))->arg[1]));
  693.     }
  694.   else
  695.     {
  696.       numargs = (*((crule_treeptr *) elem))->numargs;
  697.       for (arg = 0; arg < numargs; arg++)
  698.     MyFree ((char *) (*((crule_treeptr *) elem))->arg[arg]);
  699.     }
  700. #ifdef CR_DEBUG
  701.   (void) fprintf (stderr, "freeing element at %ld\n", *elem);
  702. #endif
  703.   MyFree (*elem);
  704.   *elem = NULL;
  705. }
  706.  
  707. #ifdef CR_DEBUG
  708. void print_tree (printelem)
  709. crule_treeptr printelem;
  710. {
  711.   int funcnum, arg;
  712.  
  713.   if (printelem->funcptr == crule__not)
  714.     {
  715.       printf ("!( ");
  716.       print_tree ((crule_treeptr) printelem->arg[0]);
  717.       printf (") ");
  718.     }
  719.   else if (printelem->funcptr == crule__andor)
  720.     {
  721.       printf ("( ");
  722.       print_tree ((crule_treeptr) printelem->arg[0]);
  723.       if (printelem->arg[2])
  724.     printf ("|| ");
  725.       else
  726.     printf ("&& ");
  727.       print_tree ((crule_treeptr) printelem->arg[1]);
  728.       printf (") ");
  729.     }
  730.   else
  731.     {
  732.       for (funcnum = 0; ;funcnum++)
  733.     {
  734.       if (printelem->funcptr == crule_funclist[funcnum].funcptr)
  735.         break;
  736.       if (crule_funclist[funcnum].funcptr == NULL)
  737.         {
  738.           printf ("\nACK!  *koff*  *sputter*\n");
  739.           exit (1);
  740.         }
  741.     }
  742.       printf ("%s(", crule_funclist[funcnum].name);
  743.       for (arg = 0; arg < printelem->numargs; arg++)
  744.     {
  745.       if (arg != 0)
  746.         printf (",");
  747.       printf ("%s", (char *) printelem->arg[arg]);
  748.     }
  749.       printf (") ");
  750.     }
  751. }
  752. #endif
  753.  
  754. #ifdef CR_DEBUG
  755. void main ()
  756. {
  757.   char indata[256];
  758.   char *rule;
  759.  
  760.   printf ("rule: ");
  761.   while (fgets (indata, 256, stdin) != NULL)
  762.     {
  763.       indata[strlen (indata) - 1] = '\0'; /* lose the newline */
  764.       if ((rule = crule_parse (indata)) != NULL)
  765.     {
  766.       printf ("equivalent rule: ");
  767.       print_tree ((crule_treeptr) rule);
  768.       printf ("\n");
  769.       crule_free (&rule);
  770.     }
  771.       printf ("\nrule: ");
  772.     }
  773.   printf ("\n");
  774. }
  775. #endif
  776.