Good idea? Bad idea? Good idea but bad code? Would other crule
functions be useful? Should I be spending more time on other feature
requests?
(doc/example.conf is not yet updated; the syntax is basically the same
as before, but with quoted strings instead of unquoted strings. The
crule_expr production in ircd_parser.y should be clear.)
Entrope
2006-07-25 Michael Poole <[EMAIL PROTECTED]>
* include/crule.h (crule_free): Remove a level of indirection.
(crule_parse): Remove declaration.
(crule_text): New function.
(crule_make_and): New function.
(crule_make_or): New function.
(crule_make_not): New function.
(crule_make_connected): New function.
(crule_make_directcon): New function.
(crule_make_via): New function.
(crule_make_directop): New function.
* ircd/crule.c: Rewrite.
* ircd/ircd_lexer.l: Recognize new tokens &&, ||, CONNECTED,
DIRECTCON, DIRECTOP, VIA.
* ircd/ircd_parser.y: Declare the new tokens.
(optall): New production with type <num>.
(crule_expr): New production with type <crule>.
(%union): Add new member to expression type union.
(cruleblock): Rewrite to not use {} and to use optall, crule_expr.
* ircd/s_conf.c (conf_erase_crule_list): Remove a level of
indirection for crule_free().
--- orig/include/crule.h
+++ mod/include/crule.h
@@ -6,16 +6,23 @@
#define INCLUDED_crule_h
/*
- * Proto types
- */
-
-/*
* opaque node pointer
*/
struct CRuleNode;
-extern void crule_free(struct CRuleNode** elem);
extern int crule_eval(struct CRuleNode* rule);
-extern struct CRuleNode* crule_parse(const char* rule);
+extern char *crule_text(struct CRuleNode *rule);
+
+extern struct CRuleNode* crule_make_and(struct CRuleNode *left,
+ struct CRuleNode *right);
+extern struct CRuleNode* crule_make_or(struct CRuleNode *left,
+ struct CRuleNode *right);
+extern struct CRuleNode* crule_make_not(struct CRuleNode *arg);
+extern struct CRuleNode* crule_make_connected(char *arg);
+extern struct CRuleNode* crule_make_directcon(char *arg);
+extern struct CRuleNode* crule_make_via(char *neighbor,
+ char *server);
+extern struct CRuleNode* crule_make_directop(void);
+extern void crule_free(struct CRuleNode* elem);
#endif /* INCLUDED_crule_h */
--- orig/ircd/crule.c
+++ mod/ircd/crule.c
@@ -4,866 +4,294 @@
* @version $Id: crule.c,v 1.11 2006/01/06 11:39:04 isomer Exp $
*
* by Tony Vencill (Tonto on IRC) <[EMAIL PROTECTED]>
+ * rewritten by Michael Poole <[EMAIL PROTECTED]>
*
- * The majority of this file is a recursive descent parser used to convert
- * connection rules into expression trees when the conf file is read.
- * All parsing structures and types are hidden in the interest of good
- * programming style and to make possible future data structure changes
- * without affecting the interface between this patch and the rest of the
- * server. The only functions accessible externally are crule_parse,
- * crule_free, and crule_eval. Prototypes for these functions can be
- * found in h.h.
- *
- * Please direct any connection rule or SmartRoute questions to Tonto on
- * IRC or by email to [EMAIL PROTECTED]
- *
- * For parser testing, defining CR_DEBUG generates a stand-alone parser
- * that takes rules from stdin and prints out memory allocation
- * information and the parsed rule. This stand alone parser is ignorant
- * of the irc server and thus cannot do rule evaluation. Do not define
- * this flag when compiling the server! If you wish to generate the
- * test parser, compile from the ircd directory with a line similar to
- * cc -o parser -DCR_DEBUG crule.c
- *
- * The define CR_CHKCONF is provided to generate routines needed in
- * chkconf. These consist of the parser, a different crule_parse that
- * prints errors to stderr, and crule_free (just for good style and to
- * more closely simulate the actual ircd environment). crule_eval and
- * the rule functions are made empty functions as in the stand-alone
- * test parser.
- *
- * The production rules for the grammar are as follows ("rule" is the
- * starting production):
- *
- * rule:
- * orexpr END END is end of input or :
- * orexpr:
- * andexpr
- * andexpr || orexpr
- * andexpr:
- * primary
- * primary && andexpr
- * primary:
- * function
- * ! primary
- * ( orexpr )
- * function:
- * word ( ) word is alphanumeric string, first character
- * word ( arglist ) must be a letter
- * arglist:
- * word
- * word , arglist
+ * This used to have a recursive descent parser and debugging helper
+ * code. That all got ripped out and moved into the config parser.
*/
-#include "config.h"
+#include "config.h"
#include "crule.h"
-#ifndef CR_DEBUG
-
-/* ircd functions and types we need */
#include "client.h"
#include "ircd.h"
#include "ircd_alloc.h"
-#include "ircd_chattr.h"
-#include "ircd_log.h"
+#include "ircd_log.h" /* for assert() */
#include "ircd_string.h"
+#include "ircd_snprintf.h"
+#include "list.h"
#include "match.h"
#include "s_bsd.h"
-#include "s_debug.h"
#include "struct.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-#else /* includes and defines to make the stand-alone test parser */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#define BadPtr(x) (!(x) || (*(x) == '\0'))
-#define DupString(x,y) \
- do { \
- x = (char*) MyMalloc(strlen(y)+1); \
- strcpy(x,y); \
- } while(0)
-
-/* We don't care about collation discrepancies here, it seems.... */
-#define ircd_strcmp strcasecmp
-
-#endif
-
-#include <string.h>
-
-
-#if defined(CR_DEBUG) || defined(CR_CHKCONF)
-#undef MyMalloc
-#undef malloc
-#define MyMalloc malloc
-#undef MyFree
-#undef free
-#define MyFree free
-#endif
-
-/* some constants and shared data types */
-#define CR_MAXARGLEN 80 /**< Maximum arg length (must be > HOSTLEN) */
-#define CR_MAXARGS 3 /**< Maximum number of args for a rule */
-
-/*
- * Some symbols for easy reading
- */
-
-/** Input scanner tokens. */
-enum crule_token {
- CR_UNKNOWN, /**< Unknown token type. */
- CR_END, /**< End of input ('\\0' or ':'). */
- CR_AND, /**< Logical and operator (&&). */
- CR_OR, /**< Logical or operator (||). */
- CR_NOT, /**< Logical not operator (!). */
- CR_OPENPAREN, /**< Open parenthesis. */
- CR_CLOSEPAREN, /**< Close parenthesis. */
- CR_COMMA, /**< Comma. */
- CR_WORD /**< Something that looks like a hostmask (alphanumerics,
"*?.-"). */
-};
-
-/** Parser error codes. */
-enum crule_errcode {
- CR_NOERR, /**< No error. */
- CR_UNEXPCTTOK, /**< Invalid token given context. */
- CR_UNKNWTOK, /**< Input did not form a valid token. */
- CR_EXPCTAND, /**< Did not see expected && operator. */
- CR_EXPCTOR, /**< Did not see expected || operator. */
- CR_EXPCTPRIM, /**< Expected a primitive (parentheses, ! or word). */
- CR_EXPCTOPEN, /**< Expected an open parenthesis after function name. */
- CR_EXPCTCLOSE, /**< Expected a close parenthesis to match open parenthesis.
*/
- CR_UNKNWFUNC, /**< Attempt to use an unknown function. */
- CR_ARGMISMAT /**< Wrong number of arguments to function. */
-};
-
-/*
- * Expression tree structure, function pointer, and tree pointer local!
- */
/** Evaluation function for a connection rule. */
-typedef int (*crule_funcptr) (int, void **);
+typedef int (*crule_funcptr) (struct CRuleNode *);
/** Node in a connection rule tree. */
struct CRuleNode {
crule_funcptr funcptr; /**< Evaluation function for this node. */
int numargs; /**< Number of arguments. */
- void *arg[CR_MAXARGS]; /**< Array of arguments. For operators, each arg
+ void *arg[1]; /**< Array of arguments. For operators, each arg
is a tree element; for functions, each arg is
a string. */
};
-/** Typedef to save typing effort. */
-typedef struct CRuleNode* CRuleNodePtr;
-
-/* local rule function prototypes */
-static int crule_connected(int, void *[]);
-static int crule_directcon(int, void *[]);
-static int crule_via(int, void *[]);
-static int crule_directop(int, void *[]);
-static int crule__andor(int, void *[]);
-static int crule__not(int, void *[]);
-
-/* local parsing function prototypes */
-static int crule_gettoken(int* token, const char** str);
-static void crule_getword(char*, int*, size_t, const char**);
-static int crule_parseandexpr(CRuleNodePtr*, int *, const char**);
-static int crule_parseorexpr(CRuleNodePtr*, int *, const char**);
-static int crule_parseprimary(CRuleNodePtr*, int *, const char**);
-static int crule_parsefunction(CRuleNodePtr*, int *, const char**);
-static int crule_parsearglist(CRuleNodePtr, int *, const char**);
-
-#if defined(CR_DEBUG) || defined(CR_CHKCONF)
-/*
- * Prototypes for the test parser; if not debugging,
- * these are defined in h.h
- */
-struct CRuleNode* crule_parse(const char*);
-void crule_free(struct CRuleNode**);
-#ifdef CR_DEBUG
-void print_tree(CRuleNodePtr);
-#endif
-#endif
-
-/** Error messages, indexed by the corresponding crule_errcode. */
-static char *crule_errstr[] = {
- "Unknown error", /* NOERR? - for completeness */
- "Unexpected token", /* UNEXPCTTOK */
- "Unknown token", /* UNKNWTOK */
- "And expr expected", /* EXPCTAND */
- "Or expr expected", /* EXPCTOR */
- "Primary expected", /* EXPCTPRIM */
- "( expected", /* EXPCTOPEN */
- ") expected", /* EXPCTCLOSE */
- "Unknown function", /* UNKNWFUNC */
- "Argument mismatch" /* ARGMISMAT */
-};
-
-/** Connection rule function table entry. */
-struct crule_funclistent {
- char name[15]; /**< Function name. */
- int reqnumargs; /**< Required number of arguments. */
- crule_funcptr funcptr; /**< Handler function. */
-};
+/** Create a CRuleNode.
+ * @param[in] funcptr Evaluation function for the node.
+ * @param[in] numargs Number of arguments.
+ * @param[in] ... Arguments as void pointers.
+ * @return Newly allocated CRuleNode.
+ */
+static struct CRuleNode *crule_make(crule_funcptr funcptr, int numargs, ...)
+{
+ struct CRuleNode *res;
+ va_list va;
+ int ii;
+
+ /* be sure we allocate at least sizeof(struct CRuleNode) */
+ if (numargs > 0)
+ res = MyMalloc(sizeof(*res) + sizeof(res->arg[0]) * (numargs - 1));
+ else
+ res = MyMalloc(sizeof(*res));
+ res->funcptr = funcptr;
+ res->numargs = numargs;
+ va_start(va, numargs);
+ for (ii = 0; ii < numargs; ++ii)
+ res->arg[ii] = va_arg(va, void*);
+ va_end(va);
+ return res;
+}
+
+/** Find any linked server with a name matching \a mask behind \a start.
+ * @param[in] mask Server name mask to search for.
+ * @param[in] start Server at which to start search.
+ * @return A pointer to a server matching \a mask, or NULL if none exist.
+ */
+static int crule_connected_from(const char *mask, struct Client *start)
+{
+ struct DLink *dl;
+
+ assert(cli_serv(start) != NULL);
+
+ for (dl = cli_serv(start)->down; dl; dl = dl->next)
+ if (match(mask, cli_name(dl->value.cptr))
+ || crule_connected_from(mask, dl->value.cptr))
+ return 1;
-/** Defined connection rules. */
-static struct crule_funclistent crule_funclist[] = {
- /* maximum function name length is 14 chars */
- {"connected", 1, crule_connected},
- {"directcon", 1, crule_directcon},
- {"via", 2, crule_via},
- {"directop", 0, crule_directop},
- {"", 0, NULL} /* this must be here to mark end of list */
-};
+ return 0;
+}
-/** Check whether any connected server matches crulearg[0].
- * @param[in] numargs Number of valid args in \a crulearg.
- * @param[in] crulearg Argument array.
+/** Check whether any connected server matches \a rule->arg[0].
+ * @param[in] rule The rule to evaluate.
* @return Non-zero if the condition is true, zero if not.
*/
-static int crule_connected(int numargs, void *crulearg[])
+static int crule_connected(struct CRuleNode *rule)
{
-#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
- struct Client *acptr;
+ assert(rule->numargs == 1);
- /* taken from m_links */
- for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
- {
- if (!IsServer(acptr) && !IsMe(acptr))
- continue;
- if (match((char *)crulearg[0], cli_name(acptr)))
- continue;
- return (1);
- }
-#endif
- return (0);
+ return crule_connected_from(rule->arg[0], &me);
}
-/** Check whether any directly connected server matches crulearg[0].
- * @param[in] numargs Number of valid args in \a crulearg.
- * @param[in] crulearg Argument array.
+/** Check whether any directly connected server matches \a rule->arg[0].
+ * @param[in] rule The rule to evaluate.
* @return Non-zero if the condition is true, zero if not.
*/
-static int crule_directcon(int numargs, void *crulearg[])
+static int crule_directcon(struct CRuleNode *rule)
{
-#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
- int i;
- struct Client *acptr;
+ struct DLink *dl;
- /* adapted from m_trace and exit_one_client */
- for (i = 0; i <= HighestFd; i++)
- {
- if (!(acptr = LocalClientArray[i]) || !IsServer(acptr))
- continue;
- if (match((char *)crulearg[0], cli_name(acptr)))
- continue;
- return (1);
- }
-#endif
- return (0);
+ assert(rule->numargs == 1);
+
+ for (dl = cli_serv(&me)->down; dl; dl = dl->next)
+ if (match(rule->arg[0], cli_name(dl->value.cptr)))
+ return 1;
+
+ return 0;
}
-/** Check whether a connected server matching crulearg[1] is
- * connnected to me behind one matching crulearg[0].
- * @param[in] numargs Number of valid args in \a crulearg.
- * @param[in] crulearg Argument array.
+/** Check whether a connected server matching \a rule->arg[1] is
+ * connnected to me behind one matching \a rule->arg[0].
+ * @param[in] rule The rule to evaluate.
* @return Non-zero if the condition is true, zero if not.
*/
-static int crule_via(int numargs, void *crulearg[])
+static int crule_via(struct CRuleNode *rule)
{
-#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
- struct Client *acptr;
+ struct DLink *dl;
- /* adapted from m_links */
- for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
- {
- if (!IsServer(acptr) && !IsMe(acptr))
- continue;
- if (match((char *)crulearg[1], cli_name(acptr)))
- continue;
- if (match((char *)crulearg[0], cli_name(cli_from(acptr))))
- continue;
- return (1);
- }
-#endif
- return (0);
+ assert(rule->numargs == 2);
+
+ for (dl = cli_serv(&me)->down; dl; dl = dl->next)
+ if (match(rule->arg[0], cli_name(dl->value.cptr))
+ && crule_connected_from(rule->arg[1], dl->value.cptr))
+ return 1;
+
+ return 0;
}
/** Check whether we have a local IRC operator.
- * @param[in] numargs Number of valid args in \a crulearg.
- * @param[in] crulearg Argument array.
+ * @param[in] rule The rule to evaluate.
* @return Non-zero if the condition is true, zero if not.
*/
-static int crule_directop(int numargs, void *crulearg[])
+static int crule_directop(struct CRuleNode *rule)
{
-#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
- int i;
struct Client *acptr;
+ int i;
+
+ assert(rule->numargs == 0);
- /* adapted from m_trace */
for (i = 0; i <= HighestFd; i++)
- {
- if (!(acptr = LocalClientArray[i]) || !IsAnOper(acptr))
- continue;
- return (1);
- }
-#endif
- return (0);
+ if ((acptr = LocalClientArray[i]) && IsAnOper(acptr))
+ return 1;
+
+ return 0;
}
-/** Evaluate a connection rule.
- * @param[in] rule Rule to evalute.
- * @return Non-zero if the rule allows the connection, zero otherwise.
+/** Perform an 'and' test on \a rule->arg[0] and \a rule->arg[1].
+ * @param[in] rule Rule to evaluate.
+ * @return Non-zero if the condition is true, zero if not.
*/
-int crule_eval(struct CRuleNode* rule)
+static int crule_and(struct CRuleNode *rule)
{
- return (rule->funcptr(rule->numargs, rule->arg));
+ assert(rule->numargs == 2);
+ return crule_eval(rule->arg[0]) && crule_eval(rule->arg[1]);
}
-/** Perform an and-or-or test on crulearg[0] and crulearg[1].
- * If crulearg[2] is non-NULL, it means do OR; if it is NULL, do AND.
- * @param[in] numargs Number of valid args in \a crulearg.
- * @param[in] crulearg Argument array.
+/** Perform an 'or' test on \a rule->arg[0] and \a rule->arg[1].
+ * @param[in] rule Rule to evaluate.
* @return Non-zero if the condition is true, zero if not.
*/
-static int crule__andor(int numargs, void *crulearg[])
+static int crule_or(struct CRuleNode *rule)
{
- int result1;
-
- result1 = crule_eval(crulearg[0]);
- if (crulearg[2]) /* or */
- return (result1 || crule_eval(crulearg[1]));
- else
- return (result1 && crule_eval(crulearg[1]));
+ assert(rule->numargs == 2);
+ return crule_eval(rule->arg[0]) || crule_eval(rule->arg[1]);
}
-/** Logically invert the result of crulearg[0].
- * @param[in] numargs Number of valid args in \a crulearg.
- * @param[in] crulearg Argument array.
+/** Invert the logical sense of \a rule->arg[0].
+ * @param[in] rule Rule to evaluate.
* @return Non-zero if the condition is true, zero if not.
*/
-static int crule__not(int numargs, void *crulearg[])
+static int crule_not(struct CRuleNode *rule)
{
- return (!crule_eval(crulearg[0]));
-}
-
-/** Scan an input token from \a ruleptr.
- * @param[out] next_tokp Receives type of next token.
- * @param[in,out] ruleptr Next readable character from input.
- * @return Either CR_UNKNWTOK if the input was unrecognizable, else CR_NOERR.
- */
-static int crule_gettoken(int* next_tokp, const char** ruleptr)
-{
- char pending = '\0';
-
- *next_tokp = CR_UNKNOWN;
- while (*next_tokp == CR_UNKNOWN)
- switch (*(*ruleptr)++)
- {
- case ' ':
- case '\t':
- break;
- case '&':
- if (pending == '\0')
- pending = '&';
- else if (pending == '&')
- *next_tokp = CR_AND;
- else
- return (CR_UNKNWTOK);
- break;
- case '|':
- if (pending == '\0')
- pending = '|';
- else if (pending == '|')
- *next_tokp = CR_OR;
- else
- return (CR_UNKNWTOK);
- break;
- case '!':
- *next_tokp = CR_NOT;
- break;
- case '(':
- *next_tokp = CR_OPENPAREN;
- break;
- case ')':
- *next_tokp = CR_CLOSEPAREN;
- break;
- case ',':
- *next_tokp = CR_COMMA;
- break;
- case '\0':
- (*ruleptr)--;
- *next_tokp = CR_END;
- break;
- case ':':
- *next_tokp = CR_END;
- break;
- default:
- if ((IsAlpha(*(--(*ruleptr)))) || (**ruleptr == '*') ||
- (**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-'))
- *next_tokp = CR_WORD;
- else
- return (CR_UNKNWTOK);
- break;
- }
- return CR_NOERR;
-}
-
-/** Scan a word from \a ruleptr.
- * @param[out] word Output buffer.
- * @param[out] wordlenp Length of word written to \a word (not including
terminating NUL).
- * @param[in] maxlen Maximum number of bytes writable to \a word.
- * @param[in,out] ruleptr Next readable character from input.
- */
-static void crule_getword(char* word, int* wordlenp, size_t maxlen, const
char** ruleptr)
-{
- char *word_ptr;
-
- word_ptr = word;
- while ((size_t)(word_ptr - word) < maxlen
- && (IsAlnum(**ruleptr)
- || **ruleptr == '*' || **ruleptr == '?'
- || **ruleptr == '.' || **ruleptr == '-'))
- *word_ptr++ = *(*ruleptr)++;
- *word_ptr = '\0';
- *wordlenp = word_ptr - word;
-}
-
-/** Parse an entire rule.
- * @param[in] rule Text form of rule.
- * @return CRuleNode for rule, or NULL if there was a parse error.
- */
-struct CRuleNode* crule_parse(const char *rule)
-{
- const char* ruleptr = rule;
- int next_tok;
- struct CRuleNode* ruleroot = 0;
- int errcode = CR_NOERR;
-
- if ((errcode = crule_gettoken(&next_tok, &ruleptr)) == CR_NOERR) {
- if ((errcode = crule_parseorexpr(&ruleroot, &next_tok, &ruleptr)) ==
CR_NOERR) {
- if (ruleroot != NULL) {
- if (next_tok == CR_END)
- return (ruleroot);
- else
- errcode = CR_UNEXPCTTOK;
- }
- else
- errcode = CR_EXPCTOR;
- }
- }
- if (ruleroot != NULL)
- crule_free(&ruleroot);
-#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
- log_write(LS_CONFIG, L_WARNING, 0, "%s in rule: %s",
- crule_errstr[errcode], rule);
-#else
- fprintf(stderr, "%s in rule: %s\n", crule_errstr[errcode], rule);
-#endif
- return 0;
-}
-
-/** Parse an or expression.
- * @param[out] orrootp Receives parsed node.
- * @param[in,out] next_tokp Next input token type.
- * @param[in,out] ruleptr Next input character.
- * @return A crule_errcode value.
- */
-static int crule_parseorexpr(CRuleNodePtr * orrootp, int *next_tokp, const
char** ruleptr)
-{
- int errcode = CR_NOERR;
- CRuleNodePtr andexpr;
- CRuleNodePtr orptr;
-
- *orrootp = NULL;
- while (errcode == CR_NOERR)
- {
- errcode = crule_parseandexpr(&andexpr, next_tokp, ruleptr);
- if ((errcode == CR_NOERR) && (*next_tokp == CR_OR))
- {
- orptr = (CRuleNodePtr) MyMalloc(sizeof(struct CRuleNode));
-#ifdef CR_DEBUG
- fprintf(stderr, "allocating or element at %ld\n", orptr);
-#endif
- orptr->funcptr = crule__andor;
- orptr->numargs = 3;
- orptr->arg[2] = (void *)1;
- if (*orrootp != NULL)
- {
- (*orrootp)->arg[1] = andexpr;
- orptr->arg[0] = *orrootp;
- }
- else
- orptr->arg[0] = andexpr;
- *orrootp = orptr;
- }
- else
- {
- if (*orrootp != NULL)
- {
- if (andexpr != NULL)
- {
- (*orrootp)->arg[1] = andexpr;
- return (errcode);
- }
- else
- {
- (*orrootp)->arg[1] = NULL; /* so free doesn't seg fault */
- return (CR_EXPCTAND);
- }
- }
- else
- {
- *orrootp = andexpr;
- return (errcode);
- }
- }
- if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
- return (errcode);
- }
- return (errcode);
+ assert(rule->numargs == 1);
+ return !crule_eval(rule->arg[0]);
}
-/** Parse an and expression.
- * @param[out] androotp Receives parsed node.
- * @param[in,out] next_tokp Next input token type.
- * @param[in,out] ruleptr Next input character.
- * @return A crule_errcode value.
+/** Evaluate a connection rule.
+ * @param[in] rule Rule to evalute.
+ * @return Non-zero if the rule allows the connection, zero otherwise.
*/
-static int crule_parseandexpr(CRuleNodePtr * androotp, int *next_tokp, const
char** ruleptr)
+int crule_eval(struct CRuleNode* rule)
{
- int errcode = CR_NOERR;
- CRuleNodePtr primary;
- CRuleNodePtr andptr;
-
- *androotp = NULL;
- while (errcode == CR_NOERR)
- {
- errcode = crule_parseprimary(&primary, next_tokp, ruleptr);
- if ((errcode == CR_NOERR) && (*next_tokp == CR_AND))
- {
- andptr = (CRuleNodePtr) MyMalloc(sizeof(struct CRuleNode));
-#ifdef CR_DEBUG
- fprintf(stderr, "allocating and element at %ld\n", andptr);
-#endif
- andptr->funcptr = crule__andor;
- andptr->numargs = 3;
- andptr->arg[2] = (void *)0;
- if (*androotp != NULL)
- {
- (*androotp)->arg[1] = primary;
- andptr->arg[0] = *androotp;
- }
- else
- andptr->arg[0] = primary;
- *androotp = andptr;
- }
- else
- {
- if (*androotp != NULL)
- {
- if (primary != NULL)
- {
- (*androotp)->arg[1] = primary;
- return (errcode);
- }
- else
- {
- (*androotp)->arg[1] = NULL; /* so free doesn't seg fault */
- return (CR_EXPCTPRIM);
- }
- }
- else
- {
- *androotp = primary;
- return (errcode);
- }
- }
- if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
- return (errcode);
- }
- return (errcode);
+ return (rule->funcptr(rule));
}
-/** Parse a primary expression.
- * @param[out] primrootp Receives parsed node.
- * @param[in,out] next_tokp Next input token type.
- * @param[in,out] ruleptr Next input character.
- * @return A crule_errcode value.
+/** Free a connection rule and all its children.
+ * @param[in] elem Pointer to element to free.
*/
-static int crule_parseprimary(CRuleNodePtr* primrootp, int *next_tokp, const
char** ruleptr)
+void crule_free(struct CRuleNode* elem)
{
- CRuleNodePtr *insertionp;
- int errcode = CR_NOERR;
-
- *primrootp = NULL;
- insertionp = primrootp;
- while (errcode == CR_NOERR)
+ if (!elem)
+ return;
+ if (elem->funcptr == crule_not)
{
- switch (*next_tokp)
- {
- case CR_OPENPAREN:
- if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
- break;
- if ((errcode = crule_parseorexpr(insertionp, next_tokp, ruleptr)) !=
CR_NOERR)
- break;
- if (*insertionp == NULL)
- {
- errcode = CR_EXPCTAND;
- break;
- }
- if (*next_tokp != CR_CLOSEPAREN)
- {
- errcode = CR_EXPCTCLOSE;
- break;
- }
- errcode = crule_gettoken(next_tokp, ruleptr);
- break;
- case CR_NOT:
- *insertionp = (CRuleNodePtr) MyMalloc(sizeof(struct CRuleNode));
-#ifdef CR_DEBUG
- fprintf(stderr, "allocating primary element at %ld\n", *insertionp);
-#endif
- (*insertionp)->funcptr = crule__not;
- (*insertionp)->numargs = 1;
- (*insertionp)->arg[0] = NULL;
- insertionp = (CRuleNodePtr *) & ((*insertionp)->arg[0]);
- if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
- break;
- continue;
- case CR_WORD:
- errcode = crule_parsefunction(insertionp, next_tokp, ruleptr);
- break;
- default:
- if (*primrootp == NULL)
- errcode = CR_NOERR;
- else
- errcode = CR_EXPCTPRIM;
- break;
- }
- return (errcode);
+ crule_free(elem->arg[0]);
}
- return (errcode);
-}
-
-/** Parse a function call.
- * @param[out] funcrootp Receives parsed node.
- * @param[in,out] next_tokp Next input token type.
- * @param[in,out] ruleptr Next input character.
- * @return A crule_errcode value.
- */
-static int crule_parsefunction(CRuleNodePtr* funcrootp, int* next_tokp, const
char** ruleptr)
-{
- int errcode = CR_NOERR;
- char funcname[CR_MAXARGLEN];
- int namelen;
- int funcnum;
-
- *funcrootp = NULL;
- crule_getword(funcname, &namelen, CR_MAXARGLEN - 1, ruleptr);
- if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
- return (errcode);
- if (*next_tokp == CR_OPENPAREN)
+ else if (elem->funcptr == crule_and || elem->funcptr == crule_or)
{
- for (funcnum = 0;; funcnum++)
- {
- if (0 == ircd_strcmp(crule_funclist[funcnum].name, funcname))
- break;
- if (crule_funclist[funcnum].name[0] == '\0')
- return (CR_UNKNWFUNC);
- }
- if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
- return (errcode);
- *funcrootp = (CRuleNodePtr) MyMalloc(sizeof(struct CRuleNode));
-#ifdef CR_DEBUG
- fprintf(stderr, "allocating function element at %ld\n", *funcrootp);
-#endif
- (*funcrootp)->funcptr = NULL; /* for freeing aborted trees */
- if ((errcode =
- crule_parsearglist(*funcrootp, next_tokp, ruleptr)) != CR_NOERR)
- return (errcode);
- if (*next_tokp != CR_CLOSEPAREN)
- return (CR_EXPCTCLOSE);
- if ((crule_funclist[funcnum].reqnumargs != (*funcrootp)->numargs) &&
- (crule_funclist[funcnum].reqnumargs != -1))
- return (CR_ARGMISMAT);
- if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
- return (errcode);
- (*funcrootp)->funcptr = crule_funclist[funcnum].funcptr;
- return (CR_NOERR);
+ crule_free(elem->arg[0]);
+ crule_free(elem->arg[1]);
}
else
- return (CR_EXPCTOPEN);
-}
-
-/** Parse the argument list to a CRuleNode.
- * @param[in,out] argrootp Node whos argument list is being populated.
- * @param[in,out] next_tokp Next input token type.
- * @param[in,out] ruleptr Next input character.
- * @return A crule_errcode value.
- */
-static int crule_parsearglist(CRuleNodePtr argrootp, int *next_tokp, const
char** ruleptr)
-{
- int errcode = CR_NOERR;
- char *argelemp = NULL;
- char currarg[CR_MAXARGLEN];
- int arglen = 0;
- char word[CR_MAXARGLEN];
- int wordlen = 0;
-
- argrootp->numargs = 0;
- currarg[0] = '\0';
- while (errcode == CR_NOERR)
{
- switch (*next_tokp)
- {
- case CR_WORD:
- crule_getword(word, &wordlen, CR_MAXARGLEN - 1, ruleptr);
- if (currarg[0] != '\0')
- {
- if ((arglen + wordlen) < (CR_MAXARGLEN - 1))
- {
- strcat(currarg, " ");
- strcat(currarg, word);
- arglen += wordlen + 1;
- }
- }
- else
- {
- strcpy(currarg, word);
- arglen = wordlen;
- }
- errcode = crule_gettoken(next_tokp, ruleptr);
- break;
- default:
-#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
- collapse(currarg);
-#endif
- if (!BadPtr(currarg))
- {
- DupString(argelemp, currarg);
- argrootp->arg[argrootp->numargs++] = (void *)argelemp;
- }
- if (*next_tokp != CR_COMMA)
- return (CR_NOERR);
- currarg[0] = '\0';
- errcode = crule_gettoken(next_tokp, ruleptr);
- break;
- }
+ while (elem->numargs)
+ MyFree(elem->arg[--elem->numargs]);
}
- return (errcode);
+ MyFree(elem);
}
-/*
- * This function is recursive.. I wish I knew a nonrecursive way but
- * I don't. Anyway, recursion is fun.. :)
- * DO NOT CALL THIS FUNCTION WITH A POINTER TO A NULL POINTER
- * (i.e.: If *elem is NULL, you're doing it wrong - seg fault)
- */
-/** Free a connection rule and all its children.
- * @param[in,out] elem Pointer to pointer to element to free. MUST NOT BE
NULL.
- */
-void crule_free(struct CRuleNode** elem)
+struct CRuleNode *
+crule_make_and(struct CRuleNode *left, struct CRuleNode *right)
{
- int arg, numargs;
+ return crule_make(crule_and, 2, left, right);
+}
- if ((*(elem))->funcptr == crule__not)
- {
- /* type conversions and ()'s are fun! ;) here have an aspirin.. */
- if ((*(elem))->arg[0] != NULL)
- crule_free((struct CRuleNode**) &((*(elem))->arg[0]));
- }
- else if ((*(elem))->funcptr == crule__andor)
- {
- crule_free((struct CRuleNode**) &((*(elem))->arg[0]));
- if ((*(elem))->arg[1] != NULL)
- crule_free((struct CRuleNode**) &((*(elem))->arg[1]));
- }
- else
- {
- numargs = (*(elem))->numargs;
- for (arg = 0; arg < numargs; arg++)
- MyFree((*(elem))->arg[arg]);
- }
-#ifdef CR_DEBUG
- fprintf(stderr, "freeing element at %ld\n", *elem);
-#endif
- MyFree(*elem);
- *elem = 0;
+struct CRuleNode *
+crule_make_or(struct CRuleNode *left, struct CRuleNode *right)
+{
+ return crule_make(crule_or, 2, left, right);
}
-#ifdef CR_DEBUG
-/** Display a connection rule as text.
- * @param[in] printelem Connection rule to display.
- */
-static void print_tree(CRuleNodePtr printelem)
+struct CRuleNode *
+crule_make_not(struct CRuleNode *arg)
{
- int funcnum, arg;
+ return crule_make(crule_not, 1, arg);
+}
- if (printelem->funcptr == crule__not)
- {
- printf("!( ");
- print_tree((CRuleNodePtr) printelem->arg[0]);
- printf(") ");
- }
- else if (printelem->funcptr == crule__andor)
- {
- printf("( ");
- print_tree((CRuleNodePtr) printelem->arg[0]);
- if (printelem->arg[2])
- printf("|| ");
- else
- printf("&& ");
- print_tree((CRuleNodePtr) printelem->arg[1]);
- printf(") ");
- }
- else
- {
- for (funcnum = 0;; funcnum++)
- {
- if (printelem->funcptr == crule_funclist[funcnum].funcptr)
- break;
- if (crule_funclist[funcnum].funcptr == NULL)
- MyCoreDump;
- }
- printf("%s(", crule_funclist[funcnum].name);
- for (arg = 0; arg < printelem->numargs; arg++)
- {
- if (arg != 0)
- printf(",");
- printf("%s", (char *)printelem->arg[arg]);
- }
- printf(") ");
- }
+struct CRuleNode *
+crule_make_connected(char *arg)
+{
+ return crule_make(crule_connected, 1, arg);
}
-#endif
+struct CRuleNode *
+crule_make_directcon(char *arg)
+{
+ return crule_make(crule_directcon, 1, arg);
+}
-#ifdef CR_DEBUG
-/** Read connection rules from stdin and display parsed forms as text.
- * @return Zero.
- */
-int main(void)
+struct CRuleNode *
+crule_make_via(char *neighbor, char *server)
{
- char indata[256];
- CRuleNode* rule;
+ return crule_make(crule_via, 2, neighbor, server);
+}
- printf("rule: ");
- while (fgets(indata, 256, stdin) != NULL)
- {
- indata[strlen(indata) - 1] = '\0'; /* lose the newline */
- if ((rule = crule_parse(indata)) != NULL)
- {
- printf("equivalent rule: ");
- print_tree((CRuleNodePtr) rule);
- printf("\n");
- crule_free(&rule);
- }
- printf("\nrule: ");
- }
- printf("\n");
+struct CRuleNode *
+crule_make_directop(void)
+{
+ return crule_make(crule_directop, 0);
+}
- return 0;
+static int
+crule_cat(struct CRuleNode *rule, char *buf, size_t remain)
+{
+ if (rule->funcptr == crule_connected) {
+ assert(rule->numargs == 1);
+ return ircd_snprintf(NULL, buf, remain, "connected(\"%s\")", rule->arg[0]);
+ } else if (rule->funcptr == crule_directcon) {
+ assert(rule->numargs == 1);
+ return ircd_snprintf(NULL, buf, remain, "directcon(\"%s\")", rule->arg[0]);
+ } else if (rule->funcptr == crule_via) {
+ assert(rule->numargs == 2);
+ return ircd_snprintf(NULL, buf, remain, "via(\"%s\", \"%s\")",
+ rule->arg[0], rule->arg[1]);
+ } else if (rule->funcptr == crule_directop) {
+ assert(rule->numargs == 0);
+ return ircd_snprintf(NULL, buf, remain, "directop()", rule->arg[0]);
+ } else if (rule->funcptr == crule_and || rule->funcptr == crule_or) {
+ const char *op = (rule->funcptr == crule_and) ? " && " : " || ";
+ size_t used = 0;
+
+ assert(rule->numargs == 2);
+ if (remain > used++)
+ buf[used - 1] = '(';
+ used += crule_cat(rule->arg[0], buf + used, (remain < used) ? 0 : remain -
used);
+ if (remain > used)
+ used += ircd_snprintf(NULL, buf + used, remain - used, op);
+ used += crule_cat(rule->arg[1], buf + used, (remain < used) ? 0 : remain -
used);
+ if (remain > used++)
+ buf[used - 1] = ')';
+ return used;
+ } else if (rule->funcptr == crule_not) {
+ if (remain)
+ buf[0] = '!';
+ return 1 + crule_cat(rule->arg[0], buf + 1, (remain < 1) ? 0 : remain - 1);
+ } else
+ return ircd_snprintf(NULL, buf, remain, "???");
}
-#endif
+char *crule_text(struct CRuleNode *rule)
+{
+ char buf[BUFSIZE], *res;
+ buf[sizeof(buf) - 1] = '\0';
+ crule_cat(rule, buf, sizeof(buf) - 1);
+ return DupString(res, buf);
+}
--- orig/ircd/ircd_lexer.l
+++ mod/ircd/ircd_lexer.l
@@ -73,6 +73,8 @@
#.* ;
<<EOF>> { yypop_buffer_state(); if (YY_CURRENT_BUFFER) return
TEOF; else yyterminate(); }
+\&\& return LOGICAL_AND;
+\|\| return LOGICAL_OR;
ADMIN return ADMIN;
ADMINISTRATOR return ADMIN;
APASS_OPMODE return TPRIV_APASS_OPMODE;
@@ -86,6 +88,7 @@
CLASS return CLASS;
CLIENT return CLIENT;
CONNECT return CONNECT;
+CONNECTED return CONNECTED;
CONNECTFREQ return CONNECTFREQ;
CONTACT return CONTACT;
CRULE return CRULE;
@@ -94,6 +97,8 @@
DEOP_LCHAN return TPRIV_DEOP_LCHAN;
DESCRIPTION return DESCRIPTION;
DIE return TPRIV_DIE;
+DIRECTCON return DIRECTCON;
+DIRECTOP return DIRECTOP;
DISPLAY return TPRIV_DISPLAY;
FAST return FAST;
FEATURES return FEATURES;
@@ -175,6 +180,7 @@
USERNAME return USERNAME;
UWORLD return UWORLD;
VHOST return VHOST;
+VIA return VIA;
WALK_LCHAN return TPRIV_WALK_LCHAN;
WEEKS return WEEKS;
WIDE_GLINE return TPRIV_WIDE_GLINE;
--- orig/ircd/ircd_parser.y
+++ mod/ircd/ircd_parser.y
@@ -207,6 +207,8 @@
%token LINESYNC
%token FROM
%token TEOF
+%token LOGICAL_AND LOGICAL_OR
+%token CONNECTED DIRECTCON VIA DIRECTOP
/* and now a lot of privileges... */
%token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN
%token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE
@@ -221,10 +223,17 @@
%type <num> timespec timefactor factoredtimes factoredtime
%type <num> expr yesorno privtype
%type <num> blocklimit blocktypes blocktype
+%type <num> optall
+%type <crule> crule_expr
+%left LOGICAL_OR
+%left LOGICAL_AND
%left '+' '-'
%left '*' '/'
+%nonassoc '!'
+%nonassoc '(' ')'
%union{
+ struct CRuleNode *crule;
char *text;
int num;
}
@@ -946,62 +955,33 @@
dconf->message = $3;
};
-cruleblock: CRULE
+cruleblock: CRULE optall QSTRING optall crule_expr ';'
{
- tconn = CRULE_AUTO;
-} '{' cruleitems '}' ';'
-{
- struct CRuleNode *node = NULL;
- if (!permitted(BLOCK_CRULE, 1))
- ;
- else if (host == NULL)
- parse_error("Missing host in crule block");
- else if (pass == NULL)
- parse_error("Missing rule in crule block");
- else if ((node = crule_parse(pass)) == NULL)
- parse_error("Invalid rule '%s' in crule block", pass);
- else
+ if (permitted(BLOCK_CRULE, 1) && $5)
{
struct CRuleConf *p = (struct CRuleConf*) MyMalloc(sizeof(*p));
- p->hostmask = host;
- p->rule = pass;
- p->type = tconn;
- p->node = node;
+ p->hostmask = collapse($3);
+ p->rule = crule_text($5);
+ p->type = ($2 || $4) ? CRULE_ALL : CRULE_AUTO;
+ p->node = $5;
p->next = cruleConfList;
cruleConfList = p;
}
- if (!node)
- {
- MyFree(host);
- MyFree(pass);
- }
- host = pass = NULL;
- tconn = 0;
};
-cruleitems: cruleitem cruleitems | cruleitem;
-cruleitem: cruleserver | crulerule | cruleall;
+optall: { $$ = 0; };
+ | ALL { $$ = 1; };
-cruleserver: SERVER '=' QSTRING ';'
-{
- MyFree(host);
- collapse($3);
- host = $3;
-};
-
-crulerule: RULE '=' QSTRING ';'
-{
- MyFree(pass);
- pass = $3;
-};
-
-cruleall: ALL '=' YES ';'
-{
- tconn = CRULE_ALL;
-} | ALL '=' NO ';'
-{
- tconn = CRULE_AUTO;
-};
+crule_expr:
+ '(' crule_expr ')' { $$ = $2; }
+ | crule_expr LOGICAL_AND crule_expr { $$ = crule_make_and($1, $3); }
+ | crule_expr LOGICAL_OR crule_expr { $$ = crule_make_or($1, $3); }
+ | '!' crule_expr { $$ = crule_make_not($2); }
+ | CONNECTED '(' QSTRING ')' { $$ = crule_make_connected($3); }
+ | DIRECTCON '(' QSTRING ')' { $$ = crule_make_directcon($3); }
+ | VIA '(' QSTRING ',' QSTRING ')' { $$ = crule_make_via($3, $5); }
+ | DIRECTOP '(' ')' { $$ = crule_make_directop(); }
+ ;
motdblock: MOTD '{' motditems '}' ';'
{
--- orig/ircd/s_conf.c
+++ mod/ircd/s_conf.c
@@ -751,7 +751,7 @@
for ( ; p; p = next) {
next = p->next;
- crule_free(&p->node);
+ crule_free(p->node);
MyFree(p->hostmask);
MyFree(p->rule);
MyFree(p);
_______________________________________________
Coder-com mailing list
[email protected]
http://undernet.sbg.org/mailman/listinfo/coder-com