Moved matchstr to global util
[yaz-moved-to-github.git] / retrieval / d1_marc.c
1 /*
2  * Copyright (c) 1995, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: d1_marc.c,v $
7  * Revision 1.3  1995-11-01 16:34:57  quinn
8  * Making data1 look for tables in data1_tabpath
9  *
10  * Revision 1.2  1995/11/01  13:54:48  quinn
11  * Minor adjustments
12  *
13  * Revision 1.1  1995/11/01  11:56:08  quinn
14  * Added Retrieval (data management) functions en masse.
15  *
16  *
17  */
18
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <oid.h>
25 #include <log.h>
26 #include <readconf.h>
27 #include <xmalloc.h>
28 #include <data1.h>
29 #include <tpath.h>
30
31 #define ISO2709_RS 035
32 #define ISO2709_FS 036
33 #define ISO2709_IDFS 037
34
35 data1_marctab *data1_read_marctab(char *file)
36 {
37     FILE *f;
38     data1_marctab *res = xmalloc(sizeof(*res));
39     char line[512], *argv[50];
40     int argc;
41     
42     if (!(f = yaz_path_fopen(data1_tabpath, file, "r")))
43     {
44         logf(LOG_WARN|LOG_ERRNO, "%s", file);
45         return 0;
46     }
47
48     res->name = 0;
49     res->reference = VAL_NONE;
50     res->next = 0;
51     res->length_data_entry = 4;
52     res->length_starting = 5;
53     res->length_implementation = 0;
54     strcpy(res->future_use, "4");
55
56     strcpy(res->record_status, "n");
57     strcpy(res->implementation_codes, "    ");
58     res->indicator_length = 2;
59     res->identifier_length = 2;
60     strcpy(res->user_systems, "z  ");
61
62     while ((argc = readconf_line(f, line, 512, argv, 50)))
63         if (!strcmp(argv[0], "name"))
64         {
65             if (argc != 2)
66             {
67                 logf(LOG_WARN, "%s: Bad name directive");
68                 continue;
69             }
70             res->name = xmalloc(strlen(argv[1])+1);
71             strcpy(res->name, argv[1]);
72         }
73         else if (!strcmp(argv[0], "reference"))
74         {
75             if (argc != 2)
76             {
77                 logf(LOG_WARN, "%s: Bad name directive");
78                 continue;
79             }
80             if ((res->reference = oid_getvalbyname(argv[1])) == VAL_NONE)
81             {
82                 logf(LOG_WARN, "%s: Unknown tagset ref '%s' in %s", file,
83                     argv[1]);
84                 continue;
85             }
86         }
87         else if (!strcmp(argv[0], "length-data-entry"))
88         {
89             if (argc != 2)
90             {
91                 logf(LOG_WARN, "%s: Bad data-length-entry");
92                 continue;
93             }
94             res->length_data_entry = atoi(argv[1]);
95         }
96         else if (!strcmp(argv[0], "length-starting"))
97         {
98             if (argc != 2)
99             {
100                 logf(LOG_WARN, "%s: Bad length-starting");
101                 continue;
102             }
103             res->length_starting = atoi(argv[1]);
104         }
105         else if (!strcmp(argv[0], "length-implementation"))
106         {
107             if (argc != 2)
108             {
109                 logf(LOG_WARN, "%s: Bad length-implentation");
110                 continue;
111             }
112             res->length_implementation = atoi(argv[1]);
113         }
114         else if (!strcmp(argv[0], "future-use"))
115         {
116             if (argc != 2)
117             {
118                 logf(LOG_WARN, "%s: Bad future-use");
119                 continue;
120             }
121             strncpy(res->future_use, argv[1], 2);
122         }
123         else
124             logf(LOG_WARN, "%s: Bad directive '%s'", file, argv[0]);
125
126     fclose(f);
127     return res;
128 }
129
130 /*
131  * Locate some data under this node. This routine should handle variants
132  * prettily.
133  */
134 static char *get_data(data1_node *n, int *len)
135 {
136     char *r;
137
138     while (n->which != DATA1N_data && n->child)
139         n = n->child;
140     if (n->which != DATA1N_data || n->u.data.what != DATA1I_text)
141     {
142         r = "[Structured/included data]";
143         *len = strlen(r);
144         return r;
145     }
146
147     *len = n->u.data.len;
148     return n->u.data.data;
149 }
150
151 static void memint (char *p, int val, int len)
152 {
153     static char buf[9];
154
155     if (len == 1)
156         *p = val + '0';
157     else
158     {
159         sprintf (buf, "%08d", val);
160         memcpy (p, buf+8-len, len);
161     }
162 }
163
164 static int nodetomarc(data1_marctab *p, data1_node *n, int selected,
165     char **buf, int *size)
166 {
167     int len = 26;
168     int dlen;
169     int base_address = 25;
170     int entry_p, data_p;
171     char *op;
172     data1_node *field, *subf;
173
174     for (field = n->child; field; field = field->next)
175     {
176         if (field->which != DATA1N_tag)
177         {
178             logf(LOG_WARN, "Malformed field composition for marc output.");
179             return -1;
180         }
181         if (selected && !field->u.tag.node_selected)
182             continue;
183         len += 4 + p->length_data_entry + p->length_starting
184             + p->length_implementation;
185         base_address += 3 + p->length_data_entry + p->length_starting
186             + p->length_implementation;
187         if (strncmp(field->u.tag.tag, "00", 2))
188             len += p->indicator_length;      /* this is fairly bogus */
189         for (subf = field->child; subf; subf = subf->next)
190         {
191             if (subf->which != DATA1N_tag)
192             {
193                 logf(LOG_WARN,
194                     "Malformed subfield composition for marc output.");
195                 return -1;
196             }
197             if (strncmp(field->u.tag.tag, "00", 2))
198                 len += p->identifier_length;
199             get_data(subf, &dlen);
200             len += dlen;
201         }
202     }
203
204     if (!*buf)
205         *buf = xmalloc(*size = len);
206     else if (*size <= len)
207         *buf = xrealloc(*buf, *size = len);
208         
209     op = *buf;
210     memint (op, len, 5);
211     memcpy (op+5, p->record_status, 1);
212     memcpy (op+6, p->implementation_codes, 4);
213     memint (op+10, p->indicator_length, 1);
214     memint (op+11, p->identifier_length, 1);
215     memint (op+12, base_address, 5);
216     memcpy (op+17, p->user_systems, 3);
217     memint (op+20, p->length_data_entry, 1);
218     memint (op+21, p->length_starting, 1);
219     memint (op+22, p->length_implementation, 1);
220     memcpy (op+23, p->future_use, 1);
221     
222     entry_p = 24;
223     data_p = base_address;
224
225     for (field = n->child; field; field = field->next)
226     {
227         int data_0 = data_p;
228         if (selected && !field->u.tag.node_selected)
229             continue;
230         if (strncmp(field->u.tag.tag, "00", 2))   /* bogus */
231         {
232             memcpy (op + data_p, "  ", p->indicator_length);
233             data_p += p->indicator_length;
234         }
235         for (subf = field->child; subf; subf = subf->next)
236         {
237             char *data;
238
239             if (strncmp(field->u.tag.tag, "00", 2))
240             {
241                 op[data_p] = ISO2709_IDFS;
242                 memcpy (op + data_p+1, subf->u.tag.tag, p->identifier_length-1);
243                 data_p += p->identifier_length;
244             }
245             data = get_data(subf, &dlen);
246             memcpy (op + data_p, data, dlen);
247             data_p += dlen;
248         }
249         op[data_p++] = ISO2709_FS;
250
251         memcpy (op + entry_p, field->u.tag.tag, 3);
252         entry_p += 3;
253         memint (op + entry_p, data_p - data_0, p->length_data_entry);
254         entry_p += p->length_data_entry;
255         memint (op + entry_p, data_0 - base_address, p->length_starting);
256         entry_p += p->length_starting;
257         entry_p += p->length_implementation;
258     }
259     op[entry_p++] = ISO2709_FS;
260     assert (entry_p == base_address);
261     op[data_p++] = ISO2709_RS;
262     assert (data_p == len);
263     return len;
264 }
265
266 char *data1_nodetomarc(data1_marctab *p, data1_node *n, int selected, int *len)
267 {
268     static char *buf = 0;
269     static int size = 0;
270
271     *len = nodetomarc(p, n, selected, &buf, &size);
272     return buf;
273 }