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