Added odr_set_stream which is is a more generic to odr_setprint.
[yaz-moved-to-github.git] / src / odr.c
1 /*
2  * Copyright (c) 1995-2004, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: odr.c,v 1.2 2004-08-11 12:15:38 adam Exp $
6  *
7  */
8 #if HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15
16 #include <yaz/xmalloc.h>
17 #include "odr-priv.h"
18
19 Odr_null *ODR_NULLVAL = (Odr_null *) "NULL";  /* the presence of a null value */
20
21 Odr_null *odr_nullval (void)
22 {
23     return ODR_NULLVAL;
24 }
25
26 char *odr_errlist[] =
27 {
28     "No (unknown) error",
29     "Memory allocation failed",
30     "System error",
31     "No space in buffer",
32     "Required data element missing",
33     "Unexpected tag",
34     "Other error",
35     "Protocol error",
36     "Malformed data",
37     "Stack overflow",
38     "Length of constructed type different from sum of members",
39     "Overflow writing definite length of constructed type",
40     "Bad HTTP Request"
41 };
42
43 char *odr_errmsg(int n)
44 {
45     return odr_errlist[n];
46 }
47
48 void odr_perror(ODR o, const char *message)
49 {
50     const char *e = odr_getelement(o);
51     int err, x;
52
53     err =  odr_geterrorx(o, &x);
54     fprintf(stderr, "%s: %s (code %d:%d)", message, odr_errlist[err], err, x);
55     if (e && *e)
56         fprintf (stderr, " element %s", e);
57     fprintf(stderr, "\n");
58 }
59
60 int odr_geterror(ODR o)
61 {
62     return o->error;
63 }
64
65 int odr_geterrorx(ODR o, int *x)
66 {
67     if (x)
68         *x = o->op->error_id;
69     return o->error;
70 }
71
72 char *odr_getelement(ODR o)
73 {
74     return o->op->element;
75 }
76
77 void odr_seterror(ODR o, int error, int id)
78 {
79     o->error = error;
80     o->op->error_id = id;
81     o->op->element[0] = '\0';
82 }
83
84 void odr_setelement(ODR o, const char *element)
85 {
86     if (element)
87     {
88         strncpy(o->op->element, element, sizeof(o->op->element)-1);
89         o->op->element[sizeof(o->op->element)-1] = '\0';
90     }
91 }
92
93 void odr_FILE_puts(void *handle, const char *strz)
94 {
95     fputs(strz, (FILE*) handle);
96 }
97
98 void odr_FILE_close(void *handle)
99 {
100     FILE *f = (FILE *) handle;
101     if (f && f != stderr && f != stdout)
102         fclose(f);
103 }
104
105 void odr_setprint(ODR o, FILE *file)
106 {
107     odr_set_stream(o, file, odr_FILE_puts, odr_FILE_close);
108 }
109
110 void odr_set_stream(ODR o, void *handle,
111                     void (*stream_puts)(void *handle, const char *strz),
112                     void (*stream_close)(void *handle))
113 {
114     o->print = handle;
115     o->op->stream_puts = stream_puts;
116     o->op->stream_close = stream_close;
117 }
118
119 int odr_set_charset(ODR o, const char *to, const char *from)
120 {
121     if (o->op->iconv_handle)
122         yaz_iconv_close (o->op->iconv_handle);
123     o->op->iconv_handle = 0;
124     if (to && from)
125     {
126         o->op->iconv_handle = yaz_iconv_open (to, from);
127         if (o->op->iconv_handle == 0)
128             return -1;
129     }
130     return 0;
131 }
132
133 #include <yaz/log.h>
134
135 ODR odr_createmem(int direction)
136 {
137     ODR o;
138
139     if (!(o = (ODR)xmalloc(sizeof(*o))))
140         return 0;
141     o->direction = direction;
142     o->buf = 0;
143     o->size = o->pos = o->top = 0;
144     o->can_grow = 1;
145     o->mem = nmem_create();
146     o->enable_bias = 1;
147     o->op = (struct Odr_private *) xmalloc (sizeof(*o->op));
148     o->op->odr_ber_tag.lclass = -1;
149     o->op->iconv_handle = 0;
150     odr_setprint(o, stderr);
151     odr_reset(o);
152     yaz_log (LOG_DEBUG, "odr_createmem dir=%d o=%p", direction, o);
153     return o;
154 }
155
156 void odr_reset(ODR o)
157 {
158     odr_seterror(o, ONONE, 0);
159     o->bp = o->buf;
160     odr_seek(o, ODR_S_SET, 0);
161     o->top = 0;
162     o->t_class = -1;
163     o->t_tag = -1;
164     o->indent = 0;
165     o->op->stackp = -1;
166     nmem_reset(o->mem);
167     o->choice_bias = -1;
168     o->lenlen = 1;
169     if (o->op->iconv_handle != 0)
170         yaz_iconv(o->op->iconv_handle, 0, 0, 0, 0);
171     yaz_log (LOG_DEBUG, "odr_reset o=%p", o);
172 }
173     
174 void odr_destroy(ODR o)
175 {
176     nmem_destroy(o->mem);
177     if (o->buf && o->can_grow)
178        xfree(o->buf);
179     if (o->op->stream_close)
180         o->op->stream_close(o->print);
181     if (o->op->iconv_handle != 0)
182         yaz_iconv_close (o->op->iconv_handle);
183     xfree(o->op);
184     xfree(o);
185     yaz_log (LOG_DEBUG, "odr_destroy o=%p", o);
186 }
187
188 void odr_setbuf(ODR o, char *buf, int len, int can_grow)
189 {
190     o->bp = (unsigned char *) buf;
191
192     o->buf = (unsigned char *) buf;
193     o->can_grow = can_grow;
194     o->top = o->pos = 0;
195     o->size = len;
196 }
197
198 char *odr_getbuf(ODR o, int *len, int *size)
199 {
200     *len = o->top;
201     if (size)
202         *size = o->size;
203     return (char*) o->buf;
204 }
205
206 void odr_printf(ODR o, const char *fmt, ...)
207 {
208     va_list ap;
209     char buf[4096];
210
211     va_start(ap, fmt);
212 #ifdef WIN32
213     _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
214 #else
215 #if HAVE_VSNPRINTF
216     vsnprintf(buf, sizeof(buf), fmt, ap);
217 #else
218     vsprintf(buf, fmt, ap);
219 #endif
220 #endif
221     o->op->stream_puts(o->print, buf);
222     va_end(ap);
223 }