Fix sample PQF
[yaz-moved-to-github.git] / ccl / ccltoken.c
index cfdc8d1..31a18d8 100644 (file)
@@ -1,9 +1,70 @@
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ *    University College Dublin
+ *    Danmarks Teknologiske Videnscenter
+ *    An Chomhairle Leabharlanna
+ *    Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ * 
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
 /* CCL - lexical analysis
  * Europagate, 1995
  *
- * $Log: ccltoken.c,v $
- * Revision 1.1  1995-04-10 10:28:22  quinn
- * Added copy of CCL.
+ * $Id: ccltoken.c,v 1.22 2003-02-14 18:49:23 adam Exp $
+ *
+ * Old Europagate Log:
+ *
+ * Revision 1.10  1995/07/11  12:28:31  adam
+ * New function: ccl_token_simple (split into simple tokens) and
+ *  ccl_token_del (delete tokens).
+ *
+ * Revision 1.9  1995/05/16  09:39:28  adam
+ * LICENSE.
+ *
+ * Revision 1.8  1995/05/11  14:03:57  adam
+ * Changes in the reading of qualifier(s). New function: ccl_qual_fitem.
+ * New variable ccl_case_sensitive, which controls whether reserved
+ * words and field names are case sensitive or not.
+ *
+ * Revision 1.7  1995/04/19  12:11:24  adam
+ * Minor change.
+ *
+ * Revision 1.6  1995/04/17  09:31:48  adam
+ * Improved handling of qualifiers. Aliases or reserved words.
  *
  * Revision 1.5  1995/02/23  08:32:00  adam
  * Changed header.
  *
  */
 
-#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <assert.h>
+#include <ctype.h>
 
-#include <ccl.h>
+#include <yaz/ccl.h>
 
-static int strin (const char *s, const char *cset)
+/*
+ * token_cmp: Compare token with keyword(s)
+ * kw:     Keyword list. Each keyword is separated by space.
+ * token:  CCL token.
+ * return: 1 if token string matches one of the keywords in list;
+ *         0 otherwise.
+ */
+static int token_cmp (CCL_parser cclp, const char *kw, struct ccl_token *token)
 {
-    while (*cset)
+    const char *cp1 = kw;
+    const char *cp2;
+    const char *aliases;
+    int case_sensitive = cclp->ccl_case_sensitive;
+
+    aliases = ccl_qual_search_special(cclp->bibset, "case");
+    if (aliases)
+       case_sensitive = atoi(aliases);
+    if (!kw)
+        return 0;
+    while ((cp2 = strchr (cp1, ' ')))
     {
-       if (*cset++ == *s)
-           return 1;
+        if (token->len == (size_t) (cp2-cp1))
+        {
+            if (case_sensitive)
+            {
+                if (!memcmp (cp1, token->name, token->len))
+                    return 1;
+            }
+            else
+            {
+                if (!ccl_memicmp (cp1, token->name, token->len))
+                    return 1;
+            }
+        }
+       cp1 = cp2+1;
     }
-    return 0;
+    if (case_sensitive)
+        return token->len == strlen(cp1) 
+            && !memcmp (cp1, token->name, token->len);
+    return token->len == strlen(cp1) &&
+        !ccl_memicmp (cp1, token->name, token->len);
 }
 
-const char *ccl_token_and = "and";
-const char *ccl_token_or = "or";
-const char *ccl_token_not = "not";
-const char *ccl_token_set = "set";
+/*
+ * ccl_token_simple: tokenize CCL raw tokens
+ */
+struct ccl_token *ccl_token_simple (const char *command)
+{
+    const char *cp = command;
+    struct ccl_token *first = NULL;
+    struct ccl_token *last = NULL;
 
-struct ccl_token *ccl_tokenize (const char *command)
+    while (1)
+    {
+       while (*cp && strchr (" \t\r\n", *cp))
+       {
+           cp++;
+           continue;
+       }
+       if (!first)
+       {
+           first = last = (struct ccl_token *)xmalloc (sizeof (*first));
+           ccl_assert (first);
+           last->prev = NULL;
+       }
+       else
+       {
+           last->next = (struct ccl_token *)xmalloc (sizeof(*first));
+           ccl_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_TERM;
+           last->name = cp;
+           last->len = 0;
+           while (*cp && *cp != '\"')
+           {
+               cp++;
+               ++ last->len;
+           }
+           if (*cp == '\"')
+               cp++;
+           break;
+       default:
+           while (*cp && !strchr (" \t\n\r", *cp))
+           {
+               cp++;
+               ++ last->len;
+           }
+            last->kind = CCL_TOK_TERM;
+       }
+    }
+    return first;
+}
+
+
+/*
+ * ccl_tokenize: tokenize CCL command string.
+ * return: CCL token list.
+ */
+struct ccl_token *ccl_parser_tokenize (CCL_parser cclp, const char *command)
 {
+    const char *aliases;
     const char *cp = command;
     struct ccl_token *first = NULL;
     struct ccl_token *last = NULL;
 
     while (1)
     {
-       while (*cp && strin (cp, " \t\r\n"))
+       while (*cp && strchr (" \t\r\n", *cp))
        {
            cp++;
            continue;
        }
        if (!first)
        {
-           first = last = malloc (sizeof (*first));
-           assert (first);
+           first = last = (struct ccl_token *)xmalloc (sizeof (*first));
+           ccl_assert (first);
            last->prev = NULL;
        }
        else
        {
-           last->next = malloc (sizeof(*first));
-           assert (last->next);
+           last->next = (struct ccl_token *)xmalloc (sizeof(*first));
+           ccl_assert (last->next);
            last->next->prev = last;
            last = last->next;
        }
@@ -90,7 +245,7 @@ struct ccl_token *ccl_tokenize (const char *command)
        case '%':
        case '!':
            last->kind = CCL_TOK_PROX;
-           while (*cp == '%' || *cp == '!')
+            while (isdigit(*cp))
            {
                ++ last->len;
                cp++;
@@ -110,9 +265,6 @@ struct ccl_token *ccl_tokenize (const char *command)
            else
                last->kind = CCL_TOK_REL;
            break;
-       case '-':
-           last->kind = CCL_TOK_MINUS;
-           break;
        case '\"':
            last->kind = CCL_TOK_TERM;
            last->name = cp;
@@ -126,26 +278,149 @@ struct ccl_token *ccl_tokenize (const char *command)
                cp++;
            break;
        default:
-           while (*cp && !strin (cp, "(),%!><=- \t\n\r"))
+           if (!strchr ("(),%!><= \t\n\r", cp[-1]))
            {
-               cp++;
-               ++ last->len;
+               while (*cp && !strchr ("(),%!><= \t\n\r", *cp))
+               {
+                   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;
+           last->kind = CCL_TOK_TERM;
+
+           aliases = ccl_qual_search_special(cclp->bibset, "and");
+           if (!aliases)
+               aliases = cclp->ccl_token_and;
+           if (token_cmp (cclp, aliases, last))
+               last->kind = CCL_TOK_AND;
+
+           aliases = ccl_qual_search_special(cclp->bibset, "or");
+           if (!aliases)
+               aliases = cclp->ccl_token_or;
+           if (token_cmp (cclp, aliases, last))
+               last->kind = CCL_TOK_OR;
+
+           aliases = ccl_qual_search_special(cclp->bibset, "not");
+           if (!aliases)
+               aliases = cclp->ccl_token_not;
+            if (token_cmp (cclp, aliases, last))
+               last->kind = CCL_TOK_NOT;
+
+           aliases = ccl_qual_search_special(cclp->bibset, "set");
+           if (!aliases)
+               aliases = cclp->ccl_token_set;
+
+           if (token_cmp (cclp, aliases, last))
+               last->kind = CCL_TOK_SET;
        }
     }
     return first;
 }
+
+struct ccl_token *ccl_tokenize (const char *command)
+{
+    CCL_parser cclp = ccl_parser_create ();
+    struct ccl_token *list;
+
+    list = ccl_parser_tokenize (cclp, command);
+
+    ccl_parser_destroy (cclp);
+    return list;
+}
+
+/*
+ * ccl_token_del: delete CCL tokens
+ */
+void ccl_token_del (struct ccl_token *list)
+{
+    struct ccl_token *list1;
+
+    while (list) 
+    {
+        list1 = list->next;
+        xfree (list);
+        list = list1;
+    }
+}
+
+char *ccl_strdup (const char *str)
+{
+    int len = strlen(str);
+    char *p = (char*) xmalloc (len+1);
+    strcpy (p, str);
+    return p;
+}
+
+CCL_parser ccl_parser_create (void)
+{
+    CCL_parser p = (CCL_parser)xmalloc (sizeof(*p));
+    if (!p)
+       return p;
+    p->look_token = NULL;
+    p->error_code = 0;
+    p->error_pos = NULL;
+    p->bibset = NULL;
+
+    p->ccl_token_and = ccl_strdup("and");
+    p->ccl_token_or = ccl_strdup("or");
+    p->ccl_token_not = ccl_strdup("not andnot");
+    p->ccl_token_set = ccl_strdup("set");
+    p->ccl_case_sensitive = 1;
+
+    return p;
+}
+
+void ccl_parser_destroy (CCL_parser p)
+{
+    if (!p)
+       return;
+    xfree (p->ccl_token_and);
+    xfree (p->ccl_token_or);
+    xfree (p->ccl_token_not);
+    xfree (p->ccl_token_set);
+    xfree (p);
+}
+
+void ccl_parser_set_op_and (CCL_parser p, const char *op)
+{
+    if (p && op)
+    {
+       if (p->ccl_token_and)
+           xfree (p->ccl_token_and);
+       p->ccl_token_and = ccl_strdup (op);
+    }
+}
+
+void ccl_parser_set_op_or (CCL_parser p, const char *op)
+{
+    if (p && op)
+    {
+       if (p->ccl_token_or)
+           xfree (p->ccl_token_or);
+       p->ccl_token_or = ccl_strdup (op);
+    }
+}
+void ccl_parser_set_op_not (CCL_parser p, const char *op)
+{
+    if (p && op)
+    {
+       if (p->ccl_token_not)
+           xfree (p->ccl_token_not);
+       p->ccl_token_not = ccl_strdup (op);
+    }
+}
+void ccl_parser_set_op_set (CCL_parser p, const char *op)
+{
+    if (p && op)
+    {
+       if (p->ccl_token_set)
+           xfree (p->ccl_token_set);
+       p->ccl_token_set = ccl_strdup (op);
+    }
+}
+
+void ccl_parser_set_case (CCL_parser p, int case_sensitivity_flag)
+{
+    if (p)
+       p->ccl_case_sensitive = case_sensitivity_flag;
+}