New MARC utilities. Uses prefix query.
[ir-tcl-moved-to-github.git] / marc.c
1 /*
2  * IR toolkit for tcl/tk
3  * (c) Index Data 1995
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: marc.c,v $
7  * Revision 1.1  1995-05-26 08:54:19  adam
8  * New MARC utilities. Uses prefix query.
9  *
10  */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <ctype.h>
15 #include <assert.h>
16
17 #include "ir-tclp.h"
18
19 #define ISO2709_RS 035
20 #define ISO2709_FS 036
21 #define ISO2709_IDFS 037
22
23 int atoi_n (const char *buf, int len)
24 {
25     int val = 0;
26
27     while (--len >= 0)
28     {
29         if (isdigit (*buf))
30             val = val*10 + (*buf - '0');
31         buf++;
32     }
33     return val;
34 }
35
36 static int marc_compare (const char *f, const char *p)
37 {
38     if (*p == '*')
39         return 0;
40     if (!f)
41         return -*p;
42     for (; *f && *p; f++, p++)
43     {
44         if (*p == '?')
45             continue;
46         if (*p != *f)
47             break;
48     }
49     return *f - *p;
50 }
51
52 FILE *outf = stderr;
53
54 char *ir_tcl_fread_marc (FILE *inf, size_t *size)
55 {
56     char length[5];
57     char *buf;
58
59     if (fread (length, 1, 5, inf) != 5)
60         return NULL;
61     *size = atoi_n (length, 5);
62     if (*size <= 6)
63         return NULL;
64     if (!(buf = malloc (*size+1)))
65         return NULL;
66     if (fread (buf+5, 1, *size-5, inf) != (*size-5))
67     {
68         free (buf);
69         return NULL;
70     }
71     memcpy (buf, length, 5);
72     buf[*size=0] = '\0';
73     return buf;
74 }
75
76 int ir_tcl_get_marc (Tcl_Interp *interp, const char *buf, 
77                      int argc, char **argv)
78 {
79     int entry_p;
80     int record_length;
81     int indicator_length;
82     int identifier_length;
83     int base_address;
84     int length_data_entry;
85     int length_starting;
86     int length_implementation;
87     int mode = 0;
88
89     if (!strcmp (argv[3], "field"))
90         mode = 'f';
91     else if (!strcmp (argv[3], "lines"))
92         mode = 'l';
93     else
94     {
95         Tcl_AppendResult (interp, "Unknown MARC extract mode", NULL);
96         return TCL_ERROR;
97     }
98     record_length = atoi_n (buf, 5);
99     if (record_length < 25)
100     {
101         Tcl_AppendResult (interp, "Not a MARC record", NULL);
102         return TCL_ERROR;
103     }
104     indicator_length = atoi_n (buf+10, 1);
105     identifier_length = atoi_n (buf+11, 1);
106     base_address = atoi_n (buf+12, 4);
107
108     length_data_entry = atoi_n (buf+20, 1);
109     length_starting = atoi_n (buf+21, 1);
110     length_implementation = atoi_n (buf+22, 1);
111
112     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
113         entry_p += 3+length_data_entry+length_starting;
114     base_address = entry_p+1;
115     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
116     {
117         int data_length;
118         int data_offset;
119         int end_offset;
120         int i, j;
121         char tag[4];
122         char indicator[128];
123         char identifier[128];
124
125         memcpy (tag, buf+entry_p, 3);
126         entry_p += 3;
127         tag[3] = '\0';
128         data_length = atoi_n (buf+entry_p, length_data_entry);
129         entry_p += length_data_entry;
130         data_offset = atoi_n (buf+entry_p, length_starting);
131         entry_p += length_starting;
132         i = data_offset + base_address;
133         end_offset = i+data_length-1;
134         *indicator = '\0';
135         if (memcmp (tag, "00", 2) && indicator_length)
136         {
137             for (j = 0; j<indicator_length; j++)
138                 indicator[j] = buf[i++];
139             indicator[j] = '\0';
140         }
141         if (marc_compare (tag, argv[4]) || marc_compare (indicator, argv[5]))
142             continue;
143         while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
144         {
145             if (memcmp (tag, "00", 2) && identifier_length)
146             {
147                 int i0;
148                 i++;
149                 for (j = 1; j<identifier_length; j++)
150                     identifier[j-1] = buf[i++];
151                 identifier[j-1] = '\0';
152                 for (i0 = i; buf[i] != ISO2709_RS && 
153                              buf[i] != ISO2709_IDFS &&
154                              buf[i] != ISO2709_FS && i < end_offset; 
155                              i++)
156                     ;
157                 if (marc_compare (identifier, argv[6])==0)
158                 {
159                     char *data = malloc (i-i0+1);
160
161                     memcpy (data, buf+i0, i-i0);
162                     data[i-i0] = '\0';
163                     Tcl_AppendElement (interp, data);
164                     free (data);
165                 }
166             }
167             else
168             {
169                 int i0;
170
171                 for (i0 = i; buf[i] != ISO2709_RS && 
172                              buf[i] != ISO2709_FS && i < end_offset; 
173                              i++)
174                     ;
175                 if (marc_compare (NULL, argv[6])==0)
176                 {
177                     char *data = malloc (i-i0+1);
178
179                     memcpy (data, buf+i0, i-i0);
180                     data[i-i0] = '\0';
181                     Tcl_AppendElement (interp, data);
182                     free (data);
183                 }
184
185             }
186         }
187         if (i < end_offset)
188             fprintf (outf, "-- separator but not at end of field\n");
189         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
190             fprintf (outf, "-- no separator at end of field\n");
191     }
192     return TCL_OK;
193 }
194
195 #if 0
196 int ir_tcl_get_marc_fields(Tcl_Interp *interp, const char *buf,
197                            size_t size, int argc, char **argv)
198 {
199     Iso2709Anchor a;
200     char *data;
201
202     if (!rec)
203         return TCL_OK;
204     a = iso2709_a_mk (rec);
205     while (iso2709_a_search (a, argv[4], argv[5], argv[6]))
206     {
207         if (!(iso2709_a_info_field (a, NULL, NULL, NULL, &data)))
208             break;
209         Tcl_AppendElement (interp, data);
210         iso2709_a_next (a);
211     }
212     iso2709_a_rm (a);
213     return TCL_OK;
214 }
215
216 int ir_tcl_get_marc_lines(Tcl_Interp *interp, const char *buf,
217                           size_t size, int argc, char **argv)
218 {
219     Iso2709Anchor a;
220     char *tag;
221     char *indicator;
222     char *identifier;
223     char *data;
224     char *ptag = "";
225     
226     if (!rec)
227         return TCL_OK;
228     a = iso2709_a_mk (rec);
229     while (iso2709_a_search (a, argv[4], argv[5], argv[6]))
230     {
231         if (!(iso2709_a_info_field (a, &tag, &indicator, &identifier, &data)))
232             break;
233         if (strcmp (tag, ptag))
234         {
235             if (*ptag)
236                 Tcl_AppendResult (interp, "}} ", NULL);
237             if (!indicator)
238                 Tcl_AppendResult (interp, "{", tag, " {} {", NULL);
239             else
240                 Tcl_AppendResult (interp, "{", tag, " {", indicator, 
241                                   "} {", NULL);
242             ptag = tag;
243         }
244         if (!identifier)
245             Tcl_AppendResult (interp, "{{}", NULL);
246         else
247             Tcl_AppendResult (interp, "{", identifier, NULL);
248         Tcl_AppendElement (interp, data);
249         Tcl_AppendResult (interp, "} ", NULL);
250         iso2709_a_next (a);
251     }
252     if (*ptag)
253         Tcl_AppendResult (interp, "}} ", NULL);
254     iso2709_a_rm (a);
255     return TCL_OK;
256 }
257 #endif