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