New 2709 function: iso2709_mk.
[egate.git] / util / iso2709.c
1 /*
2  * Iso2709 record management
3  *
4  * Europagate, 1994-1995.
5  *
6  * $Log: iso2709.c,v $
7  * Revision 1.13  1995/03/30 07:33:32  adam
8  * New 2709 function: iso2709_mk.
9  * First implementation of iso2709_a_insert.
10  *
11  * Revision 1.12  1995/03/29  16:08:56  adam
12  * Better error recovery when using bad records.
13  *
14  * Revision 1.11  1995/03/28  16:07:07  adam
15  * New function: iso2709_out. This function is the reverse of iso2709_cvt.
16  *
17  * Revision 1.10  1995/03/10  09:10:56  adam
18  * Removed dbc2709_cvt function. Makes heuristic guess for DBC2709 records.
19  *
20  * Revision 1.9  1995/03/08  12:36:39  adam
21  * New function: dbc2709_cvt.
22  *
23  * Revision 1.8  1995/03/08  12:03:15  adam
24  * Hack: When tags 00? are used, every separator (DC[1-3]) marks
25  * the end of the data field.
26  *
27  * Revision 1.7  1995/02/22  21:28:03  adam
28  * Changed header.
29  *
30  * Revision 1.5  1995/02/22  15:24:14  adam
31  * Function iso2709_cvt makes a litte check for the format. It returns
32  * NULL if the buffer parameter can never be a MARC record.
33  *
34  * Revision 1.4  1995/02/15  17:45:44  adam
35  * Bug fix in iso2709 module.
36  *
37  * Revision 1.3  1995/02/10  17:05:18  adam
38  * New function iso2709_display to display MARC records in a
39  * line-by-line format. The iso2709_cvt function no longer
40  * prints the record to stderr.
41  *
42  * Revision 1.2  1995/02/10  16:50:32  adam
43  * Indicator field moved to 'struct iso2709_dir' from 'struct
44  * iso2709_field'.
45  * Function iso2709_rm implemented - to delete a MARC record.
46  *
47  * Revision 1.1.1.1  1995/02/09  17:27:11  adam
48  * Initial version of email gateway under CVS control.
49  *
50  */
51
52 #include <stdlib.h>
53 #include <string.h>
54 #include <stdio.h>
55 #include <assert.h>
56 #include <ctype.h>
57
58 #include <iso2709p.h>
59
60 static int atoin (const char *buf, int n)
61 {
62     int val = 0;
63     while (--n >= 0)
64     {
65         if (isdigit(*buf))
66             val = val*10 + (*buf - '0');
67         buf++;
68     }
69     return val;
70 }
71
72 static void strncpyx (char *d, const char *s, int n)
73 {
74     while (--n >= 0 && *s)
75         if (*s != ISO2709_IDFS)
76             *d++ = *s++;
77         else
78         {
79             *d++ = ' ';
80             s++;
81         }
82     *d = '\0';
83 }
84
85 char *iso2709_read (FILE *inf)
86 {
87     char length_str[5];
88     int size;
89     char *buf;
90
91     if (fread (length_str, 1, 5, inf) != 5)
92         return NULL;
93     size = atoin (length_str, 5);
94     if (size <= 6)
95         return NULL;
96     if (!(buf = malloc (size+1)))
97         return NULL;
98     if (fread (buf+5, 1, size-5, inf) != (size-5))
99     {
100         free (buf);
101         return NULL;
102     }
103     memcpy (buf, length_str, 5);
104     buf[size] = '\0';
105     return buf;
106 }
107
108 Iso2709Rec iso2709_mk (void)
109 {
110     Iso2709Rec p;
111
112     if (!(p = malloc (sizeof(*p))))
113         return NULL;
114
115     p->record_length = 0;
116     strncpyx (p->record_status, " ", 1);
117     strncpyx (p->implementation_codes, "    ", 4);
118     p->indicator_length = 2;
119     p->identifier_length = 2;
120     p->base_address = 0;
121     strncpyx (p->user_systems, "   ", 3);
122     p->length_data_entry = 4;
123     p->length_starting = 5;
124     p->length_implementation = 0;
125     strncpyx (p->future_use, " ", 1);
126
127     p->directory = NULL;
128     return p;
129 }
130
131 Iso2709Rec iso2709_cvt (const char *buf)
132 {
133     struct iso2709_dir **dpp, *dp;
134     int pos = 24;
135     Iso2709Rec p;
136
137     if (!(p = malloc (sizeof(*p))))
138         return NULL;
139
140     /* deal with record label (24 characters) */
141     p->record_length = atoin (buf, 5);
142     strncpyx (p->record_status, buf+5, 1);
143     strncpyx (p->implementation_codes, buf+6, 4);
144     p->indicator_length = atoin (buf+10, 1);
145     p->identifier_length = atoin (buf+11, 1);
146     p->base_address = atoin (buf+12, 4);
147     strncpyx (p->user_systems, buf+17, 3);
148
149     if (p->record_length < 26)
150     {
151         free (p);
152         return NULL;
153     }
154     p->length_data_entry = atoin (buf+20, 1);
155     p->length_starting = atoin (buf+21, 1);
156     p->length_implementation = atoin (buf+22, 1);
157     strncpyx (p->future_use, buf+23, 1);
158
159     /* deal with directory */
160     dpp = &p->directory;
161     *dpp = NULL;
162     while (buf[pos] != ISO2709_FS)
163     {
164         if (!(*dpp = malloc (sizeof(**dpp))))
165         {
166             iso2709_rm (p);
167             return NULL;
168         }
169         (*dpp)->next = NULL;
170         (*dpp)->fields = NULL;
171         strncpyx ((*dpp)->tag, buf+pos, 3);
172         pos += 3;
173         (*dpp)->length = atoin (buf+pos, p->length_data_entry);
174         pos += p->length_data_entry;
175         (*dpp)->offset = atoin (buf+pos, p->length_starting);
176         pos += p->length_starting + p->length_implementation;
177
178         dpp = &(*dpp)->next;
179         if (pos > p->record_length)
180         {
181             iso2709_rm (p);
182             return NULL;
183         }
184     }
185     pos++;
186     /* deal with datafields */
187     for (dp = p->directory; dp; dp = dp->next)
188     {
189         int identifier_flag;
190         struct iso2709_field **fpp;
191         int dpos = pos+dp->offset;
192         int epos = pos+dp->offset+dp->length-1;
193
194         fpp = &dp->fields;
195
196         if (!(*fpp = malloc (sizeof(**fpp))))
197         {
198             iso2709_rm (p);
199             return NULL;
200         }
201         (*fpp)->next = NULL;
202
203         identifier_flag = 1;
204         if (p->indicator_length)
205         {
206 #if STUPID_ISO_DBC
207             if (buf[dpos+p->indicator_length] != ISO2709_IDFS)
208                 identifier_flag = 0;
209 #else
210             if (!memcmp (dp->tag, "00", 2))
211                 identifier_flag = 0;
212 #endif
213         }
214         else if (!memcmp (dp->tag, "00", 2))
215                 identifier_flag = 0;
216         if (identifier_flag && p->indicator_length)
217         {
218             if (!(dp->indicator = malloc (p->indicator_length+1)))
219             {
220                 iso2709_rm (p);
221                 return NULL;
222             }
223             strncpyx (dp->indicator, buf+dpos, p->indicator_length);
224             dpos += p->indicator_length;
225         }
226         else
227             dp->indicator = NULL;
228         while (1)
229         {
230             int dpos_n;
231             if (p->identifier_length && identifier_flag)
232             {
233                 if (!((*fpp)->identifier = malloc (p->identifier_length+1)))
234                 {
235                     iso2709_rm (p);
236                     return NULL;
237                 }
238                 strncpyx ((*fpp)->identifier, buf+dpos+1,
239                           p->identifier_length-1);
240                 dpos_n = dpos += p->identifier_length;
241                 while (buf[dpos_n] != ISO2709_FS && buf[dpos_n] != ISO2709_RS
242                        && buf[dpos_n] != ISO2709_IDFS && dpos_n < epos)
243                     dpos_n++;
244             }
245             else
246             {
247                 (*fpp)->identifier = NULL;
248                 dpos_n = dpos;
249                 while (buf[dpos_n] != ISO2709_FS && buf[dpos_n] != ISO2709_RS
250                        && dpos_n < epos)
251                     dpos_n++;
252             }
253             if (!((*fpp)->data = malloc (dpos_n - dpos + 1)))
254             {
255                 iso2709_rm (p);
256                 return NULL;
257             }
258             strncpyx ((*fpp)->data, buf+dpos, dpos_n - dpos);
259             dpos = dpos_n;
260             
261             if (dpos == epos)
262             {
263                 if (buf[dpos] != ISO2709_FS && buf[dpos] != ISO2709_RS)
264                     fprintf (stderr, "Missing separator at end of field "
265                              "in %s %s\n", dp->tag, (*fpp)->identifier ?
266                              (*fpp)->identifier : "");
267                 break;
268             }
269             if (buf[dpos] == ISO2709_FS || buf[dpos] == ISO2709_RS)
270             {
271                 fprintf (stderr, "Unexpected separator inside field\n");
272                 break;
273             }
274             fpp = &(*fpp)->next;
275             if (!(*fpp = malloc (sizeof(**fpp))))
276             {
277                 iso2709_rm (p);
278                 return NULL;
279             }
280             (*fpp)->next = NULL;
281         }
282     }
283     return p;
284 }
285
286 void iso2709_rm (Iso2709Rec rec)
287 {
288     struct iso2709_dir *dir, *dir1;
289
290     for (dir = rec->directory; dir; dir = dir1)
291     {
292         struct iso2709_field *field, *field1;
293
294         for (field = dir->fields; field; field = field1)
295         {
296             free (field->identifier);
297             free (field->data);
298             field1 = field->next;
299             free (field);
300         }
301         free (dir->indicator);
302         dir1 = dir->next;
303         free (dir);
304     }
305 }
306