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