From: Adam Dickmeiss Date: Mon, 13 Feb 1995 12:35:20 +0000 (+0000) Subject: First version of CCL. Qualifiers aren't handled yet. X-Git-Url: http://sru.miketaylor.org.uk/cgi-bin?a=commitdiff_plain;h=68727e97f4ab17a7008c5a8552796ec123af031c;p=egate.git First version of CCL. Qualifiers aren't handled yet. --- diff --git a/ccl/Makefile b/ccl/Makefile new file mode 100644 index 0000000..20984f1 --- /dev/null +++ b/ccl/Makefile @@ -0,0 +1,49 @@ +# Makefile for Email gateway CCL +# Europagate, 1995 +# +# $Log: Makefile,v $ +# Revision 1.1 1995/02/13 12:35:20 adam +# First version of CCL. Qualifiers aren't handled yet. +# +SHELL=/bin/sh +INCLUDE=-I../include +CFLAGS=-g -Wall -pedantic -ansi +CC=gcc +TPROG1=cclsh +LIB=../lib/ccl.a +PO=cclfind.o ccltoken.o cclerrms.o +CPP=cc -E +DEFS=$(INCLUDE) + +all: $(TPROG1) + +$(TPROG1): $(TPROG1).o $(LIB) ../lib/util.a + $(CC) $(CFLAGS) -o $(TPROG1) $(TPROG1).o $(LIB) ../lib/util.a + +$(LIB): $(PO) + rm -f $(LIB) + ar qc $(LIB) $(PO) + ranlib $(LIB) + +.c.o: + $(CC) -c $(DEFS) $(CFLAGS) $< + +clean: + rm -f *.log *.[oa] $(TPROG1) $(TPROG2) core mon.out gmon.out errlist *~ + +depend: depend2 + +depend1: + mv Makefile Makefile.tmp + sed '/^#Depend/q' Makefile + $(CPP) $(INCLUDE) -M *.c >>Makefile + -rm Makefile.tmp + +depend2: + $(CPP) $(INCLUDE) -M *.c >.depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + +#Depend --- DOT NOT DELETE THIS LINE diff --git a/ccl/ccl.h b/ccl/ccl.h new file mode 100644 index 0000000..444575e --- /dev/null +++ b/ccl/ccl.h @@ -0,0 +1,19 @@ +/* CCL - public header file + * Europagate, 1995 + * + * $Log: ccl.h,v $ + * Revision 1.1 1995/02/13 12:35:20 adam + * First version of CCL. Qualifiers aren't handled yet. + * + */ + +#define CCL_ERR_OK 0 +#define CCL_ERR_TERM_EXPECTED 1 +#define CCL_ERR_RP_EXPECTED 2 +#define CCL_ERR_SETNAME_EXPECTED 3 +#define CCL_ERR_OP_EXPECTED 4 +#define CCL_ERR_BAD_RP 5 + +void ccl_find_str (const char *str, int *error, int *pos); + +char *ccl_err_msg (int ccl_errno); diff --git a/ccl/cclerrms.c b/ccl/cclerrms.c new file mode 100644 index 0000000..85a4ce6 --- /dev/null +++ b/ccl/cclerrms.c @@ -0,0 +1,22 @@ +/* + * Europagate, 1995 + * + * $Log: cclerrms.c,v $ + * Revision 1.1 1995/02/13 12:35:20 adam + * First version of CCL. Qualifiers aren't handled yet. + * + */ + +char *err_msg_array[] = { + "Ok", + "Search word expected", + ") expected", + "Set name expected", + "Operator expected", + "Unbalanced )" +}; + +const char *ccl_err_msg (int ccl_errno) +{ + return err_msg_array[ccl_errno]; +} diff --git a/ccl/cclfind.c b/ccl/cclfind.c new file mode 100644 index 0000000..b663666 --- /dev/null +++ b/ccl/cclfind.c @@ -0,0 +1,341 @@ +/* CCL find (to rpn conversion) + * Europagate, 1995 + * + * $Log: cclfind.c,v $ + * Revision 1.1 1995/02/13 12:35:20 adam + * First version of CCL. Qualifiers aren't handled yet. + * + */ + +#include +#include +#include +#include + +#include "cclp.h" + +static struct ccl_token *look_token; +static int ccl_error; + +#define KIND (look_token->kind) +#define ADVANCE look_token = look_token->next +#define ADVX(x) x=(x)->next + +static void strxcat (char *n, const char *src, int len) +{ + while (*n) + n++; + while (--len >= 0) + *n++ = *src++; + *n = '\0'; +} + +static char *copy_token_name (struct ccl_token *tp) +{ + char *str = malloc (tp->len + 1); + memcpy (str, tp->name, tp->len); + str[tp->len] = '\0'; + return str; +} + +static struct ccl_rpn_node *mk_node (enum rpn_node_kind kind) +{ + struct ccl_rpn_node *p; + p = malloc (sizeof(*p)); + assert (p); + p->kind = kind; + return p; +} + +void ccl_rpn_delete (struct ccl_rpn_node *rpn) +{ + if (!rpn) + return; + switch (rpn->kind) + { + case AND: + case OR: + case NOT: + ccl_rpn_delete (rpn->u.p[0]); + ccl_rpn_delete (rpn->u.p[1]); + break; + case TERM: + free (rpn->u.t.term); + /* attr list */ + break; + case SET: + free (rpn->u.setname); + break; + case PROX: + ccl_rpn_delete (rpn->u.p[0]); + ccl_rpn_delete (rpn->u.p[1]); + break; + } + free (rpn); +} + +static struct ccl_rpn_node *find_spec (void); + +static struct ccl_rpn_node *search_term (void) +{ + struct ccl_rpn_node *p; + struct ccl_token *lookahead = look_token; + int len = 0; + + if (KIND != CCL_TOK_TERM) + { + ccl_error = CCL_ERR_TERM_EXPECTED; + return NULL; + } + while (lookahead->kind == CCL_TOK_TERM) + { + len += 1+lookahead->len; + lookahead = lookahead->next; + } + p = mk_node (TERM); + p->u.t.term = malloc (len); + p->u.t.attr_list = NULL; + p->u.t.term[0] = '\0'; + assert (p->u.t.term); + strxcat (p->u.t.term, look_token->name, look_token->len); + ADVANCE; + while (KIND == CCL_TOK_TERM) + { + strcat (p->u.t.term, " "); + strxcat (p->u.t.term, look_token->name, look_token->len); + ADVANCE; + } + return p; +} + +static struct ccl_rpn_node *qualifiers (struct ccl_token *la) +{ + assert (0); + return NULL; +} + +static struct ccl_rpn_node *search_terms (void) +{ + struct ccl_rpn_node *p1, *p2, *pn; + p1 = search_term (); + if (!p1) + return NULL; + while (1) + { + if (KIND == CCL_TOK_PROX) + { + ADVANCE; + p2 = search_term (); + if (!p2) + { + ccl_rpn_delete (p1); + return NULL; + } + pn = mk_node (PROX); + pn->u.p[0] = p1; + pn->u.p[1] = p2; + p1 = pn; + } + else if (KIND == CCL_TOK_TERM) + { + p2 = search_term (); + if (!p2) + { + ccl_rpn_delete (p1); + return NULL; + } + pn = mk_node (PROX); + pn->u.p[0] = p1; + pn->u.p[1] = p2; + p1 = pn; + } + else + break; + } + return p1; +} + +static struct ccl_rpn_node *search_elements (void) +{ + struct ccl_rpn_node *p1; + struct ccl_token *lookahead; + if (KIND == CCL_TOK_LP) + { + ADVANCE; + p1 = find_spec (); + if (!p1) + return NULL; + if (KIND != CCL_TOK_RP) + { + ccl_error = CCL_ERR_RP_EXPECTED; + ccl_rpn_delete (p1); + return NULL; + } + ADVANCE; + return p1; + } + else if (KIND == CCL_TOK_SET) + { + ADVANCE; + if (KIND != CCL_TOK_TERM) + { + ccl_error = CCL_ERR_SETNAME_EXPECTED; + return NULL; + } + p1 = mk_node (SET); + p1->u.setname = copy_token_name (look_token); + ADVANCE; + return p1; + } + lookahead = look_token; + + while (lookahead->kind==CCL_TOK_TERM || lookahead->kind==CCL_TOK_COMMA) + lookahead = lookahead->next; + if (lookahead->kind == CCL_TOK_REL || lookahead->kind == CCL_TOK_EQ) + return qualifiers (lookahead); + return search_terms (); +} + +static struct ccl_rpn_node *find_spec (void) +{ + struct ccl_rpn_node *p1, *p2, *pn; + if (!(p1 = search_elements ())) + return NULL; + while (1) + { + switch (KIND) + { + case CCL_TOK_AND: + ADVANCE; + p2 = search_elements (); + if (!p2) + { + ccl_rpn_delete (p1); + return NULL; + } + pn = mk_node (AND); + pn->u.p[0] = p1; + pn->u.p[1] = p2; + p1 = pn; + continue; + case CCL_TOK_OR: + ADVANCE; + p2 = search_elements (); + if (!p2) + { + ccl_rpn_delete (p1); + return NULL; + } + pn = mk_node (OR); + pn->u.p[0] = p1; + pn->u.p[1] = p2; + p1 = pn; + continue; + case CCL_TOK_NOT: + ADVANCE; + p2 = search_elements (); + if (!p2) + { + ccl_rpn_delete (p1); + return NULL; + } + pn = mk_node (NOT); + pn->u.p[0] = p1; + pn->u.p[1] = p2; + p1 = pn; + continue; + } + break; + } + return p1; +} + +struct ccl_rpn_node *ccl_find (struct ccl_token *list, + int *error, const char **pos) +{ + struct ccl_rpn_node *p; + + look_token = list; + p = find_spec (); + if (p && KIND != CCL_TOK_EOL) + { + if (KIND == CCL_TOK_RP) + ccl_error = CCL_ERR_BAD_RP; + else + ccl_error = CCL_ERR_OP_EXPECTED; + ccl_rpn_delete (p); + p = NULL; + } + *pos = look_token->name; + if (p) + *error = CCL_ERR_OK; + else + *error = ccl_error; + return p; +} + +static void pr_tree (struct ccl_rpn_node *rpn) +{ + switch (rpn->kind) + { + case TERM: + printf ("\"%s\"", rpn->u.t.term); + break; + case AND: + printf ("("); + pr_tree (rpn->u.p[0]); + printf (") and ("); + pr_tree (rpn->u.p[1]); + printf (")"); + break; + case OR: + printf ("("); + pr_tree (rpn->u.p[0]); + printf (") or ("); + pr_tree (rpn->u.p[1]); + printf (")"); + break; + case NOT: + printf ("("); + pr_tree (rpn->u.p[0]); + printf (") not ("); + pr_tree (rpn->u.p[1]); + printf (")"); + break; + case SET: + printf ("set=%s", rpn->u.setname); + break; + case PROX: + printf ("("); + pr_tree (rpn->u.p[0]); + printf (") prox ("); + pr_tree (rpn->u.p[1]); + printf (")"); + break; + default: + assert (0); + } +} + +void ccl_find_str (const char *str, int *error, int *pos) +{ + struct ccl_token *list, *li; + struct ccl_rpn_node *rpn; + const char *char_pos; + + list = ccl_tokenize (str); +#if 0 + for (li = list; li; li = li->next) + printf ("kind=%d, str='%.*s'\n", li->kind, li->len, li->name); +#endif + rpn = ccl_find (list, error, &char_pos); + if (! *error) + { + pr_tree (rpn); + printf ("\n"); + } + else + { + *pos = char_pos - str; + } +} diff --git a/ccl/cclp.h b/ccl/cclp.h new file mode 100644 index 0000000..d8aa138 --- /dev/null +++ b/ccl/cclp.h @@ -0,0 +1,53 @@ +/* CCL - private header file + * Europagate, 1995 + * + * $Log: cclp.h,v $ + * Revision 1.1 1995/02/13 12:35:20 adam + * First version of CCL. Qualifiers aren't handled yet. + * + */ + +#include "ccl.h" + +#define CCL_TOK_EOL 0 +#define CCL_TOK_TERM 1 +#define CCL_TOK_REL 2 +#define CCL_TOK_EQ 3 +#define CCL_TOK_PROX 4 +#define CCL_TOK_LP 5 +#define CCL_TOK_RP 6 +#define CCL_TOK_COMMA 7 +#define CCL_TOK_AND 8 +#define CCL_TOK_OR 7 +#define CCL_TOK_NOT 9 +#define CCL_TOK_MINUS 10 +#define CCL_TOK_SET 11 + +struct ccl_token { + char kind; + char len; + const char *name; + struct ccl_token *next; + struct ccl_token *prev; +}; + +struct ccl_rpn_attr { + struct ccl_rpn_attr *next; + int name; + int value; +}; + +struct ccl_rpn_node { + enum rpn_node_kind { AND, OR, NOT, TERM, SET, PROX } kind; + union { + struct ccl_rpn_node *p[2]; + struct { + char *term; + struct ccl_rpn_attr *attr_list; + } t; + char *setname; + } u; +}; + +struct ccl_token *ccl_tokenize (const char *command); +void ccl_rpn_delete (struct ccl_rpn_node *rpn); diff --git a/ccl/cclsh.c b/ccl/cclsh.c new file mode 100644 index 0000000..24c4520 --- /dev/null +++ b/ccl/cclsh.c @@ -0,0 +1,62 @@ +/* CCL shell. + * Europagate 1995 + * + * $Log: cclsh.c,v $ + * Revision 1.1 1995/02/13 12:35:21 adam + * First version of CCL. Qualifiers aren't handled yet. + * + */ + +#include +#include + +#include "ccl.h" + +static int debug = 0; +static char *prog; + +int main (int argc, char **argv) +{ + prog = *argv; + while (--argc > 0) + { + ++argv; + if (**++argv == '-') + { + switch (argv[0][1]) + { + case 'd': + debug = 1; + break; + default: + fprintf (stderr, "%s: unknown option '%s'\n", + prog, *argv); + exit (1); + } + } + else + { + fprintf (stderr, "%s: no filenames, please\n", prog); + exit (1); + } + } + while (1) + { + char buf[80]; + int error; + int pos; + printf ("CCLSH>"); fflush (stdout); + if (!fgets (buf, 79, stdin)) + break; + ccl_find_str (buf, &error, &pos); + if (error) + { + printf ("%*s^ - ", 6+pos, " "); + printf ("%s\n", ccl_err_msg (error)); + + } + } + return 0; +} + + diff --git a/ccl/ccltoken.c b/ccl/ccltoken.c new file mode 100644 index 0000000..adbf1f6 --- /dev/null +++ b/ccl/ccltoken.c @@ -0,0 +1,136 @@ +/* CCL - lexical analysis + * Europagate, 1995 + * + * $Log: ccltoken.c,v $ + * Revision 1.1 1995/02/13 12:35:21 adam + * First version of CCL. Qualifiers aren't handled yet. + * + */ + +#include +#include +#include +#include + +#include "cclp.h" + +static int strin (const char *s, const char *cset) +{ + while (*cset) + { + if (*cset++ == *s) + return 1; + } + return 0; +} + +char *ccl_token_and = "and"; +char *ccl_token_or = "or"; +char *ccl_token_not = "not"; +char *ccl_token_set = "set"; + +struct ccl_token *ccl_tokenize (const char *command) +{ + const char *cp = command; + struct ccl_token *first = NULL; + struct ccl_token *last = NULL; + + while (1) + { + while (*cp && strin (cp, " \t\r\n")) + { + cp++; + continue; + } + if (!first) + { + first = last = malloc (sizeof (*first)); + assert (first); + last->prev = NULL; + } + else + { + last->next = malloc (sizeof(*first)); + assert (last->next); + last->next->prev = last; + last = last->next; + } + last->next = NULL; + last->name = cp; + last->len = 1; + switch (*cp++) + { + case '\0': + last->kind = CCL_TOK_EOL; + return first; + case '(': + last->kind = CCL_TOK_LP; + break; + case ')': + last->kind = CCL_TOK_RP; + break; + case ',': + last->kind = CCL_TOK_COMMA; + break; + case '%': + case '!': + last->kind = CCL_TOK_PROX; + while (*cp == '%' || *cp == '!') + { + ++ last->len; + cp++; + } + break; + case '>': + case '<': + case '=': + if (*cp == '=' || *cp == '<' || *cp == '>') + { + cp++; + last->kind = CCL_TOK_REL; + ++ last->len; + } + else if (cp[-1] == '=') + last->kind = CCL_TOK_EQ; + else + last->kind = CCL_TOK_REL; + break; + case '-': + last->kind = CCL_TOK_MINUS; + break; + case '\"': + last->kind = CCL_TOK_TERM; + last->name = cp; + last->len = 0; + while (*cp && *cp != '\"') + { + cp++; + ++ last->len; + } + if (*cp == '\"') + cp++; + break; + default: + while (*cp && !strin (cp, "(),%!><=- \t\n\r")) + { + cp++; + ++ last->len; + } + if (strlen (ccl_token_and)==last->len && + !memcmp (ccl_token_and, last->name, last->len)) + last->kind = CCL_TOK_AND; + else if (strlen (ccl_token_or)==last->len && + !memcmp (ccl_token_or, last->name, last->len)) + last->kind = CCL_TOK_OR; + else if (strlen (ccl_token_not)==last->len && + !memcmp (ccl_token_not, last->name, last->len)) + last->kind = CCL_TOK_NOT; + else if (strlen (ccl_token_set)==last->len && + !memcmp (ccl_token_set, last->name, last->len)) + last->kind = CCL_TOK_SET; + else + last->kind = CCL_TOK_TERM; + } + } + return first; +}