/* source: dalan.c */ /* Copyright Gerhard Rieger and contributors (see file CHANGES) */ /* Published under the GNU General Public License V.2, see file COPYING */ /* idea of a low level data description language. currently only a most primitive subset exists. */ #include "config.h" #include #include #include #if HAVE_STDBOOL_H #include #endif #include #include "dalan.h" /* test structure to find maximal alignment */ static struct { char a; long double b; } maxalign; /* test structure to find minimal alignment */ static struct { char a; char b; } minalign; /* test union to find kind of byte ordering */ static union { char a[2]; short b; } byteorder = { "01" }; struct dalan_opts_s dalan_opts = { sizeof(int), sizeof(short), sizeof(long), sizeof(char), sizeof(float), sizeof(double) } ; /* fill the dalan_opts structure with machine dependent defaults values. */ static void _dalan_dflts(struct dalan_opts_s *dlo) { dlo->c_int = sizeof(int); dlo->c_short = sizeof(short); dlo->c_long = sizeof(long); dlo->c_char = sizeof(char); dlo->c_float = sizeof(float); dlo->c_double = sizeof(double); dlo->maxalign = (char *)&maxalign.b-&maxalign.a; dlo->minalign = &minalign.b-&minalign.a; dlo->byteorder = (byteorder.b!=7711); } /* allocate a new dalan_opts structure, fills it with machine dependent defaults values, and returns the pointer. */ struct dalan_opts_s *dalan_props(void) { struct dalan_opts_s *dlo; dlo = malloc(sizeof(struct dalan_opts_s)); if (dlo == NULL) { return NULL; } _dalan_dflts(dlo); return dlo; } void dalan_init(void) { _dalan_dflts(&dalan_opts); } /* Parses and coverts a data item. Returns 0 on success, -1 if the data was cut due to n limit, 1 if a syntax error occurred 2 if the actual character is white space 3 if the first character is not a type specifier */ static int dalan_item(int c, const char **line0, uint8_t *data, size_t *p, size_t n) { const char *line = *line0; size_t p1 = *p; switch (c) { case ' ': case '\t': case '\r': case '\n': return 2; case '"': while (1) { switch (c = *line++) { case '\0': fputs("unterminated string\n", stderr); *line0 = line; return 1; case '"': break; case '\\': if (!(c = *line++)) { fputs("continuation line not implemented\n", stderr); *line0 = line; return 1; } switch (c) { case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'f': c = '\f'; break; case 'b': c = '\b'; break; case 'a': c = '\a'; break; #if 0 case 'e': c = '\e'; break; #else case 'e': c = '\033'; break; #endif case '0': c = '\0'; break; } /* PASSTHROUGH */ default: if (p1 >= n) { *p = p1; *line0 = line; return -1; } data[p1++] = c; continue; } if (c == '"') break; } break; case '\'': switch (c = *line++) { case '\0': fputs("unterminated character\n", stderr); *line0 = line; return 1; case '\'': fputs("error in character\n", stderr); *line0 = line; return 1; case '\\': if (!(c = *line++)) { fputs("continuation line not implemented\n", stderr); *line0 = line; return 1; } switch (c) { case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'f': c = '\f'; break; case 'b': c = '\b'; break; case 'a': c = '\a'; break; #if 0 case 'e': c = '\e'; break; #else case 'e': c = '\033'; break; #endif } /* PASSTHROUGH */ default: if (p1 >= n) { *p = p1; return -1; } data[p1++] = c; break; } if (*line != '\'') { fputs("error in character termination\n", stderr); *p = p1; *line0 = line; return 1; } ++line; break; case 'x': /* expecting hex data, must be an even number of digits!! */ while (true) { int x; c = *line; if (isdigit(c&0xff)) { x = (c-'0') << 4; } else if (isxdigit(c&0xff)) { x = ((c&0x07) + 9) << 4; } else break; ++line; c = *line; if (isdigit(c&0xff)) { x |= (c-'0'); } else if (isxdigit(c&0xff)) { x |= (c&0x07) + 9; } else { fputs("odd number of hexadecimal digits\n", stderr); *p = p1; *line0 = line; return 1; } ++line; if (p1 >= n) { *p = p1; *line0 = line; return -1; } data[p1++] = x; } break; case 'l': /* expecting decimal number, with target type long */ { char *endptr; *(long *)&data[p1] = strtol(line, &endptr, 10); p1 += sizeof(long); line = endptr; } break; case 'L': /* expecting decimal number, with target type unsigned long */ { char *endptr; *(unsigned long *)&data[p1] = strtol(line, &endptr, 10); p1 += sizeof(unsigned long); line = endptr; } break; case 'i': /* expecting decimal number, with target type int */ { char *endptr; *(int *)&data[p1] = strtol(line, &endptr, 10); p1 += sizeof(int); line = endptr; } break; case 'I': /* expecting decimal number, with target type unsigned int */ { char *endptr; *(unsigned int *)&data[p1] = strtol(line, &endptr, 10); p1 += sizeof(unsigned int); line = endptr; } break; case 's': /* expecting decimal number, with target type short */ { char *endptr; *(short *)&data[p1] = strtol(line, &endptr, 10); p1 += sizeof(short); line = endptr; } break; case 'S': /* expecting decimal number, with target type unsigned short */ { char *endptr; *(unsigned short *)&data[p1] = strtol(line, &endptr, 10); p1 += sizeof(unsigned short); line = endptr; } break; case 'b': /* expecting decimal number, with target type byte (int8_t) */ { char *endptr; *(int8_t *)&data[p1] = strtoul(line, &endptr, 10); p1 += sizeof(uint8_t); line = endptr; } case 'B': /* expecting decimal number, with target type byte (uint8_t) */ { char *endptr; *(uint8_t *)&data[p1] = strtoul(line, &endptr, 10); p1 += sizeof(uint8_t); line = endptr; } break; default: *line0 = line; return 3; } *p = p1; *line0 = line; return 0; } /* read data description from line (\0-terminated), write result to data; do not write so much data that *p exceeds n ! *p must be initialized. return 0 on success, -1 if the data was cut due to n limit, 1 if a syntax error occurred *p is a global data counter; especially it must be used when calculating alignment. On successful return from the function *p must be actual! */ int dalan(const char *line, uint8_t *data, size_t *p, size_t n, char deflt) { size_t p0; char c; int rc; while (1) { /* assume there is a type specifier on beginning of rest of line */ c = *line++; if (c == '\0') break; p0 = *p; rc = dalan_item(c, &line, data, p, n); if (rc == 0) { deflt = c; /* continue with this type as default */ } else if (rc == 2) { /* white space */ continue; } else if (rc == 3) { const char *line0; --line; line0 = line; /* No, we did not recognize c as type specifier, try default type */ rc = dalan_item(deflt, &line, data, p, n); if (line == line0) { /* Nothing was parsed */ return 1; } } if (rc != 0) { return rc; } /* rc == 0 */ n -= (*p-p0); } return 0; }