Omit CVS Id. Update copyright year.
[idzebra-moved-to-github.git] / util / xpath.c
index 1155cb1..cea10c7 100644 (file)
@@ -1,8 +1,5 @@
-/* $Id: xpath.c,v 1.1 2003-02-04 12:06:48 pop Exp $
-   Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
-   Index Data Aps
-
-This file is part of the Zebra server.
+/* This file is part of the Zebra server.
+   Copyright (C) 1995-2008 Index Data
 
 Zebra is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -15,9 +12,9 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with Zebra; see the file LICENSE.zebra.  If not, write to the
-Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
 */
 
 
@@ -28,129 +25,150 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include <yaz/nmem.h>
 #include <zebra_xpath.h>
 
-char *get_xp_part (char **strs, NMEM mem) {
-  char *str = *strs;
-  char *res = '\0';
-  char *cp = str;
-  char *co;
-  int quoted = 0;
-
-  /* ugly */
-  char *sep = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\" ";
-
-  while (*cp == ' ') {cp++; str++;}
-  if (!strchr("><=] ", *cp)) sep = "><=] ";
-
-  while (*cp && !(strchr(sep,*cp) && !quoted) && (*cp != ']')) {
-    if (*cp =='"') quoted = 1 - quoted;
-    cp++;
-  }  
-  /* removing leading and trailing " */
-  co = cp;
-  if (*str == '"') str++;
-  if (*(cp-1) == '"') cp--;
-  if (str < co) {
-    res = nmem_malloc(mem, cp - str + 1);
-    memcpy (res, str, (cp-str));
-    *(res + (cp-str)) = '\0';
-    *strs = co;
-  }
-
-  return (res);
+static char *get_xp_part (char **strs, NMEM mem, int *literal)
+{
+    char *cp = *strs;
+    char *str = 0;
+    char *res = 0;
+
+    *literal = 0;
+    while (*cp == ' ')
+        cp++;
+    str = cp;
+    if (strchr("()", *cp))
+        cp++;
+    else if (strchr("><=", *cp))
+    {
+        while (strchr("><=", *cp))
+            cp++;
+    }
+    else if (*cp == '"' || *cp == '\'')
+    {
+        int sep = *cp;
+        str++;
+        cp++;
+        while (*cp && *cp != sep)
+            cp++;
+        res = nmem_malloc(mem, cp - str + 1);
+        if ((cp - str))
+            memcpy (res, str, (cp-str));
+        res[cp-str] = '\0';
+        if (*cp)
+            cp++;
+        *literal = 1;
+    }
+    else
+    {
+        while (*cp && !strchr("><=()]\" ", *cp))
+            cp++;
+    }
+    if (!res)
+    {
+        res = nmem_malloc(mem, cp - str + 1);
+        if ((cp - str))
+            memcpy (res, str, (cp-str));
+        res[cp-str] = '\0';
+    }
+    *strs = cp;
+    return res;
 }
 
+static struct xpath_predicate *get_xpath_boolean(char **pr, NMEM mem,
+                                                 char **look, int *literal);
 
-struct xpath_predicate *get_xpath_predicate(char *predicates, NMEM mem) {
-  char *p1;
-  char *p2;
-  char *p3;
-  char *p4;
-
-  struct xpath_predicate *r1;
-  struct xpath_predicate *r2;
-  struct xpath_predicate *res = 0;
-
-  char *pr = predicates;
-
-  if ((p1 = get_xp_part(&pr, mem))) {
-    if ((p2 = get_xp_part(&pr, mem))) {
-      if (!strcmp (p2, "and") || !strcmp (p2, "or") || !strcmp (p2, "not")) {
-       r1=nmem_malloc(mem, sizeof(struct xpath_predicate));
-       r1->which = XPATH_PREDICATE_RELATION;
-       r1->u.relation.name = p1;
-       r1->u.relation.op = "";
-       r1->u.relation.value = "";
-       
-       r2 = get_xpath_predicate (pr, mem);
-      
-       res = nmem_malloc(mem, sizeof(struct xpath_predicate));
-       res->which = XPATH_PREDICATE_BOOLEAN;
-       res->u.boolean.op = p2;
-       res->u.boolean.left = r1;
-       res->u.boolean.right = r2;
-
-       return (res);
-      }
-
-      if (strchr("><=] ", *p2)) {
-       r1 = nmem_malloc(mem, sizeof(struct xpath_predicate));
-       
-       r1->which = XPATH_PREDICATE_RELATION;
-       r1->u.relation.name = p1;
-       r1->u.relation.op = p2;
-
-       if ((p3 = get_xp_part(&pr, mem))) {
-         r1->u.relation.value = p3;
-       } else {
-         /* error */
-       }
-      }
-      
-      if ((p4 = get_xp_part(&pr, mem))) {
-       if (!strcmp (p4, "and") || !strcmp (p4, "or") || !strcmp (p4, "not")) {
-
-         r2 = get_xpath_predicate (pr, mem);
-
-         res = nmem_malloc(mem, sizeof(struct xpath_predicate));
-         res->which = XPATH_PREDICATE_BOOLEAN;
-         res->u.boolean.op = p4;
-         res->u.boolean.left = r1;
-         res->u.boolean.right = r2;
-         return (res);
-       } else {
-         /* error */
-       }
-      } else {
-       return (r1);
-      }
-         
-    } else {
-       r1 = nmem_malloc(mem, sizeof(struct xpath_predicate));
-       
-       r1->which = XPATH_PREDICATE_RELATION;
-       r1->u.relation.name = p1;
-       r1->u.relation.op = "";
-       r1->u.relation.value = "";
-
-       return (r1);
+static struct xpath_predicate *get_xpath_relation(char **pr, NMEM mem,
+                                                  char **look, int *literal)
+{
+    struct xpath_predicate *res = 0;
+    if (!*literal && !strcmp(*look, "("))
+    {
+        *look = get_xp_part(pr, mem, literal);
+        res = get_xpath_boolean(pr, mem, look, literal);
+        if (!strcmp(*look, ")"))
+            *look = get_xp_part(pr, mem, literal);
+        else
+            res = 0; /* error */
     }
-  }
-  return 0;
+    else
+    {
+        res=nmem_malloc(mem, sizeof(struct xpath_predicate));
+        res->which = XPATH_PREDICATE_RELATION;
+        res->u.relation.name = *look;
+
+        *look = get_xp_part(pr, mem, literal);
+        if (*look && !*literal && strchr("><=", **look))
+        {
+            res->u.relation.op = *look;
+
+            *look = get_xp_part(pr, mem, literal);
+            if (!*look)
+                return 0;  /* error */
+            res->u.relation.value = *look;
+            *look = get_xp_part(pr, mem, literal);
+        }
+        else
+        {
+            res->u.relation.op = "";
+            res->u.relation.value = "";
+        }
+    }
+    return res;
+}
+
+static struct xpath_predicate *get_xpath_boolean(char **pr, NMEM mem,
+                                                 char **look, int *literal)
+{
+    struct xpath_predicate *left = 0;
+    
+    left = get_xpath_relation(pr, mem, look, literal);
+    if (!left)
+        return 0;
+    
+    while (*look && !*literal &&
+           (!strcmp(*look, "and") || !strcmp(*look, "or") || 
+            !strcmp(*look, "not")))
+    {
+        struct xpath_predicate *res, *right;
+
+        res = nmem_malloc(mem, sizeof(struct xpath_predicate));
+        res->which = XPATH_PREDICATE_BOOLEAN;
+        res->u.boolean.op = *look;
+        res->u.boolean.left = left;
+
+        *look = get_xp_part(pr, mem, literal); /* skip the boolean name */
+        right = get_xpath_relation(pr, mem, look, literal);
+
+        res->u.boolean.right = right;
+
+        left = res;
+    }
+    return left;
 }
 
-int parse_xpath_str(const char *xpath_string,
-                   struct xpath_location_step *xpath, NMEM mem)
+static struct xpath_predicate *get_xpath_predicate(char *predicate, NMEM mem)
+{
+    int literal;
+    char **pr = &predicate;
+    char *look = get_xp_part(pr, mem, &literal);
+
+    if (!look)
+        return 0;
+    return get_xpath_boolean(pr, mem, &look, &literal);
+}
+
+int zebra_parse_xpath_str(const char *xpath_string,
+                          struct xpath_location_step *xpath, int max, NMEM mem)
 {
     const char *cp;
     char *a;
-
+    
     int no = 0;
     
     if (!xpath_string || *xpath_string != '/')
         return -1;
     cp = xpath_string;
-
-    while (*cp)
+    
+    while (*cp && no < max)
     {
         int i = 0;
         while (*cp && !strchr("/[",*cp))
@@ -160,7 +178,8 @@ int parse_xpath_str(const char *xpath_string,
         }
         xpath[no].predicate = 0;
         xpath[no].part = nmem_malloc (mem, i+1);
-        memcpy (xpath[no].part,  cp - i, i);
+        if (i)
+            memcpy (xpath[no].part,  cp - i, i);
         xpath[no].part[i] = 0;
 
         if (*cp == '[')
@@ -182,33 +201,49 @@ int parse_xpath_str(const char *xpath_string,
             break;
         cp++;
     }
+
+/* for debugging .. */
+#if 0
+    dump_xp_steps(xpath, no);
+#endif
+
     return no;
 }
 
-void dump_xp_predicate (struct xpath_predicate *p) {
+void dump_xp_predicate (struct xpath_predicate *p)
+{
     if (p) {
-      if (p->which == XPATH_PREDICATE_RELATION &&
-         p->u.relation.name[0]) {
-       fprintf (stderr, "%s,%s,%s", 
-                p->u.relation.name,
-                p->u.relation.op,
-                p->u.relation.value);
-      } else {
-       fprintf (stderr, "(");
-       dump_xp_predicate(p->u.boolean.left);
-       fprintf (stderr, ") %s (", p->u.boolean.op);
-       dump_xp_predicate(p->u.boolean.right);
-       fprintf (stderr, ")");
-      }
+        if (p->which == XPATH_PREDICATE_RELATION &&
+            p->u.relation.name[0]) {
+            fprintf (stderr, "%s,%s,%s", 
+                     p->u.relation.name,
+                     p->u.relation.op,
+                     p->u.relation.value);
+        } else {
+            fprintf (stderr, "(");
+            dump_xp_predicate(p->u.boolean.left);
+            fprintf (stderr, ") %s (", p->u.boolean.op);
+            dump_xp_predicate(p->u.boolean.right);
+            fprintf (stderr, ")");
+        }
     }
 }
 
-void dump_xp_steps (struct xpath_location_step *xpath, int no) {
-  int i;
-  for (i=0; i<no; i++) {
-    fprintf (stderr, "Step %d: %s   ",i,xpath[i].part);
-    dump_xp_predicate(xpath[i].predicate);
-    fprintf (stderr, "\n");
-  }
+void dump_xp_steps (struct xpath_location_step *xpath, int no)
+{
+    int i;
+    for (i=0; i<no; i++) {
+        fprintf (stderr, "Step %d: %s   ",i,xpath[i].part);
+        dump_xp_predicate(xpath[i].predicate);
+        fprintf (stderr, "\n");
+    }
 }
 
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+