Run latex
[egate.git] / util / iso2709.c
1 /*
2  * Copyright (c) 1995, the EUROPAGATE consortium (see below).
3  *
4  * The EUROPAGATE consortium members are:
5  *
6  *    University College Dublin
7  *    Danmarks Teknologiske Videnscenter
8  *    An Chomhairle Leabharlanna
9  *    Consejo Superior de Investigaciones Cientificas
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation, in whole or in part, for any purpose, is hereby granted,
13  * provided that:
14  *
15  * 1. This copyright and permission notice appear in all copies of the
16  * software and its documentation. Notices of copyright or attribution
17  * which appear at the beginning of any file must remain unchanged.
18  *
19  * 2. The names of EUROPAGATE or the project partners may not be used to
20  * endorse or promote products derived from this software without specific
21  * prior written permission.
22  *
23  * 3. Users of this software (implementors and gateway operators) agree to
24  * inform the EUROPAGATE consortium of their use of the software. This
25  * information will be used to evaluate the EUROPAGATE project and the
26  * software, and to plan further developments. The consortium may use
27  * the information in later publications.
28  * 
29  * 4. Users of this software agree to make their best efforts, when
30  * documenting their use of the software, to acknowledge the EUROPAGATE
31  * consortium, and the role played by the software in their work.
32  *
33  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
34  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
35  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
36  * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
37  * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
38  * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
39  * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
40  * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
41  * USE OR PERFORMANCE OF THIS SOFTWARE.
42  *
43  */
44 /*
45  * Iso2709 record management
46  *
47  * Europagate, 1994-1995.
48  *
49  * $Log: iso2709.c,v $
50  * Revision 1.17  1995/12/20 16:28:08  adam
51  * Extra parameter block to gw_db_open. If block is 0 gw_db_open
52  * returns NULL if lock couldn't be satisfied.
53  * Minor changes in iso2709.c.
54  *
55  * Revision 1.16  1995/05/16  09:40:53  adam
56  * LICENSE.
57  *
58  * Revision 1.15  1995/03/31  10:42:41  adam
59  * Bug fix.
60  *
61  * Revision 1.14  1995/03/30  14:22:18  adam
62  * More work on new MARC anchor functions.
63  *
64  * Revision 1.13  1995/03/30  07:33:32  adam
65  * New 2709 function: iso2709_mk.
66  * First implementation of iso2709_a_insert.
67  *
68  * Revision 1.12  1995/03/29  16:08:56  adam
69  * Better error recovery when using bad records.
70  *
71  * Revision 1.11  1995/03/28  16:07:07  adam
72  * New function: iso2709_out. This function is the reverse of iso2709_cvt.
73  *
74  * Revision 1.10  1995/03/10  09:10:56  adam
75  * Removed dbc2709_cvt function. Makes heuristic guess for DBC2709 records.
76  *
77  * Revision 1.9  1995/03/08  12:36:39  adam
78  * New function: dbc2709_cvt.
79  *
80  * Revision 1.8  1995/03/08  12:03:15  adam
81  * Hack: When tags 00? are used, every separator (DC[1-3]) marks
82  * the end of the data field.
83  *
84  * Revision 1.7  1995/02/22  21:28:03  adam
85  * Changed header.
86  *
87  * Revision 1.5  1995/02/22  15:24:14  adam
88  * Function iso2709_cvt makes a litte check for the format. It returns
89  * NULL if the buffer parameter can never be a MARC record.
90  *
91  * Revision 1.4  1995/02/15  17:45:44  adam
92  * Bug fix in iso2709 module.
93  *
94  * Revision 1.3  1995/02/10  17:05:18  adam
95  * New function iso2709_display to display MARC records in a
96  * line-by-line format. The iso2709_cvt function no longer
97  * prints the record to stderr.
98  *
99  * Revision 1.2  1995/02/10  16:50:32  adam
100  * Indicator field moved to 'struct iso2709_dir' from 'struct
101  * iso2709_field'.
102  * Function iso2709_rm implemented - to delete a MARC record.
103  *
104  * Revision 1.1.1.1  1995/02/09  17:27:11  adam
105  * Initial version of email gateway under CVS control.
106  *
107  */
108
109 #include <stdlib.h>
110 #include <string.h>
111 #include <stdio.h>
112 #include <assert.h>
113 #include <ctype.h>
114
115 #include <iso2709p.h>
116
117 static int atoin (const char *buf, int n)
118 {
119     int val = 0;
120     while (--n >= 0)
121     {
122         if (isdigit(*buf))
123             val = val*10 + (*buf - '0');
124         buf++;
125     }
126     return val;
127 }
128
129 static void strncpyx (char *d, const char *s, int n)
130 {
131     while (--n >= 0 && *s)
132         if (*s != ISO2709_IDFS)
133             *d++ = *s++;
134         else
135         {
136             *d++ = ' ';
137             s++;
138         }
139     *d = '\0';
140 }
141
142 char *iso2709_read (FILE *inf)
143 {
144     char length_str[5];
145     int size;
146     char *buf;
147
148     if (fread (length_str, 1, 5, inf) != 5)
149         return NULL;
150     size = atoin (length_str, 5);
151     if (size <= 6)
152         return NULL;
153     if (!(buf = malloc (size+1)))
154         return NULL;
155     if (fread (buf+5, 1, size-5, inf) != (size-5))
156     {
157         free (buf);
158         return NULL;
159     }
160     memcpy (buf, length_str, 5);
161     buf[size] = '\0';
162     return buf;
163 }
164
165 Iso2709Rec iso2709_mk (void)
166 {
167     Iso2709Rec p;
168
169     if (!(p = malloc (sizeof(*p))))
170         return NULL;
171
172     p->record_length = 0;
173     strncpyx (p->record_status, " ", 1);
174     strncpyx (p->implementation_codes, "    ", 4);
175     p->indicator_length = 2;
176     p->identifier_length = 2;
177     p->base_address = 0;
178     strncpyx (p->user_systems, "   ", 3);
179     p->length_data_entry = 4;
180     p->length_starting = 5;
181     p->length_implementation = 0;
182     strncpyx (p->future_use, " ", 1);
183
184     p->directory = NULL;
185     return p;
186 }
187
188 Iso2709Rec iso2709_cvt (const char *buf)
189 {
190     struct iso2709_dir **dpp, *dp;
191     int pos = 24;
192     Iso2709Rec p;
193
194     if (!(p = malloc (sizeof(*p))))
195         return NULL;
196
197     /* deal with record label (24 characters) */
198     p->record_length = atoin (buf, 5);
199     strncpyx (p->record_status, buf+5, 1);
200     strncpyx (p->implementation_codes, buf+6, 4);
201     p->indicator_length = atoin (buf+10, 1);
202     p->identifier_length = atoin (buf+11, 1);
203     p->base_address = atoin (buf+12, 4);
204     strncpyx (p->user_systems, buf+17, 3);
205
206     if (p->record_length < 26)
207     {
208         free (p);
209         return NULL;
210     }
211     p->length_data_entry = atoin (buf+20, 1);
212     p->length_starting = atoin (buf+21, 1);
213     p->length_implementation = atoin (buf+22, 1);
214     strncpyx (p->future_use, buf+23, 1);
215
216     /* deal with directory */
217     dpp = &p->directory;
218     *dpp = NULL;
219     while (buf[pos] != ISO2709_FS)
220     {
221         if (!(*dpp = malloc (sizeof(**dpp))))
222         {
223             iso2709_rm (p);
224             return NULL;
225         }
226         (*dpp)->next = NULL;
227         (*dpp)->fields = NULL;
228         (*dpp)->indicator = NULL;
229         strncpyx ((*dpp)->tag, buf+pos, 3);
230         pos += 3;
231         (*dpp)->length = atoin (buf+pos, p->length_data_entry);
232         pos += p->length_data_entry;
233         (*dpp)->offset = atoin (buf+pos, p->length_starting);
234         pos += p->length_starting + p->length_implementation;
235
236         dpp = &(*dpp)->next;
237         if (pos > p->record_length)
238         {
239             iso2709_rm (p);
240             return NULL;
241         }
242     }
243     pos++;
244     /* deal with datafields */
245     for (dp = p->directory; dp; dp = dp->next)
246     {
247         int identifier_flag;
248         struct iso2709_field **fpp;
249         int dpos = pos+dp->offset;
250         int epos = pos+dp->offset+dp->length-1;
251
252         if (epos <= dpos)
253         {
254             iso2709_rm (p);
255             return NULL;
256         }
257         fpp = &dp->fields;
258
259         if (!(*fpp = malloc (sizeof(**fpp))))
260         {
261             iso2709_rm (p);
262             return NULL;
263         }
264         (*fpp)->next = NULL;
265
266         identifier_flag = 1;
267         if (p->indicator_length)
268         {
269 #if WEIRD_ISO_DBC
270             if (buf[dpos+p->indicator_length] != ISO2709_IDFS)
271                 identifier_flag = 0;
272 #else
273             if (!memcmp (dp->tag, "00", 2))
274                 identifier_flag = 0;
275 #endif
276         }
277         else if (!memcmp (dp->tag, "00", 2))
278                 identifier_flag = 0;
279         if (identifier_flag && p->indicator_length)
280         {
281             if (!(dp->indicator = malloc (p->indicator_length+1)))
282             {
283                 iso2709_rm (p);
284                 return NULL;
285             }
286             strncpyx (dp->indicator, buf+dpos, p->indicator_length);
287             dpos += p->indicator_length;
288         }
289         else
290             dp->indicator = NULL;
291         while (1)
292         {
293             int dpos_n;
294             if (p->identifier_length && identifier_flag)
295             {
296                 strncpyx ((*fpp)->identifier, buf+dpos+1,
297                           p->identifier_length-1);
298                 dpos_n = dpos += p->identifier_length;
299                 while (buf[dpos_n] != ISO2709_FS && buf[dpos_n] != ISO2709_RS
300                        && buf[dpos_n] != ISO2709_IDFS && dpos_n < epos)
301                     dpos_n++;
302             }
303             else
304             {
305                 *(*fpp)->identifier = '\0';
306                 dpos_n = dpos;
307                 while (buf[dpos_n] != ISO2709_FS && buf[dpos_n] != ISO2709_RS
308                        && dpos_n < epos)
309                     dpos_n++;
310             }
311             if (!((*fpp)->data = malloc (dpos_n - dpos + 1)))
312             {
313                 iso2709_rm (p);
314                 return NULL;
315             }
316             strncpyx ((*fpp)->data, buf+dpos, dpos_n - dpos);
317             dpos = dpos_n;
318             
319             if (dpos >= epos)
320             {
321                 if (buf[dpos] != ISO2709_FS && buf[dpos] != ISO2709_RS)
322                     fprintf (stderr, "Missing separator at end of field "
323                              "in %s %s\n", dp->tag, (*fpp)->identifier);
324                 break;
325             }
326             if (buf[dpos] == ISO2709_FS || buf[dpos] == ISO2709_RS)
327             {
328                 fprintf (stderr, "Unexpected separator inside field %s %s\n",
329                          dp->tag, (*fpp)->identifier);
330                 break;
331             }
332             fpp = &(*fpp)->next;
333             if (!(*fpp = malloc (sizeof(**fpp))))
334             {
335                 iso2709_rm (p);
336                 return NULL;
337             }
338             (*fpp)->next = NULL;
339         }
340     }
341     return p;
342 }
343
344 void iso2709_rm (Iso2709Rec rec)
345 {
346     struct iso2709_dir *dir, *dir1;
347
348     for (dir = rec->directory; dir; dir = dir1)
349     {
350         struct iso2709_field *field, *field1;
351
352         for (field = dir->fields; field; field = field1)
353         {
354             free (field->data);
355             field1 = field->next;
356             free (field);
357         }
358         free (dir->indicator);
359         dir1 = dir->next;
360         free (dir);
361     }
362 }
363