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