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