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