Exteded yaz_marc_write_marcxhange new parameters, format and type.
[yaz-moved-to-github.git] / src / odr.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: odr.c,v 1.13 2005-08-11 14:21:55 adam Exp $
6  *
7  */
8
9 /**
10  * \file odr.c
11  * \brief Implements fundamental ODR functionality
12  */
13
14 #if HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17
18 #include <assert.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22
23 #include <yaz/xmalloc.h>
24 #include <yaz/log.h>
25 #include "odr-priv.h"
26
27 static int log_level=0;
28 static int log_level_initialized=0;
29
30 Odr_null *ODR_NULLVAL = (Odr_null *) "NULL";  /* the presence of a null value */
31
32 Odr_null *odr_nullval (void)
33 {
34     return ODR_NULLVAL;
35 }
36
37 char *odr_errlist[] =
38 {
39     "No (unknown) error",
40     "Memory allocation failed",
41     "System error",
42     "No space in buffer",
43     "Required data element missing",
44     "Unexpected tag",
45     "Other error",
46     "Protocol error",
47     "Malformed data",
48     "Stack overflow",
49     "Length of constructed type different from sum of members",
50     "Overflow writing definite length of constructed type",
51     "Bad HTTP Request"
52 };
53
54 char *odr_errmsg(int n)
55 {
56     return odr_errlist[n];
57 }
58
59 void odr_perror(ODR o, const char *message)
60 {
61     const char *e = odr_getelement(o);
62     const char **element_path = odr_get_element_path(o);
63     int err, x;
64
65     err =  odr_geterrorx(o, &x);
66     fprintf(stderr, "%s: %s (code %d:%d)", message, odr_errlist[err], err, x);
67     if (e && *e)
68         fprintf(stderr, " element %s", e);
69     
70     fprintf(stderr, "\n");
71     if (element_path)
72     {
73         fprintf(stderr, "Element path:");
74         while (*element_path)
75             fprintf(stderr, " %s", *element_path++);
76         fprintf(stderr, "\n");
77     }
78 }
79
80 int odr_geterror(ODR o)
81 {
82     return o->error;
83 }
84
85 int odr_geterrorx(ODR o, int *x)
86 {
87     if (x)
88         *x = o->op->error_id;
89     return o->error;
90 }
91
92 const char *odr_getelement(ODR o)
93 {
94     return o->op->element;
95 }
96
97 const char **odr_get_element_path(ODR o)
98 {
99     int cur_sz = 0;
100     struct odr_constack *st;
101
102     for (st = o->op->stack_top; st; st = st->prev)
103         cur_sz++;
104     if (o->op->tmp_names_sz < cur_sz + 1)
105     {
106         o->op->tmp_names_sz = 2 * cur_sz + 5;
107         o->op->tmp_names_buf = (const char **)
108             odr_malloc(o, o->op->tmp_names_sz * sizeof(char*));
109     }
110     o->op->tmp_names_buf[cur_sz] = 0;
111     for (st = o->op->stack_top; st; st = st->prev)
112     {
113         cur_sz--;
114         o->op->tmp_names_buf[cur_sz] = st->name;
115     }
116     assert(cur_sz == 0);
117     return o->op->tmp_names_buf;
118 }
119
120 void odr_seterror(ODR o, int error, int id)
121 {
122     o->error = error;
123     o->op->error_id = id;
124     o->op->element[0] = '\0';
125 }
126
127 void odr_setelement(ODR o, const char *element)
128 {
129     if (element)
130     {
131         strncpy(o->op->element, element, sizeof(o->op->element)-1);
132         o->op->element[sizeof(o->op->element)-1] = '\0';
133     }
134 }
135
136 void odr_FILE_write(ODR o, void *handle, int type,
137                     const char *buf, int len)
138 {
139     int i;
140 #if 0
141     if (type  == ODR_OCTETSTRING)
142     {
143         const char **stack_names = odr_get_element_path(o);
144         for (i = 0; stack_names[i]; i++)
145             fprintf((FILE*) handle, "[%s]", stack_names[i]);
146         fputs("\n", (FILE*) handle);
147     }
148 #endif
149     for (i = 0; i<len; i++)
150     {
151         unsigned c = ((const unsigned char *) buf)[i];
152         if (i == 2000 && len > 3100)
153         {
154             fputs(" ..... ", (FILE*) handle);
155                 i = len - 1000;
156         }
157         if (strchr("\r\n\f\t", c) || (c >= ' ' && c <= 126))
158             putc(c, (FILE*) handle);
159         else
160         {
161             char x[5];
162             sprintf(x, "\\X%02X", c);
163             fputs(x, (FILE*) handle);
164         }
165     }
166 }
167
168 void odr_FILE_close(void *handle)
169 {
170     FILE *f = (FILE *) handle;
171     if (f && f != stderr && f != stdout)
172         fclose(f);
173 }
174
175 void odr_setprint(ODR o, FILE *file)
176 {
177     odr_set_stream(o, file, odr_FILE_write, odr_FILE_close);
178 }
179
180 void odr_set_stream(ODR o, void *handle,
181                     void (*stream_write)(ODR o, 
182                                          void *handle, int type,
183                                          const char *buf, int len),
184                     void (*stream_close)(void *handle))
185 {
186     o->print = (FILE*) handle;
187     o->op->stream_write = stream_write;
188     o->op->stream_close = stream_close;
189 }
190
191 int odr_set_charset(ODR o, const char *to, const char *from)
192 {
193     if (o->op->iconv_handle)
194         yaz_iconv_close (o->op->iconv_handle);
195     o->op->iconv_handle = 0;
196     if (to && from)
197     {
198         o->op->iconv_handle = yaz_iconv_open (to, from);
199         if (o->op->iconv_handle == 0)
200             return -1;
201     }
202     return 0;
203 }
204
205
206 ODR odr_createmem(int direction)
207 {
208     ODR o;
209     if (!log_level_initialized)
210     {
211         log_level=yaz_log_module_level("odr");
212         log_level_initialized=1;
213     }
214
215     if (!(o = (ODR)xmalloc(sizeof(*o))))
216         return 0;
217     o->direction = direction;
218     o->buf = 0;
219     o->size = o->pos = o->top = 0;
220     o->can_grow = 1;
221     o->mem = nmem_create();
222     o->enable_bias = 1;
223     o->op = (struct Odr_private *) xmalloc (sizeof(*o->op));
224     o->op->odr_ber_tag.lclass = -1;
225     o->op->iconv_handle = 0;
226     odr_setprint(o, stderr);
227     odr_reset(o);
228     yaz_log (log_level, "odr_createmem dir=%d o=%p", direction, o);
229     return o;
230 }
231
232 void odr_reset(ODR o)
233 {
234     if (!log_level_initialized)
235     {
236         log_level=yaz_log_module_level("odr");
237         log_level_initialized=1;
238     }
239
240     odr_seterror(o, ONONE, 0);
241     o->bp = o->buf;
242     odr_seek(o, ODR_S_SET, 0);
243     o->top = 0;
244     o->t_class = -1;
245     o->t_tag = -1;
246     o->indent = 0;
247     o->op->stack_first = 0;
248     o->op->stack_top = 0;
249     o->op->tmp_names_sz = 0;
250     o->op->tmp_names_buf = 0;
251     nmem_reset(o->mem);
252     o->choice_bias = -1;
253     o->lenlen = 1;
254     if (o->op->iconv_handle != 0)
255         yaz_iconv(o->op->iconv_handle, 0, 0, 0, 0);
256     yaz_log (log_level, "odr_reset o=%p", o);
257 }
258     
259 void odr_destroy(ODR o)
260 {
261     nmem_destroy(o->mem);
262     if (o->buf && o->can_grow)
263        xfree(o->buf);
264     if (o->op->stream_close)
265         o->op->stream_close(o->print);
266     if (o->op->iconv_handle != 0)
267         yaz_iconv_close (o->op->iconv_handle);
268     xfree(o->op);
269     xfree(o);
270     yaz_log (log_level, "odr_destroy o=%p", o);
271 }
272
273 void odr_setbuf(ODR o, char *buf, int len, int can_grow)
274 {
275     odr_seterror(o, ONONE, 0);
276     o->bp = (unsigned char *) buf;
277
278     o->buf = (unsigned char *) buf;
279     o->can_grow = can_grow;
280     o->top = o->pos = 0;
281     o->size = len;
282 }
283
284 char *odr_getbuf(ODR o, int *len, int *size)
285 {
286     *len = o->top;
287     if (size)
288         *size = o->size;
289     return (char*) o->buf;
290 }
291
292 void odr_printf(ODR o, const char *fmt, ...)
293 {
294     va_list ap;
295     char buf[4096];
296
297     va_start(ap, fmt);
298 #ifdef WIN32
299     _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
300 #else
301 #if HAVE_VSNPRINTF
302     vsnprintf(buf, sizeof(buf), fmt, ap);
303 #else
304     vsprintf(buf, fmt, ap);
305 #endif
306 #endif
307     o->op->stream_write(o, o->print, ODR_VISIBLESTRING, buf, strlen(buf));
308     va_end(ap);
309 }
310 /*
311  * Local variables:
312  * c-basic-offset: 4
313  * indent-tabs-mode: nil
314  * End:
315  * vim: shiftwidth=4 tabstop=8 expandtab
316  */
317