Allow YAZ 2 series only
[ir-tcl-moved-to-github.git] / grs.c
1 /*
2  * IR toolkit for tcl/tk
3  * (c) Index Data 1995-1997
4  * See the file LICENSE for details.
5  * Sebastian Hammer, Adam Dickmeiss
6  *
7  * $Log: grs.c,v $
8  * Revision 1.11  1997-11-19 11:22:09  adam
9  * Object identifiers can be accessed in GRS-1 records.
10  *
11  * Revision 1.10  1997/09/09 10:19:52  adam
12  * New MSV5.0 port with fewer warnings.
13  *
14  * Revision 1.9  1996/08/16 15:07:44  adam
15  * First work on Explain.
16  *
17  * Revision 1.8  1996/07/03  13:31:10  adam
18  * The xmalloc/xfree functions from YAZ are used to manage memory.
19  *
20  * Revision 1.7  1996/06/05  09:26:20  adam
21  * Bug fix: the change above introduced an error.
22  *
23  * Revision 1.6  1996/06/05  08:59:23  adam
24  * Changed syntax of element specs in GRS-1 retrieval.
25  *
26  * Revision 1.5  1996/05/29  20:28:08  adam
27  * Bug fix: Function ir_tcl_grs_del sometimes free'd bad memory.
28  *
29  * Revision 1.4  1996/05/29  06:37:42  adam
30  * Function ir_tcl_get_grs_r enhanced so that specific elements can be
31  * extracted.
32  *
33  * Revision 1.3  1996/03/05 09:21:01  adam
34  * Bug fix: memory used by GRS records wasn't freed.
35  * Rewrote some of the error handling code - the connection is always
36  * closed before failback is called.
37  * If failback is defined the send APDU methods (init, search, ...) will
38  * return OK but invoke failback (as is the case if the write operation
39  * fails).
40  * Bug fix: ref_count in assoc object could grow if fraction of PDU was
41  * read.
42  *
43  * Revision 1.2  1995/09/20  11:37:01  adam
44  * Configure searches for tk4.1 and tk7.5.
45  * Work on GRS.
46  *
47  * Revision 1.1  1995/08/29  15:38:34  adam
48  * Added grs.c. new version.
49  *
50  */
51
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <ctype.h>
55 #include <assert.h>
56
57 #include "ir-tclp.h"
58
59 void ir_tcl_grs_del (IrTcl_GRS_Record **grs_record)
60 {
61     struct GRS_Record_entry *e;
62     int i;
63
64     while (!*grs_record)
65         return;
66     e = (*grs_record)->entries;
67     for (i = 0; i < (*grs_record)->noTags; i++, e++)
68     {
69         switch (e->tagWhich)
70         {
71         case Z_StringOrNumeric_numeric:
72             break;
73         default:
74             xfree (e->tagVal.str);
75         }
76         switch (e->dataWhich)
77         {
78         case Z_ElementData_octets:
79             xfree (e->tagData.octets.buf);
80             break;
81         case Z_ElementData_numeric:
82             break;
83         case Z_ElementData_date:
84             xfree (e->tagData.str);
85             break;            
86         case Z_ElementData_ext:
87             break;
88         case Z_ElementData_string:
89             xfree (e->tagData.str);
90             break;
91         case Z_ElementData_trueOrFalse:
92         case Z_ElementData_oid:
93             xfree (e->tagData.oid);
94             break;
95         case Z_ElementData_intUnit:
96         case Z_ElementData_elementNotThere:
97         case Z_ElementData_elementEmpty:
98         case Z_ElementData_noDataRequested:
99         case Z_ElementData_diagnostic:
100             break;
101         case Z_ElementData_subtree:
102             ir_tcl_grs_del (&e->tagData.sub);
103             break;
104         }
105     }
106     xfree ((*grs_record)->entries);
107     xfree (*grs_record);
108     *grs_record = NULL;
109 }
110
111 void ir_tcl_grs_mk (Z_GenericRecord *r, IrTcl_GRS_Record **grs_record)
112 {
113     int i;
114     struct GRS_Record_entry *e;
115
116     *grs_record = NULL;
117     if (!r)
118         return;
119     *grs_record = ir_tcl_malloc (sizeof(**grs_record));
120     if (!((*grs_record)->noTags = r->num_elements))
121     {
122         (*grs_record)->entries = NULL;
123         return;
124     }
125     e = (*grs_record)->entries = ir_tcl_malloc (r->num_elements *
126                                                 sizeof(*e));
127     for (i = 0; i < r->num_elements; i++, e++)
128     {
129         Z_TaggedElement *t;
130         int len;
131
132         t = r->elements[i];
133         if (t->tagType)
134             e->tagType = *t->tagType;
135         else
136             e->tagType = 0;
137         e->tagWhich = t->tagValue->which;
138         if (t->tagValue->which == Z_StringOrNumeric_numeric)
139             e->tagVal.num = *t->tagValue->u.numeric;
140         else
141             ir_tcl_strdup (NULL, &e->tagVal.str, t->tagValue->u.string);
142         e->dataWhich = t->content->which;
143
144         switch (t->content->which)
145         {
146         case Z_ElementData_octets:
147             e->tagData.octets.len = t->content->u.octets->len;
148             e->tagData.octets.buf = ir_tcl_malloc (t->content->u.octets->len);
149             memcpy (e->tagData.octets.buf, t->content->u.octets->buf, 
150                     t->content->u.octets->len);
151             break;
152         case Z_ElementData_numeric:
153             e->tagData.num = *t->content->u.numeric;
154             break;
155         case Z_ElementData_date:
156             ir_tcl_strdup (NULL, &e->tagData.str, t->content->u.string);
157             break;            
158         case Z_ElementData_ext:
159             break;
160         case Z_ElementData_string:
161             ir_tcl_strdup (NULL, &e->tagData.str, t->content->u.string);
162             break;
163         case Z_ElementData_trueOrFalse:
164             e->tagData.bool = *t->content->u.trueOrFalse;
165             break;
166         case Z_ElementData_oid:
167             len = 1+oid_oidlen (t->content->u.oid);
168             e->tagData.oid = ir_tcl_malloc (len * sizeof(*e->tagData.oid));
169             memcpy (e->tagData.oid, t->content->u.oid,
170                     len * sizeof(*e->tagData.oid));
171             break;
172         case Z_ElementData_intUnit:
173             break;
174         case Z_ElementData_elementNotThere:
175         case Z_ElementData_elementEmpty:
176         case Z_ElementData_noDataRequested:
177             break;
178         case Z_ElementData_diagnostic:
179             break;
180         case Z_ElementData_subtree:
181             ir_tcl_grs_mk (t->content->u.subtree, &e->tagData.sub);
182             break;
183         }
184     }
185 }
186
187 static int ir_tcl_get_grs_r (Tcl_Interp *interp, IrTcl_GRS_Record *grs_record,
188                              int argc, char **argv, int argno)
189 {
190     static char tmpbuf[32];
191     int i;
192     struct GRS_Record_entry *e = grs_record->entries;
193
194     for (i = 0; i<grs_record->noTags; i++, e++)
195     {
196         int yes = 0;
197         if (argno >= argc)
198             yes = 1;
199         else
200         {
201             const char *cp0 = argv[argno];
202             const char *cp1 = strchr (cp0, ',');
203
204             if (!cp1 || cp1-cp0 < 1)
205                 yes = 1;
206             else
207             {
208                 if (*cp0 == '(')
209                     cp0++;
210                 if (atoi(cp0) == e->tagType) 
211                 {
212                     if (e->tagWhich == Z_StringOrNumeric_numeric)
213                     {
214                         if (atoi (cp1+1) == e->tagVal.num)
215                             yes = 1;
216                     }
217                     else
218                     {
219                         size_t len = strlen(cp1+1);
220                         if (cp1[len] == ')')
221                             len--;
222                         if (len && strlen(e->tagVal.str) == len &&
223                             !memcmp (cp1+1, e->tagVal.str, len))
224                             yes = 1;
225                     }
226                 }
227             }
228         }
229         if (!yes)
230             continue;
231         Tcl_AppendResult (interp, "{ ", NULL);
232         sprintf (tmpbuf, "%d", e->tagType);
233         Tcl_AppendElement (interp, tmpbuf);
234
235         if (e->tagWhich == Z_StringOrNumeric_numeric)
236         {
237             Tcl_AppendResult (interp, " numeric ", NULL);
238             sprintf (tmpbuf, "%d", e->tagVal.num);
239             Tcl_AppendElement (interp, tmpbuf);
240         }
241         else
242         {
243             Tcl_AppendResult (interp, " string ", NULL);
244             Tcl_AppendElement (interp, e->tagVal.str);
245         }
246         switch (e->dataWhich)
247         {
248         case Z_ElementData_octets:
249             Tcl_AppendResult (interp, " octets {} ", NULL);
250             break;
251         case Z_ElementData_numeric:
252             Tcl_AppendResult (interp, " numeric ", NULL);
253             sprintf (tmpbuf, "%d", e->tagData.num);
254             Tcl_AppendElement (interp, tmpbuf);
255             break;
256         case Z_ElementData_date:
257             Tcl_AppendResult (interp, " date {} ", NULL);
258             break;
259         case Z_ElementData_ext:
260             Tcl_AppendResult (interp, " ext {} ", NULL);
261             break;
262         case Z_ElementData_string:
263             Tcl_AppendResult (interp, " string ", NULL);
264             Tcl_AppendElement (interp, e->tagData.str);
265             break;
266         case Z_ElementData_trueOrFalse:
267             Tcl_AppendResult (interp, " bool ",
268                               e->tagData.bool ? "1" : "0", " ", NULL);
269             break;
270         case Z_ElementData_oid:
271             Tcl_AppendResult (interp, " oid", NULL);
272             if (!e->tagData.oid)
273                 Tcl_AppendResult (interp, "{}", NULL);
274             else
275             {
276                 int i;
277                 int sep = ' ';
278                 for (i = 0; e->tagData.oid[i] >= 0; i++)
279                 {
280                     sprintf (tmpbuf, "%c%d", sep, e->tagData.oid[i]);
281                     Tcl_AppendResult (interp, tmpbuf, NULL);
282                     sep = '.';
283                 }
284             }
285             break;
286         case Z_ElementData_intUnit:
287             Tcl_AppendResult (interp, " intUnit {} ", NULL);
288             break;
289         case Z_ElementData_elementNotThere:
290             Tcl_AppendResult (interp, " notThere {} ", NULL);
291             break;
292         case Z_ElementData_elementEmpty:
293             Tcl_AppendResult (interp, " empty {} ", NULL);
294             break;
295         case Z_ElementData_noDataRequested:
296             Tcl_AppendResult (interp, " notRequested {} ", NULL);
297             break;
298         case Z_ElementData_diagnostic:
299             Tcl_AppendResult (interp, " diagnostic {} ", NULL);
300             break;
301         case Z_ElementData_subtree:
302             Tcl_AppendResult (interp, " subtree { ", NULL);
303             ir_tcl_get_grs_r (interp, e->tagData.sub, argc, argv, argno+1);
304             Tcl_AppendResult (interp, " } ", NULL);
305             break;
306         }
307         Tcl_AppendResult (interp, " } ", NULL);
308     }
309     return TCL_OK;
310 }
311
312 int ir_tcl_get_grs (Tcl_Interp *interp, IrTcl_GRS_Record *grs_record, 
313                      int argc, char **argv)
314 {
315     return ir_tcl_get_grs_r (interp, grs_record, argc, argv, 3);
316 }
317