Happy new year
[idzebra-moved-to-github.git] / util / xpath.c
1 /* This file is part of the Zebra server.
2    Copyright (C) Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <ctype.h>
28 #include <yaz/nmem.h>
29 #include <zebra_xpath.h>
30
31 static char *get_xp_part (char **strs, NMEM mem, int *literal)
32 {
33     char *cp = *strs;
34     char *str = 0;
35     char *res = 0;
36
37     *literal = 0;
38     while (*cp == ' ')
39         cp++;
40     str = cp;
41     if (strchr("()", *cp))
42         cp++;
43     else if (strchr("><=", *cp))
44     {
45         while (strchr("><=", *cp))
46             cp++;
47     }
48     else if (*cp == '"' || *cp == '\'')
49     {
50         int sep = *cp;
51         str++;
52         cp++;
53         while (*cp && *cp != sep)
54             cp++;
55         res = nmem_malloc(mem, cp - str + 1);
56         if ((cp - str))
57             memcpy (res, str, (cp-str));
58         res[cp-str] = '\0';
59         if (*cp)
60             cp++;
61         *literal = 1;
62     }
63     else
64     {
65         while (*cp && !strchr("><=()]\" ", *cp))
66             cp++;
67     }
68     if (!res)
69     {
70         res = nmem_malloc(mem, cp - str + 1);
71         if ((cp - str))
72             memcpy (res, str, (cp-str));
73         res[cp-str] = '\0';
74     }
75     *strs = cp;
76     return res;
77 }
78
79 static struct xpath_predicate *get_xpath_boolean(char **pr, NMEM mem,
80                                                  char **look, int *literal);
81
82 static struct xpath_predicate *get_xpath_relation(char **pr, NMEM mem,
83                                                   char **look, int *literal)
84 {
85     struct xpath_predicate *res = 0;
86     if (!*literal && !strcmp(*look, "("))
87     {
88         *look = get_xp_part(pr, mem, literal);
89         res = get_xpath_boolean(pr, mem, look, literal);
90         if (!strcmp(*look, ")"))
91             *look = get_xp_part(pr, mem, literal);
92         else
93             res = 0; /* error */
94     }
95     else
96     {
97         res=nmem_malloc(mem, sizeof(struct xpath_predicate));
98         res->which = XPATH_PREDICATE_RELATION;
99         res->u.relation.name = *look;
100
101         *look = get_xp_part(pr, mem, literal);
102         if (*look && !*literal && strchr("><=", **look))
103         {
104             res->u.relation.op = *look;
105
106             *look = get_xp_part(pr, mem, literal);
107             if (!*look)
108                 return 0;  /* error */
109             res->u.relation.value = *look;
110             *look = get_xp_part(pr, mem, literal);
111         }
112         else
113         {
114             res->u.relation.op = "";
115             res->u.relation.value = "";
116         }
117     }
118     return res;
119 }
120
121 static struct xpath_predicate *get_xpath_boolean(char **pr, NMEM mem,
122                                                  char **look, int *literal)
123 {
124     struct xpath_predicate *left = 0;
125
126     left = get_xpath_relation(pr, mem, look, literal);
127     if (!left)
128         return 0;
129
130     while (*look && !*literal &&
131            (!strcmp(*look, "and") || !strcmp(*look, "or") ||
132             !strcmp(*look, "not")))
133     {
134         struct xpath_predicate *res, *right;
135
136         res = nmem_malloc(mem, sizeof(struct xpath_predicate));
137         res->which = XPATH_PREDICATE_BOOLEAN;
138         res->u.boolean.op = *look;
139         res->u.boolean.left = left;
140
141         *look = get_xp_part(pr, mem, literal); /* skip the boolean name */
142         right = get_xpath_relation(pr, mem, look, literal);
143
144         res->u.boolean.right = right;
145
146         left = res;
147     }
148     return left;
149 }
150
151 static struct xpath_predicate *get_xpath_predicate(char *predicate, NMEM mem)
152 {
153     int literal;
154     char **pr = &predicate;
155     char *look = get_xp_part(pr, mem, &literal);
156
157     if (!look)
158         return 0;
159     return get_xpath_boolean(pr, mem, &look, &literal);
160 }
161
162 int zebra_parse_xpath_str(const char *xpath_string,
163                           struct xpath_location_step *xpath, int max, NMEM mem)
164 {
165     const char *cp;
166     char *a;
167
168     int no = 0;
169
170     if (!xpath_string || *xpath_string != '/')
171         return -1;
172     cp = xpath_string;
173
174     while (*cp && no < max)
175     {
176         int i = 0;
177         while (*cp && !strchr("/[",*cp))
178         {
179             i++;
180             cp++;
181         }
182         xpath[no].predicate = 0;
183         xpath[no].part = nmem_malloc (mem, i+1);
184         if (i)
185             memcpy (xpath[no].part,  cp - i, i);
186         xpath[no].part[i] = 0;
187
188         if (*cp == '[')
189         {
190             cp++;
191             while (*cp == ' ')
192                 cp++;
193
194             a = (char *)cp;
195             xpath[no].predicate = get_xpath_predicate(a, mem);
196             while(*cp && *cp != ']') {
197               cp++;
198             }
199             if (*cp == ']')
200                 cp++;
201         } /* end of ] predicate */
202         no++;
203         if (*cp != '/')
204             break;
205         cp++;
206     }
207
208 /* for debugging .. */
209 #if 0
210     dump_xp_steps(xpath, no);
211 #endif
212
213     return no;
214 }
215
216 void dump_xp_predicate (struct xpath_predicate *p)
217 {
218     if (p) {
219         if (p->which == XPATH_PREDICATE_RELATION &&
220             p->u.relation.name[0]) {
221             fprintf (stderr, "%s,%s,%s",
222                      p->u.relation.name,
223                      p->u.relation.op,
224                      p->u.relation.value);
225         } else {
226             fprintf (stderr, "(");
227             dump_xp_predicate(p->u.boolean.left);
228             fprintf (stderr, ") %s (", p->u.boolean.op);
229             dump_xp_predicate(p->u.boolean.right);
230             fprintf (stderr, ")");
231         }
232     }
233 }
234
235 void dump_xp_steps (struct xpath_location_step *xpath, int no)
236 {
237     int i;
238     for (i=0; i<no; i++) {
239         fprintf (stderr, "Step %d: %s   ",i,xpath[i].part);
240         dump_xp_predicate(xpath[i].predicate);
241         fprintf (stderr, "\n");
242     }
243 }
244
245 /*
246  * Local variables:
247  * c-basic-offset: 4
248  * c-file-style: "Stroustrup"
249  * indent-tabs-mode: nil
250  * End:
251  * vim: shiftwidth=4 tabstop=8 expandtab
252  */
253