Fix compilation on windows for new backtrace stuff
[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 void odr_setprint_noclose(ODR o, FILE *file)
170 {
171     odr_set_stream(o, file, odr_FILE_write, 0);
172 }
173
174 void odr_set_stream(ODR o, void *handle,
175                     void (*stream_write)(ODR o,
176                                          void *handle, int type,
177                                          const char *buf, int len),
178                     void (*stream_close)(void *handle))
179 {
180     o->op->print = (FILE*) handle;
181     o->op->stream_write = stream_write;
182     o->op->stream_close = stream_close;
183 }
184
185 int odr_set_charset(ODR o, const char *to, const char *from)
186 {
187     if (o->op->iconv_handle)
188         yaz_iconv_close (o->op->iconv_handle);
189     o->op->iconv_handle = 0;
190     if (to && from)
191     {
192         o->op->iconv_handle = yaz_iconv_open(to, from);
193         if (o->op->iconv_handle == 0)
194             return -1;
195     }
196     return 0;
197 }
198
199
200 ODR odr_createmem(int direction)
201 {
202     ODR o;
203     if (!log_level_initialized)
204     {
205         log_level = yaz_log_module_level("odr");
206         log_level_initialized = 1;
207     }
208
209     if (!(o = (ODR) xmalloc(sizeof(*o))))
210         return 0;
211     o->op = (struct Odr_private *) xmalloc(sizeof(*o->op));
212     o->direction = direction;
213     o->op->buf = 0;
214     o->op->size = o->op->pos = o->op->top = 0;
215     o->op->can_grow = 1;
216     o->mem = nmem_create();
217     o->op->enable_bias = 1;
218     o->op->odr_ber_tag.lclass = -1;
219     o->op->iconv_handle = 0;
220     odr_setprint_noclose(o, stderr);
221     odr_reset(o);
222     yaz_log(log_level, "odr_createmem dir=%d o=%p", direction, o);
223     return o;
224 }
225
226 void odr_reset(ODR o)
227 {
228     if (!log_level_initialized)
229     {
230         log_level = yaz_log_module_level("odr");
231         log_level_initialized = 1;
232     }
233
234     odr_seterror(o, ONONE, 0);
235     o->op->bp = o->op->buf;
236     odr_seek(o, ODR_S_SET, 0);
237     o->op->top = 0;
238     o->op->t_class = -1;
239     o->op->t_tag = -1;
240     o->op->indent = 0;
241     o->op->stack_first = 0;
242     o->op->stack_top = 0;
243     o->op->tmp_names_sz = 0;
244     o->op->tmp_names_buf = 0;
245     nmem_reset(o->mem);
246     o->op->choice_bias = -1;
247     o->op->lenlen = 1;
248     if (o->op->iconv_handle != 0)
249         yaz_iconv(o->op->iconv_handle, 0, 0, 0, 0);
250     yaz_log(log_level, "odr_reset o=%p", o);
251 }
252
253 void odr_destroy(ODR o)
254 {
255     nmem_destroy(o->mem);
256     if (o->op->buf && o->op->can_grow)
257        xfree(o->op->buf);
258     if (o->op->stream_close)
259         o->op->stream_close(o->op->print);
260     if (o->op->iconv_handle != 0)
261         yaz_iconv_close(o->op->iconv_handle);
262     xfree(o->op);
263     xfree(o);
264     yaz_log(log_level, "odr_destroy o=%p", o);
265 }
266
267 void odr_setbuf(ODR o, char *buf, int len, int can_grow)
268 {
269     odr_seterror(o, ONONE, 0);
270     o->op->bp = buf;
271     o->op->buf = buf;
272     o->op->can_grow = can_grow;
273     o->op->top = o->op->pos = 0;
274     o->op->size = len;
275 }
276
277 char *odr_getbuf(ODR o, int *len, int *size)
278 {
279     *len = o->op->top;
280     if (size)
281         *size = o->op->size;
282     return o->op->buf;
283 }
284
285 int odr_offset(ODR o)
286 {
287     return o->op->bp - o->op->buf;
288 }
289
290 void odr_printf(ODR o, const char *fmt, ...)
291 {
292     va_list ap;
293     char buf[4096];
294
295     va_start(ap, fmt);
296     yaz_vsnprintf(buf, sizeof(buf), fmt, ap);
297     o->op->stream_write(o, o->op->print, ODR_VISIBLESTRING, buf, strlen(buf));
298     va_end(ap);
299 }
300 /*
301  * Local variables:
302  * c-basic-offset: 4
303  * c-file-style: "Stroustrup"
304  * indent-tabs-mode: nil
305  * End:
306  * vim: shiftwidth=4 tabstop=8 expandtab
307  */
308