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