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