Minor change - to prevent warnings.
[yaz-moved-to-github.git] / retrieval / d1_if.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  *
5  * d1_if.c : A simple interface for extracting strings from data1_node tree structures
6  *
7  * $Log: d1_if.c,v $
8  * Revision 1.4  2000-01-06 14:30:56  adam
9  * Minor change - to prevent warnings.
10  *
11  * Revision 1.3  2000/01/06 11:27:02  adam
12  * Minor fix so that this source compiles using Visual C++.
13  *
14  * Revision 1.2  2000/01/04 17:46:17  ian
15  * Added function to count occurences of a tag spec in a data1 tree.
16  *
17  * Revision 1.1  1999/12/21 14:16:19  ian
18  * Changed retrieval module to allow data1 trees with no associated absyn.
19  * Also added a simple interface for extracting values from data1 trees using
20  * a string based tagpath.
21  *
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <yaz/data1.h>
30 #include <yaz/log.h>
31
32 #include <string.h>
33
34
35 /*
36  * Search for a token in the supplied string up to the supplied list of stop characters or EOL
37  * At the end, return the character causing the break and fill pTokenBuffer with the token string so far
38  * After the scan, *pPosInBuffer will point to the next character after the one causing the break and
39  *                 pTokenBuffer will contain the actual token
40  */
41 char data1_ScanNextToken(char* pBuffer,
42                          char** pPosInBuffer,
43                          char* pBreakChars,
44                          char* pWhitespaceChars,
45                          char* pTokenBuffer)
46 {
47     char* pBuff = pTokenBuffer;
48     *pBuff = '\0';
49
50     while ( **pPosInBuffer )
51     {
52         if ( strchr(pBreakChars,**pPosInBuffer) != NULL )
53         {
54             /* Current character is a break character */
55             *pBuff++ = '\0';
56             return *((*pPosInBuffer)++);
57         }
58         else
59         {
60             if ( strchr(pWhitespaceChars, **pPosInBuffer) != NULL )
61                 (*pPosInBuffer)++;
62             else
63                 *pBuff++ = *((*pPosInBuffer)++);
64         }
65     }
66
67     *pBuff++ = *((*pPosInBuffer)++);
68     return(**pPosInBuffer);
69 }
70
71 /* 
72  * Attempt to find a string value given the specified tagpath
73  * 
74  * Need to make this safe by passing in a buffer..... 
75  *
76  */
77 char *data1_getNodeValue(data1_node* node, char* pTagPath)
78 {
79     data1_node* n = NULL;
80
81     n = data1_LookupNode(node, pTagPath );
82
83     if ( n )
84     {
85         /* n should be a tag node with some data under it.... */
86         if ( n->child )
87         {
88             if ( n->child->which == DATA1N_data )
89             {
90                 return n->child->u.data.data;
91             }
92             else
93             {
94                 yaz_log(LOG_WARN,"Attempting to lookup data for tagpath: Child node is not a data node");
95             }
96         }
97         else
98         {
99             yaz_log(LOG_WARN,"Found a node matching the tagpath, but it has no child data nodes");
100         }
101     }
102     else
103     {
104         yaz_log(LOG_WARN,"Unable to lookup a node on the specified tag path");
105     }
106
107     return "";
108 }
109
110
111 /* Max length of a tag */
112 #define MAX_TAG_SIZE 50
113
114 /* 
115  * data1_LookupNode : Try and find a node as specified by a tagpath
116  */
117 data1_node *data1_LookupNode(data1_node* node, char* pTagPath)
118 {
119     /* Node matching the pattern in the tagpath */
120     data1_node* matched_node = NULL;
121
122     /* Current Child node as we search for nodes matching the pattern in the tagpath */
123     data1_node* current_child = node->child;
124
125     /* Current position in string */
126     char* pCurrCharInPath = pTagPath;
127
128     /* Work buffer */
129     char Buffer[MAX_TAG_SIZE];
130
131     /* The tag type of this node */
132     int iTagType = 0;
133
134     /* for non string tags, the tag value */
135     int iTagValue = 0;
136
137     /* for string tags, the tag value */
138     char StringTagVal[MAX_TAG_SIZE];
139
140     /* Which occurence of that tag under this node */
141     int iOccurences=0;
142
143     /* Character causing a break */
144     char sepchr = '\0';
145     Buffer[0] = '\0';
146     StringTagVal[0] = '\0';
147
148     sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ",[(."," ", Buffer);
149
150     if ( sepchr == '[' )
151     {
152         /* Next component in node value is [ TagType, TagVal, TagOccurence ] */
153         sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ","," ", Buffer);
154         iTagType = atoi(Buffer);
155
156         /* Occurence is optional... */
157         sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ",]."," ", Buffer);
158
159         if ( iTagType == 3 )
160             strcpy(StringTagVal,Buffer);
161         else
162             iTagValue = atoi(Buffer);
163
164         /* If sepchar was a ',' there should be an instance */
165         if ( sepchr == ',' )
166         {
167             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "]."," ", Buffer);
168             iOccurences = atoi(Buffer);
169         }
170
171         if ( sepchr == ']' )
172         {
173             /* See if we can scan the . for the next component or the end of the line... */
174             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "."," ", Buffer);
175         }
176         else
177         {
178             yaz_log(LOG_FATAL,"Node does not end with a ]");
179             /* Fatal Error */
180             return(NULL);
181         }
182     }
183     else
184     {
185         /* We have a TagName so Read up to ( or . or EOL */
186         iTagType = 3;
187         strcpy(StringTagVal,Buffer);
188
189         if ( sepchr == '(' )
190         {
191             /* Read the occurence */
192             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ")"," ", Buffer);
193             iOccurences = atoi(Buffer);
194
195             /* See if we can find the . at the end of this clause */
196             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "."," ", Buffer);
197         }
198         
199     }
200
201     yaz_log(LOG_DEBUG,"search node for child like [%d,%d,%s,%d]",iTagType,iTagValue,StringTagVal,iOccurences);
202     
203
204     /* OK.. We have extracted tagtype, Value and Occurence, see if we can find a node */
205     /* Under the current parent matching that description                             */
206
207     while ( ( current_child ) && ( matched_node == NULL ) )
208     {
209         if ( current_child->which == DATA1N_tag )
210         {
211             if ( iTagType == 3 )
212             {
213                 if ( ( current_child->u.tag.element == NULL ) &&
214                      ( strcmp(current_child->u.tag.tag, StringTagVal) == 0 ) )
215                 {
216                     if ( iOccurences )
217                     {
218                         // Everything matched, but not yet found the right occurence of the given tag
219                         iOccurences--;
220                     }
221                     else
222                     {
223                         /* We have matched a string tag... Is there more to process? */
224                         matched_node = current_child;
225                     }
226                 }
227             }
228             else /* Attempt to match real element */
229             {
230                 yaz_log(LOG_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 }