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