2 Based on genstruct by Andrew Tridgell:
4 Copyright (C) Andrew Tridgell <genstruct@tridgell.net> 2002
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <ccan/talloc/talloc.h>
31 #include "cdump_internal.h"
33 /* intermediate dumps are stored in one of these */
39 /* see if a range of memory is all zero. Used to prevent dumping of zero elements */
40 static bool all_zero(const char *ptr, size_t size)
44 for (i=0;i<size;i++) {
45 if (ptr[i]) return false;
50 /* encode a buffer of bytes into a escaped string */
51 static char *encode_bytes(const void *ctx, const char *ptr, size_t len)
53 const char *hexdig = "0123456789abcdef";
56 ret = talloc_array(ctx, char, len*3 + 1); /* worst case size */
59 for (p=ret,i=0;i<len;i++) {
60 if (isalnum(ptr[i]) || isspace(ptr[i]) ||
61 (ispunct(ptr[i]) && !strchr("\\{}", ptr[i]))) {
64 unsigned char c = *(unsigned char *)(ptr+i);
65 if (c == 0 && all_zero(ptr+i, len-i)) break;
78 /* decode an escaped string from encode_bytes() into a buffer */
79 static char *decode_bytes(const void *ctx, const char *s)
84 ret = talloc_array(ctx, char, strlen(s)+1); /* worst case length */
90 for (p=ret,i=0;s[i];i++) {
93 } else if (s[i] == '\\') {
95 if (sscanf(&s[i+1], "%02x", &v) != 1 || v > 255) {
99 *(unsigned char *)p = v;
106 /* Nul-terminate in case we're being used as a string. */
111 static char *bundle(const void *ctx,
112 const struct cdump_desc *info,
116 /* the add*() functions deal with adding things to a struct
119 /* allocate more space if needed */
120 static bool addgen_alloc(struct cdump_string *p, int n)
122 if (p->length + n <= talloc_get_size(p->s)) return true;
123 p->s = talloc_realloc(p, p->s, char, p->length + n + 200);
127 /* add a character to the buffer */
128 static bool addchar(struct cdump_string *p, char c)
130 if (!addgen_alloc(p, 2)) {
133 p->s[p->length++] = c;
138 /* add a string to the buffer */
139 static bool addstr(struct cdump_string *p, const char *s)
142 if (!addgen_alloc(p, len+1)) {
145 memcpy(p->s + p->length, s, len+1);
150 /* add a string to the buffer with a tab prefix */
151 static bool addtabbed(struct cdump_string *p, const char *s, unsigned indent)
154 if (!addgen_alloc(p, indent+len+1)) {
158 p->s[p->length++] = '\t';
160 memcpy(p->s + p->length, s, len+1);
165 /* note! this can only be used for results up to 60 chars wide! */
166 static bool addshort(struct cdump_string *p, const char *fmt, ...)
172 n = vsnprintf(buf, sizeof(buf), fmt, ap);
174 if (!addgen_alloc(p, n + 1)) {
177 memcpy(p->s + p->length, buf, n);
184 this is here to make it easier for people to write dump functions
187 bool cdump_addstr(struct cdump_string *p, const char *fmt, ...)
193 buf = talloc_vasprintf(NULL, fmt, ap);
197 ret = addstr(p, buf);
202 /* dump a enumerated type */
203 bool cdump_bundle_enum(const struct cdump_enum *einfo,
204 struct cdump_string *p,
208 unsigned v = *(unsigned *)ptr;
210 for (i=0;einfo[i].name;i++) {
211 if (v == einfo[i].value) {
212 return addstr(p, einfo[i].name);
215 /* hmm, maybe we should just fail? */
216 return cdump_bundle_unsigned(p, ptr, indent);
219 /* dump a single non-array element, handling struct and enum */
220 static bool bundle_one(struct cdump_string *p,
221 const struct cdump_desc *info,
225 if (info->bundle == cdump_bundle_char && info->ptr_count == 1) {
226 char *s = encode_bytes(p, ptr, strlen(ptr));
229 if (!addchar(p,'{') ||
237 return info->bundle(p, ptr, indent);
240 /* handle dumping of an array of arbitrary type */
241 static bool bundle_array(struct cdump_string *p,
242 const struct cdump_desc *info,
249 /* special handling of fixed length strings */
250 if (array_len != 0 &&
251 info->ptr_count == 0 &&
252 info->bundle == cdump_bundle_char) {
253 char *s = encode_bytes(p, ptr, array_len);
254 if (!s) return false;
255 if (!addtabbed(p, info->name, indent) ||
256 !addstr(p, " = {") ||
264 for (i=0;i<array_len;i++) {
265 const char *p2 = ptr;
266 size_t size = info->size;
268 /* generic pointer dereference */
269 if (info->ptr_count) {
270 p2 = *(const char **)ptr;
271 size = sizeof(void *);
274 if ((count || info->ptr_count) &&
275 !(info->flags & CDUMP_FLAG_ALWAYS) &&
276 all_zero(ptr, size)) {
281 if (!addtabbed(p, info->name, indent) ||
282 !addshort(p, " = %u:", i)) {
286 if (!addshort(p, ", %u:", i) != 0) {
290 if (!bundle_one(p, info, p2, indent)) {
297 return addstr(p, "\n");
302 /* find a variable by name in a loaded structure and return its value
303 as an integer. Used to support dynamic arrays */
304 static ssize_t find_var(const struct cdump_desc *info,
311 /* this allows for constant lengths */
316 for (i=0;info[i].name;i++) {
317 if (strcmp(info[i].name, var) == 0) break;
319 if (!info[i].name) return -1;
321 ptr = data + info[i].offset;
323 if (info[i].size == sizeof(int))
325 else if (info[i].size == sizeof(size_t))
326 return *(ssize_t *)ptr;
327 else if (info[i].size == sizeof(char))
334 bool cdump_bundle_struct(const struct cdump_desc *info,
335 struct cdump_string *p,
339 char *s = bundle(p, info, ptr, indent+1);
343 return addstr(p, "{\n") && addstr(p,s) && addtabbed(p, "}", indent);
346 static bool bundle_string(struct cdump_string *p,
347 const struct cdump_desc *info,
351 const char *ptr = *(char **)data;
352 char *s = encode_bytes(p, ptr, strlen(ptr));
356 return addtabbed(p, info->name, indent)
363 /* the generic dump routine. Scans the parse information for this structure
364 and processes it recursively */
365 static char *bundle(const void *ctx,
366 const struct cdump_desc *info,
370 struct cdump_string *p;
374 p = talloc(ctx, struct cdump_string);
380 for (i=0;info[i].name;i++) {
381 const void *ptr = (char *)data + info[i].offset;
382 unsigned size = info[i].size;
384 if (info[i].ptr_count) {
385 size = sizeof(void *);
388 /* special handling for array types */
389 if (info[i].array_len) {
390 unsigned len = info[i].array_len;
391 if (!bundle_array(p, &info[i], ptr, len, indent)) {
397 /* and dynamically sized arrays */
398 if (info[i].dynamic_len) {
399 ssize_t len = find_var(info, data, info[i].dynamic_len);
400 struct cdump_desc p2 = info[i];
406 p2.dynamic_len = NULL;
407 if (!bundle_array(p, &p2, *(void **)ptr,
415 /* don't dump zero elements */
416 if (!(info[i].flags & CDUMP_FLAG_ALWAYS) && all_zero(ptr, size))
419 /* assume char* is a null terminated string */
420 if (info[i].size == 1 && info[i].ptr_count == 1 &&
421 info[i].bundle == cdump_bundle_char) {
422 if (!bundle_string(p, &info[i], ptr, indent)) {
428 /* generic pointer dereference */
429 if (info[i].ptr_count) {
430 ptr = *(const void **)ptr;
433 if (!addtabbed(p, info[i].name, indent) ||
435 !bundle_one(p, &info[i], ptr, indent) ||
440 s = talloc_steal(ctx, p->s);
446 char *cdump_bundle(const void *ctx,
447 const struct cdump_desc *info, const void *data)
449 return bundle(ctx, info, data, 0);
452 /* parse routine for enumerated types */
453 bool cdump_unbundle_enum(const struct cdump_enum *einfo,
461 if (sscanf(str, "%u", &v) != 1) {
465 *(unsigned *)ptr = v;
469 for (i=0;einfo[i].name;i++) {
470 if (strcmp(einfo[i].name, str) == 0) {
471 *(unsigned *)ptr = einfo[i].value;
476 /* unknown enum value?? */
481 /* parse all base types */
482 static bool unbundle_base(const void *ctx,
483 const struct cdump_desc *info,
487 if (info->unbundle == cdump_unbundle_char && info->ptr_count==1) {
488 char *s = decode_bytes(ctx, str);
495 if (info->ptr_count) {
496 struct cdump_desc p2 = *info;
497 *(void **)ptr = talloc_zero_size(ctx,
498 info->ptr_count>1?sizeof(void *):info->size);
499 if (! *(void **)ptr) {
504 return unbundle_base(ctx, &p2, ptr, str);
507 return info->unbundle(ctx, ptr, str);
510 /* search for a character in a string, skipping over sections within
512 static char *match_braces(char *s, char c)
524 if (depth == 0 && *s == c) {
532 /* parse a generic array */
533 static bool unbundle_array(const void *ctx,
534 const struct cdump_desc *info,
540 size_t size = info->size;
542 /* special handling of fixed length strings */
543 if (array_len != 0 &&
544 info->ptr_count == 0 &&
545 info->bundle == cdump_bundle_char) {
546 char *s = decode_bytes(ctx, str);
549 memset(ptr, 0, array_len);
550 memcpy(ptr, s, array_len);
555 if (info->ptr_count) {
556 size = sizeof(void *);
567 p2 = match_braces(p, ',');
576 if (!unbundle_base(ctx, info, ptr + idx*size, p)) {
588 /* parse one element, handling dynamic and static arrays */
589 static bool unbundle_one(const void *ctx,
590 const struct cdump_desc *info,
596 for (i=0;info[i].name;i++) {
597 if (strcmp(info[i].name, name) == 0) {
601 if (info[i].name == NULL) {
605 if (info[i].array_len) {
606 return unbundle_array(ctx, &info[i], data+info[i].offset,
607 str, info[i].array_len);
610 if (info[i].dynamic_len) {
611 ssize_t len = find_var(info, data, info[i].dynamic_len);
618 struct cdump_desc p2 = info[i];
620 size = info[i].ptr_count>1?sizeof(void*):info[i].size;
621 ptr = talloc_zero_size(ctx, len * size);
624 *((char **)(data + info[i].offset)) = ptr;
626 p2.dynamic_len = NULL;
627 return unbundle_array(ctx, &p2, ptr, str, len);
632 return unbundle_base(ctx, &info[i], data + info[i].offset, str);
635 /* the main parse routine */
636 bool cdump_unbundle_struct(const void *ctx,
637 const struct cdump_desc *info,
638 void *data, const char *s)
642 s0 = talloc_strdup(ctx, s);
650 /* skip leading whitespace */
651 while (isspace(*str)) str++;
653 p = strchr(str, '=');
656 while (p > str && isspace(*(p-1))) {
663 while (isspace(*value)) value++;
666 str = match_braces(value, '}');
669 str = match_braces(value, '\n');
674 if (!unbundle_one(ctx, info, name, data, value)) {
684 bool cdump_unbundle(const void *ctx,
685 const struct cdump_desc *info,
686 void *data, const char *s)
688 return cdump_unbundle_struct(ctx, info, data, s);
691 /* for convenience supply some standard dumpers and parsers here */
692 bool cdump_unbundle_char(const void *ctx, void *ptr, const char *str)
694 *(unsigned char *)ptr = atoi(str);
698 bool cdump_unbundle_int(const void *ctx, void *ptr, const char *str)
700 *(int *)ptr = atoi(str);
704 bool cdump_unbundle_unsigned(const void *ctx, void *ptr, const char *str)
706 *(unsigned *)ptr = strtoul(str, NULL, 10);
710 bool cdump_unbundle_time_t(const void *ctx, void *ptr, const char *str)
712 *(time_t *)ptr = strtoul(str, NULL, 10);
716 bool cdump_unbundle_double(const void *ctx, void *ptr, const char *str)
718 *(double *)ptr = atof(str);
722 bool cdump_unbundle_float(const void *ctx, void *ptr, const char *str)
724 *(float *)ptr = atof(str);
728 bool cdump_unbundle_size_t(const void *ctx, void *ptr, const char *str)
730 *(size_t *)ptr = strtoul(str, NULL, 10);
734 bool cdump_bundle_char(struct cdump_string *p, const void *ptr, unsigned indent)
736 return addshort(p, "%u", *(unsigned char *)ptr);
739 bool cdump_bundle_int(struct cdump_string *p, const void *ptr, unsigned indent)
741 return addshort(p, "%d", *(int *)ptr);
744 bool cdump_bundle_unsigned(struct cdump_string *p, const void *ptr, unsigned indent)
746 return addshort(p, "%u", *(unsigned *)ptr);
749 bool cdump_bundle_time_t(struct cdump_string *p, const void *ptr, unsigned indent)
751 return addshort(p, "%lu", (long int)*(time_t *)ptr);
754 bool cdump_bundle_double(struct cdump_string *p, const void *ptr, unsigned indent)
756 return addshort(p, "%lg", *(double *)ptr);
759 bool cdump_bundle_float(struct cdump_string *p, const void *ptr, unsigned indent)
761 return addshort(p, "%g", *(float *)ptr);
764 bool cdump_bundle_size_t(struct cdump_string *p, const void *ptr, unsigned indent)
766 return addshort(p, "%zu", *(size_t *)ptr);