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