Allow range to be specified in termlist, e.g. title:w:range(data,2,4)
[idzebra-moved-to-github.git] / data1 / d1_if.c
1 /* $Id: d1_if.c,v 1.2 2002-10-22 13:19:50 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <data1.h>
29 #include <yaz/log.h>
30
31 #include <string.h>
32
33
34 /*
35  * Search for a token in the supplied string up to the supplied list of stop characters or EOL
36  * At the end, return the character causing the break and fill pTokenBuffer with the token string so far
37  * After the scan, *pPosInBuffer will point to the next character after the one causing the break and
38  *                 pTokenBuffer will contain the actual token
39  */
40 char data1_ScanNextToken(char* pBuffer,
41                          char** pPosInBuffer,
42                          char* pBreakChars,
43                          char* pWhitespaceChars,
44                          char* pTokenBuffer)
45 {
46     char* pBuff = pTokenBuffer;
47     *pBuff = '\0';
48
49     while ( **pPosInBuffer )
50     {
51         if ( strchr(pBreakChars,**pPosInBuffer) != NULL )
52         {
53             /* Current character is a break character */
54             *pBuff++ = '\0';
55             return *((*pPosInBuffer)++);
56         }
57         else
58         {
59             if ( strchr(pWhitespaceChars, **pPosInBuffer) != NULL )
60                 (*pPosInBuffer)++;
61             else
62                 *pBuff++ = *((*pPosInBuffer)++);
63         }
64     }
65
66     *pBuff++ = *((*pPosInBuffer)++);
67     return(**pPosInBuffer);
68 }
69
70 /* 
71  * Attempt to find a string value given the specified tagpath
72  * 
73  * Need to make this safe by passing in a buffer..... 
74  *
75  */
76 char *data1_getNodeValue(data1_node* node, char* pTagPath)
77 {
78     data1_node* n = NULL;
79
80     n = data1_LookupNode(node, pTagPath );
81
82     if ( n )
83     {
84         /* n should be a tag node with some data under it.... */
85         if ( n->child )
86         {
87             if ( n->child->which == DATA1N_data )
88             {
89                 return n->child->u.data.data;
90             }
91             else
92             {
93                 yaz_log(LOG_WARN,"Attempting to lookup data for tagpath: Child node is not a data node");
94             }
95         }
96         else
97         {
98             yaz_log(LOG_WARN,"Found a node matching the tagpath, but it has no child data nodes");
99         }
100     }
101     else
102     {
103         yaz_log(LOG_WARN,"Unable to lookup a node on the specified tag path");
104     }
105
106     return "";
107 }
108
109
110 /* Max length of a tag */
111 #define MAX_TAG_SIZE 50
112
113 /* 
114  * data1_LookupNode : Try and find a node as specified by a tagpath
115  */
116 data1_node *data1_LookupNode(data1_node* node, char* pTagPath)
117 {
118     /* Node matching the pattern in the tagpath */
119     data1_node* matched_node = NULL;
120
121     /* Current Child node as we search for nodes matching the pattern in the tagpath */
122     data1_node* current_child = node->child;
123
124     /* Current position in string */
125     char* pCurrCharInPath = pTagPath;
126
127     /* Work buffer */
128     char Buffer[MAX_TAG_SIZE];
129
130     /* The tag type of this node */
131     int iTagType = 0;
132
133     /* for non string tags, the tag value */
134     int iTagValue = 0;
135
136     /* for string tags, the tag value */
137     char StringTagVal[MAX_TAG_SIZE];
138
139     /* Which occurence of that tag under this node */
140     int iOccurences=0;
141
142     /* Character causing a break */
143     char sepchr = '\0';
144     Buffer[0] = '\0';
145     StringTagVal[0] = '\0';
146
147     sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ",[(."," ", Buffer);
148
149     if ( sepchr == '[' )
150     {
151         /* Next component in node value is [ TagType, TagVal, TagOccurence ] */
152         sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ","," ", Buffer);
153         iTagType = atoi(Buffer);
154
155         /* Occurence is optional... */
156         sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ",]."," ", Buffer);
157
158         if ( iTagType == 3 )
159             strcpy(StringTagVal,Buffer);
160         else
161             iTagValue = atoi(Buffer);
162
163         /* If sepchar was a ',' there should be an instance */
164         if ( sepchr == ',' )
165         {
166             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "]."," ", Buffer);
167             iOccurences = atoi(Buffer);
168         }
169
170         if ( sepchr == ']' )
171         {
172             /* See if we can scan the . for the next component or the end of the line... */
173             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "."," ", Buffer);
174         }
175         else
176         {
177             yaz_log(LOG_FATAL,"Node does not end with a ]");
178             /* Fatal Error */
179             return(NULL);
180         }
181     }
182     else
183     {
184         /* We have a TagName so Read up to ( or . or EOL */
185         iTagType = 3;
186         strcpy(StringTagVal,Buffer);
187
188         if ( sepchr == '(' )
189         {
190             /* Read the occurence */
191             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ")"," ", Buffer);
192             iOccurences = atoi(Buffer);
193
194             /* See if we can find the . at the end of this clause */
195             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "."," ", Buffer);
196         }
197         
198     }
199
200     yaz_log(LOG_DEBUG,"search node for child like [%d,%d,%s,%d]",iTagType,iTagValue,StringTagVal,iOccurences);
201     
202
203     /* OK.. We have extracted tagtype, Value and Occurence, see if we can find a node */
204     /* Under the current parent matching that description                             */
205
206     while ( ( current_child ) && ( matched_node == NULL ) )
207     {
208         if ( current_child->which == DATA1N_tag )
209         {
210             if ( iTagType == 3 )
211             {
212                 if ( ( current_child->u.tag.element == NULL ) &&
213                      ( strcmp(current_child->u.tag.tag, StringTagVal) == 0 ) )
214                 {
215                     if ( iOccurences )
216                     {
217                         /* Everything matched, but not yet found the
218                            right occurence of the given tag */
219                         iOccurences--;
220                     }
221                     else
222                     {
223                         /* We have matched a string tag... Is there more to
224                            process? */
225                         matched_node = current_child;
226                     }
227                 }
228             }
229             else /* Attempt to match real element */
230             {
231                 yaz_log(LOG_WARN,"Non string tag matching not yet implemented");
232             }
233         }
234         current_child = current_child->next;
235     }
236
237
238     /* If there is more... Continue */
239     if ( ( sepchr == '.' ) && ( matched_node ) )
240     {
241         return data1_LookupNode(matched_node, pCurrCharInPath);
242     }
243     else
244     {
245         return matched_node;
246     }
247 }
248
249 /**
250
251 data1_CountOccurences
252
253 Count the number of occurences of the last instance on a tagpath.
254
255 @param data1_node* node : The root of the tree we wish to look for occurences in
256 @param const char* pTagPath : The tagpath we want to count the occurences of... 
257
258 */
259 int data1_CountOccurences(data1_node* node, char* pTagPath)
260 {
261     int iRetVal = 0;
262     data1_node* n = NULL;
263     data1_node* pParent = NULL;
264
265     n = data1_LookupNode(node, pTagPath );
266
267
268     if ( ( n ) &&
269          ( n->which == DATA1N_tag ) &&
270          ( n->parent ) )
271     {
272         data1_node* current_child;
273         pParent = n->parent;
274
275         for ( current_child = pParent->child;
276               current_child;
277               current_child = current_child->next )
278         {
279             if ( current_child->which == DATA1N_tag )
280             {
281                 if ( current_child->u.tag.element == NULL )
282                 {
283                     if ( ( n->u.tag.tag ) &&
284                          ( current_child->u.tag.tag ) &&
285                          ( strcmp(current_child->u.tag.tag, n->u.tag.tag) == 0 ) )
286                     {
287                         iRetVal++;
288                     }
289                 }
290                 else if ( current_child->u.tag.element == n->u.tag.element )
291                 {
292                     /* Hmmm... Is the above right for non string tags???? */
293                     iRetVal++;
294                 }
295             }
296         }
297     }
298
299     return iRetVal;
300 }