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