First version of CCL. Qualifiers aren't handled yet.
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 13 Feb 1995 12:35:20 +0000 (12:35 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 13 Feb 1995 12:35:20 +0000 (12:35 +0000)
ccl/Makefile [new file with mode: 0644]
ccl/ccl.h [new file with mode: 0644]
ccl/cclerrms.c [new file with mode: 0644]
ccl/cclfind.c [new file with mode: 0644]
ccl/cclp.h [new file with mode: 0644]
ccl/cclsh.c [new file with mode: 0644]
ccl/ccltoken.c [new file with mode: 0644]

diff --git a/ccl/Makefile b/ccl/Makefile
new file mode 100644 (file)
index 0000000..20984f1
--- /dev/null
@@ -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.tmp >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 (file)
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 (file)
index 0000000..85a4ce6
--- /dev/null
@@ -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 (file)
index 0000000..b663666
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#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 (file)
index 0000000..d8aa138
--- /dev/null
@@ -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 (file)
index 0000000..24c4520
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+
+#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 (file)
index 0000000..adbf1f6
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#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;
+}