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