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