Version 1.8.0.0
[socat.git] / dalan.c
blob736d2abda5c34c63463ff04e127c98f6a59c7273
1 /* source: dalan.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* idea of a low level data description language. currently only a most
6 primitive subset exists. */
8 #include "config.h"
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #if HAVE_STDBOOL_H
13 #include <stdbool.h>
14 #endif
15 #include <ctype.h>
16 #include "dalan.h"
18 /* test structure to find maximal alignment */
19 static struct {
20 char a;
21 long double b;
22 } maxalign;
24 /* test structure to find minimal alignment */
25 static struct {
26 char a;
27 char b;
28 } minalign;
30 /* test union to find kind of byte ordering */
31 static union {
32 char a[2];
33 short b;
34 } byteorder = { "01" };
36 struct dalan_opts_s dalan_opts = {
37 sizeof(int),
38 sizeof(short),
39 sizeof(long),
40 sizeof(char),
41 sizeof(float),
42 sizeof(double)
43 } ;
45 /* fill the dalan_opts structure with machine dependent defaults values. */
46 static void _dalan_dflts(struct dalan_opts_s *dlo) {
47 dlo->c_int = sizeof(int);
48 dlo->c_short = sizeof(short);
49 dlo->c_long = sizeof(long);
50 dlo->c_char = sizeof(char);
51 dlo->c_float = sizeof(float);
52 dlo->c_double = sizeof(double);
53 dlo->maxalign = (char *)&maxalign.b-&maxalign.a;
54 dlo->minalign = &minalign.b-&minalign.a;
55 dlo->byteorder = (byteorder.b!=7711);
58 /* allocate a new dalan_opts structure, fills it with machine dependent
59 defaults values, and returns the pointer. */
60 struct dalan_opts_s *dalan_props(void) {
61 struct dalan_opts_s *dlo;
62 dlo = malloc(sizeof(struct dalan_opts_s));
63 if (dlo == NULL) {
64 return NULL;
66 _dalan_dflts(dlo);
67 return dlo;
70 void dalan_init(void) {
71 _dalan_dflts(&dalan_opts);
74 /* Parses and coverts a data item.
75 Returns 0 on success,
76 -1 if the data was cut due to n limit,
77 1 if a syntax error occurred
78 2 if the actual character is white space
79 3 if the first character is not a type specifier
81 static int dalan_item(int c, const char **line0, uint8_t *data, size_t *p, size_t n) {
82 const char *line = *line0;
83 size_t p1 = *p;
85 switch (c) {
86 case ' ':
87 case '\t':
88 case '\r':
89 case '\n':
90 return 2;
91 case '"':
92 while (1) {
93 switch (c = *line++) {
94 case '\0': fputs("unterminated string\n", stderr);
95 *line0 = line;
96 return 1;
97 case '"':
98 break;
99 case '\\':
100 if (!(c = *line++)) {
101 fputs("continuation line not implemented\n", stderr);
102 *line0 = line;
103 return 1;
105 switch (c) {
106 case 'n': c = '\n'; break;
107 case 'r': c = '\r'; break;
108 case 't': c = '\t'; break;
109 case 'f': c = '\f'; break;
110 case 'b': c = '\b'; break;
111 case 'a': c = '\a'; break;
112 #if 0
113 case 'e': c = '\e'; break;
114 #else
115 case 'e': c = '\033'; break;
116 #endif
117 case '0': c = '\0'; break;
119 /* PASSTHROUGH */
120 default:
121 if (p1 >= n) {
122 *p = p1;
123 *line0 = line;
124 return -1;
126 data[p1++] = c;
127 continue;
129 if (c == '"')
130 break;
132 break;
133 case '\'':
134 switch (c = *line++) {
135 case '\0': fputs("unterminated character\n", stderr);
136 *line0 = line;
137 return 1;
138 case '\'': fputs("error in character\n", stderr);
139 *line0 = line;
140 return 1;
141 case '\\':
142 if (!(c = *line++)) {
143 fputs("continuation line not implemented\n", stderr);
144 *line0 = line;
145 return 1;
147 switch (c) {
148 case 'n': c = '\n'; break;
149 case 'r': c = '\r'; break;
150 case 't': c = '\t'; break;
151 case 'f': c = '\f'; break;
152 case 'b': c = '\b'; break;
153 case 'a': c = '\a'; break;
154 #if 0
155 case 'e': c = '\e'; break;
156 #else
157 case 'e': c = '\033'; break;
158 #endif
160 /* PASSTHROUGH */
161 default:
162 if (p1 >= n) { *p = p1; return -1; }
163 data[p1++] = c;
164 break;
166 if (*line != '\'') {
167 fputs("error in character termination\n", stderr);
168 *p = p1;
169 *line0 = line;
170 return 1;
172 ++line;
173 break;
174 case 'x':
175 /* expecting hex data, must be an even number of digits!! */
176 while (true) {
177 int x;
178 c = *line;
179 if (isdigit(c&0xff)) {
180 x = (c-'0') << 4;
181 } else if (isxdigit(c&0xff)) {
182 x = ((c&0x07) + 9) << 4;
183 } else
184 break;
185 ++line;
186 c = *line;
187 if (isdigit(c&0xff)) {
188 x |= (c-'0');
189 } else if (isxdigit(c&0xff)) {
190 x |= (c&0x07) + 9;
191 } else {
192 fputs("odd number of hexadecimal digits\n", stderr);
193 *p = p1;
194 *line0 = line;
195 return 1;
197 ++line;
198 if (p1 >= n) {
199 *p = p1;
200 *line0 = line;
201 return -1;
203 data[p1++] = x;
205 break;
206 case 'l':
207 /* expecting decimal number, with target type long */
209 char *endptr;
210 *(long *)&data[p1] = strtol(line, &endptr, 10);
211 p1 += sizeof(long);
212 line = endptr;
214 break;
215 case 'L':
216 /* expecting decimal number, with target type unsigned long */
218 char *endptr;
219 *(unsigned long *)&data[p1] = strtol(line, &endptr, 10);
220 p1 += sizeof(unsigned long);
221 line = endptr;
223 break;
224 case 'i':
225 /* expecting decimal number, with target type int */
227 char *endptr;
228 *(int *)&data[p1] = strtol(line, &endptr, 10);
229 p1 += sizeof(int);
230 line = endptr;
232 break;
233 case 'I':
234 /* expecting decimal number, with target type unsigned int */
236 char *endptr;
237 *(unsigned int *)&data[p1] = strtol(line, &endptr, 10);
238 p1 += sizeof(unsigned int);
239 line = endptr;
241 break;
242 case 's':
243 /* expecting decimal number, with target type short */
245 char *endptr;
246 *(short *)&data[p1] = strtol(line, &endptr, 10);
247 p1 += sizeof(short);
248 line = endptr;
250 break;
251 case 'S':
252 /* expecting decimal number, with target type unsigned short */
254 char *endptr;
255 *(unsigned short *)&data[p1] = strtol(line, &endptr, 10);
256 p1 += sizeof(unsigned short);
257 line = endptr;
259 break;
260 case 'b':
261 /* expecting decimal number, with target type byte (int8_t) */
263 char *endptr;
264 *(int8_t *)&data[p1] = strtoul(line, &endptr, 10);
265 p1 += sizeof(uint8_t);
266 line = endptr;
268 case 'B':
269 /* expecting decimal number, with target type byte (uint8_t) */
271 char *endptr;
272 *(uint8_t *)&data[p1] = strtoul(line, &endptr, 10);
273 p1 += sizeof(uint8_t);
274 line = endptr;
276 break;
277 default:
278 *line0 = line;
279 return 3;
281 *p = p1;
282 *line0 = line;
283 return 0;
286 /* read data description from line (\0-terminated), write result to data; do
287 not write so much data that *p exceeds n !
288 *p must be initialized.
289 return 0 on success,
290 -1 if the data was cut due to n limit,
291 1 if a syntax error occurred
292 *p is a global data counter; especially it must be used when calculating
293 alignment. On successful return from the function *p must be actual!
295 int dalan(const char *line, uint8_t *data, size_t *p, size_t n, char deflt) {
296 size_t p0;
297 char c;
298 int rc;
300 while (1) {
301 /* assume there is a type specifier on beginning of rest of line */
302 c = *line++;
303 if (c == '\0')
304 break;
305 p0 = *p;
306 rc = dalan_item(c, &line, data, p, n);
307 if (rc == 0) {
308 deflt = c; /* continue with this type as default */
309 } else if (rc == 2) {
310 /* white space */
311 continue;
312 } else if (rc == 3) {
313 const char *line0;
314 --line;
315 line0 = line;
316 /* No, we did not recognize c as type specifier, try default type */
317 rc = dalan_item(deflt, &line, data, p, n);
318 if (line == line0) {
319 /* Nothing was parsed */
320 return 1;
323 if (rc != 0) {
324 return rc;
326 /* rc == 0 */
327 n -= (*p-p0);
329 return 0;