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