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