mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
ef2e26c91b
(This used to be commit b0510b5428
)
787 lines
17 KiB
C
787 lines
17 KiB
C
/*
|
|
Copyright (C) Andrew Tridgell <genstruct@tridgell.net> 2002
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/*
|
|
automatic marshalling/unmarshalling system for C structures
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
/* see if a range of memory is all zero. Used to prevent dumping of zero elements */
|
|
static int all_zero(const char *ptr, unsigned size)
|
|
{
|
|
int i;
|
|
if (!ptr) return 1;
|
|
for (i=0;i<size;i++) {
|
|
if (ptr[i]) return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* encode a buffer of bytes into a escaped string */
|
|
static char *encode_bytes(TALLOC_CTX *mem_ctx, const char *ptr, unsigned len)
|
|
{
|
|
const char *hexdig = "0123456789abcdef";
|
|
char *ret, *p;
|
|
unsigned i;
|
|
ret = talloc(mem_ctx, len*3 + 1); /* worst case size */
|
|
if (!ret) return NULL;
|
|
for (p=ret,i=0;i<len;i++) {
|
|
if (isalnum(ptr[i]) || isspace(ptr[i]) ||
|
|
(ispunct(ptr[i]) && !strchr("\\{}", ptr[i]))) {
|
|
*p++ = ptr[i];
|
|
} else {
|
|
unsigned char c = *(const unsigned char *)(ptr+i);
|
|
if (c == 0 && all_zero(ptr+i, len-i)) break;
|
|
p[0] = '\\';
|
|
p[1] = hexdig[c>>4];
|
|
p[2] = hexdig[c&0xF];
|
|
p += 3;
|
|
}
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* decode an escaped string from encode_bytes() into a buffer */
|
|
static char *decode_bytes(TALLOC_CTX *mem_ctx, const char *s, unsigned *len)
|
|
{
|
|
char *ret, *p;
|
|
unsigned i;
|
|
int slen = strlen(s) + 1;
|
|
|
|
ret = talloc(mem_ctx, slen); /* worst case length */
|
|
if (!ret)
|
|
return NULL;
|
|
memset(ret, 0, slen);
|
|
|
|
if (*s == '{') s++;
|
|
|
|
for (p=ret,i=0;s[i];i++) {
|
|
if (s[i] == '}') {
|
|
break;
|
|
} else if (s[i] == '\\') {
|
|
unsigned v;
|
|
if (sscanf(&s[i+1], "%02x", &v) != 1 || v > 255) {
|
|
return NULL;
|
|
}
|
|
*(unsigned char *)p = v;
|
|
p++;
|
|
i += 2;
|
|
} else {
|
|
*p++ = s[i];
|
|
}
|
|
}
|
|
*p = 0;
|
|
|
|
(*len) = (unsigned)(p - ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* the add*() functions deal with adding things to a struct
|
|
parse_string */
|
|
|
|
/* allocate more space if needed */
|
|
static int addgen_alloc(TALLOC_CTX *mem_ctx, struct parse_string *p, int n)
|
|
{
|
|
if (p->length + n <= p->allocated) return 0;
|
|
p->allocated = p->length + n + 200;
|
|
p->s = talloc_realloc(mem_ctx, p->s, p->allocated);
|
|
if (!p->s) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* add a character to the buffer */
|
|
static int addchar(TALLOC_CTX *mem_ctx, struct parse_string *p, char c)
|
|
{
|
|
if (addgen_alloc(mem_ctx, p, 2) != 0) {
|
|
return -1;
|
|
}
|
|
p->s[p->length++] = c;
|
|
p->s[p->length] = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* add a string to the buffer */
|
|
int addstr(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *s)
|
|
{
|
|
int len = strlen(s);
|
|
if (addgen_alloc(mem_ctx, p, len+1) != 0) {
|
|
return -1;
|
|
}
|
|
memcpy(p->s + p->length, s, len+1);
|
|
p->length += len;
|
|
return 0;
|
|
}
|
|
|
|
/* add a string to the buffer with a tab prefix */
|
|
static int addtabbed(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *s, unsigned indent)
|
|
{
|
|
int len = strlen(s);
|
|
if (addgen_alloc(mem_ctx, p, indent+len+1) != 0) {
|
|
return -1;
|
|
}
|
|
while (indent--) {
|
|
p->s[p->length++] = '\t';
|
|
}
|
|
memcpy(p->s + p->length, s, len+1);
|
|
p->length += len;
|
|
return 0;
|
|
}
|
|
|
|
/* note! this can only be used for results up to 60 chars wide! */
|
|
int addshort(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *fmt, ...)
|
|
{
|
|
char buf[60];
|
|
int n;
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
n = vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
va_end(ap);
|
|
if (addgen_alloc(mem_ctx, p, n + 1) != 0) {
|
|
return -1;
|
|
}
|
|
if (n != 0) {
|
|
memcpy(p->s + p->length, buf, n);
|
|
}
|
|
p->length += n;
|
|
p->s[p->length] = 0;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
this is here to make it easier for people to write dump functions
|
|
for their own types
|
|
*/
|
|
int gen_addgen(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *fmt, ...)
|
|
{
|
|
char *buf = NULL;
|
|
int n;
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
n = vasprintf(&buf, fmt, ap);
|
|
va_end(ap);
|
|
if (addgen_alloc(mem_ctx, p, n + 1) != 0) {
|
|
if (buf) free(buf);
|
|
return -1;
|
|
}
|
|
if (n != 0) {
|
|
memcpy(p->s + p->length, buf, n);
|
|
}
|
|
p->length += n;
|
|
p->s[p->length] = 0;
|
|
if (buf) free(buf);
|
|
return 0;
|
|
}
|
|
|
|
/* dump a enumerated type */
|
|
int gen_dump_enum(TALLOC_CTX *mem_ctx,
|
|
const struct enum_struct *einfo,
|
|
struct parse_string *p,
|
|
const char *ptr,
|
|
unsigned indent)
|
|
{
|
|
unsigned v = *(const unsigned *)ptr;
|
|
int i;
|
|
for (i=0;einfo[i].name;i++) {
|
|
if (v == einfo[i].value) {
|
|
addstr(mem_ctx, p, einfo[i].name);
|
|
return 0;
|
|
}
|
|
}
|
|
/* hmm, maybe we should just fail? */
|
|
return gen_dump_unsigned(mem_ctx, p, ptr, indent);
|
|
}
|
|
|
|
/* dump a single non-array element, hanlding struct and enum */
|
|
static int gen_dump_one(TALLOC_CTX *mem_ctx,
|
|
struct parse_string *p,
|
|
const struct parse_struct *pinfo,
|
|
const char *ptr,
|
|
unsigned indent)
|
|
{
|
|
if (pinfo->dump_fn == gen_dump_char && pinfo->ptr_count == 1) {
|
|
char *s = encode_bytes(mem_ctx, ptr, strlen(ptr));
|
|
if (addchar(mem_ctx, p,'{') ||
|
|
addstr(mem_ctx, p, s) ||
|
|
addstr(mem_ctx, p, "}")) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return pinfo->dump_fn(mem_ctx, p, ptr, indent);
|
|
}
|
|
|
|
/* handle dumping of an array of arbitrary type */
|
|
static int gen_dump_array(TALLOC_CTX *mem_ctx,
|
|
struct parse_string *p,
|
|
const struct parse_struct *pinfo,
|
|
const char *ptr,
|
|
int array_len,
|
|
int indent)
|
|
{
|
|
int i, count=0;
|
|
|
|
/* special handling of fixed length strings */
|
|
if (array_len != 0 &&
|
|
pinfo->ptr_count == 0 &&
|
|
pinfo->dump_fn == gen_dump_char) {
|
|
char *s = encode_bytes(mem_ctx, ptr, array_len);
|
|
if (!s) return -1;
|
|
if (addtabbed(mem_ctx, p, pinfo->name, indent) ||
|
|
addstr(mem_ctx, p, " = {") ||
|
|
addstr(mem_ctx, p, s) ||
|
|
addstr(mem_ctx, p, "}\n")) {
|
|
return -1;
|
|
}
|
|
free(s);
|
|
return 0;
|
|
}
|
|
|
|
for (i=0;i<array_len;i++) {
|
|
const char *p2 = ptr;
|
|
unsigned size = pinfo->size;
|
|
|
|
/* generic pointer dereference */
|
|
if (pinfo->ptr_count) {
|
|
p2 = *(const char **)ptr;
|
|
size = sizeof(void *);
|
|
}
|
|
|
|
if ((count || pinfo->ptr_count) &&
|
|
!(pinfo->flags & FLAG_ALWAYS) &&
|
|
all_zero(ptr, size)) {
|
|
ptr += size;
|
|
continue;
|
|
}
|
|
if (count == 0) {
|
|
if (addtabbed(mem_ctx, p, pinfo->name, indent) ||
|
|
addshort(mem_ctx, p, " = %u:", i)) {
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (addshort(mem_ctx, p, ", %u:", i) != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
if (gen_dump_one(mem_ctx, p, pinfo, p2, indent) != 0) {
|
|
return -1;
|
|
}
|
|
ptr += size;
|
|
count++;
|
|
}
|
|
if (count) {
|
|
return addstr(mem_ctx, p, "\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* find a variable by name in a loaded structure and return its value
|
|
as an integer. Used to support dynamic arrays */
|
|
static int find_var(const struct parse_struct *pinfo,
|
|
const char *data,
|
|
const char *var)
|
|
{
|
|
int i;
|
|
const char *ptr;
|
|
|
|
/* this allows for constant lengths */
|
|
if (isdigit(*var)) {
|
|
return atoi(var);
|
|
}
|
|
|
|
for (i=0;pinfo[i].name;i++) {
|
|
if (strcmp(pinfo[i].name, var) == 0) break;
|
|
}
|
|
if (!pinfo[i].name) return -1;
|
|
|
|
ptr = data + pinfo[i].offset;
|
|
|
|
switch (pinfo[i].size) {
|
|
case sizeof(int):
|
|
return *(const int *)ptr;
|
|
case sizeof(char):
|
|
return *(const char *)ptr;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
int gen_dump_struct(TALLOC_CTX *mem_ctx,
|
|
const struct parse_struct *pinfo,
|
|
struct parse_string *p,
|
|
const char *ptr,
|
|
unsigned indent)
|
|
{
|
|
char *s = gen_dump(mem_ctx, pinfo, ptr, indent+1);
|
|
if (!s) return -1;
|
|
if (addstr(mem_ctx, p, "{\n") ||
|
|
addstr(mem_ctx, p, s) ||
|
|
addtabbed(mem_ctx, p, "}", indent)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int gen_dump_string(TALLOC_CTX *mem_ctx,
|
|
struct parse_string *p,
|
|
const struct parse_struct *pinfo,
|
|
const char *data,
|
|
unsigned indent)
|
|
{
|
|
const char *ptr = *(const char **)data;
|
|
char *s = encode_bytes(mem_ctx, ptr, strlen(ptr));
|
|
if (addtabbed(mem_ctx, p, pinfo->name, indent) ||
|
|
addstr(mem_ctx, p, " = ") ||
|
|
addchar(mem_ctx, p, '{') ||
|
|
addstr(mem_ctx, p, s) ||
|
|
addstr(mem_ctx, p, "}\n")) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
find the length of a nullterm array
|
|
*/
|
|
static int len_nullterm(const char *ptr, int size, int array_len)
|
|
{
|
|
int len;
|
|
|
|
if (size == 1) {
|
|
len = strnlen(ptr, array_len);
|
|
} else {
|
|
for (len=0; len < array_len; len++) {
|
|
if (all_zero(ptr+len*size, size)) break;
|
|
}
|
|
}
|
|
|
|
if (len == 0) len = 1;
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
/* the generic dump routine. Scans the parse information for this structure
|
|
and processes it recursively */
|
|
char *gen_dump(TALLOC_CTX *mem_ctx,
|
|
const struct parse_struct *pinfo,
|
|
const char *data,
|
|
unsigned indent)
|
|
{
|
|
struct parse_string p;
|
|
int i;
|
|
|
|
p.length = 0;
|
|
p.allocated = 0;
|
|
p.s = NULL;
|
|
|
|
if (addstr(mem_ctx, &p, "") != 0) {
|
|
return NULL;
|
|
}
|
|
|
|
for (i=0;pinfo[i].name;i++) {
|
|
const char *ptr = data + pinfo[i].offset;
|
|
unsigned size = pinfo[i].size;
|
|
|
|
if (pinfo[i].ptr_count) {
|
|
size = sizeof(void *);
|
|
}
|
|
|
|
/* special handling for array types */
|
|
if (pinfo[i].array_len) {
|
|
unsigned len = pinfo[i].array_len;
|
|
if (pinfo[i].flags & FLAG_NULLTERM) {
|
|
len = len_nullterm(ptr, size, len);
|
|
}
|
|
if (gen_dump_array(mem_ctx, &p, &pinfo[i], ptr,
|
|
len, indent)) {
|
|
goto failed;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* and dynamically sized arrays */
|
|
if (pinfo[i].dynamic_len) {
|
|
int len = find_var(pinfo, data, pinfo[i].dynamic_len);
|
|
struct parse_struct p2 = pinfo[i];
|
|
if (len < 0) {
|
|
goto failed;
|
|
}
|
|
if (len > 0) {
|
|
if (pinfo[i].flags & FLAG_NULLTERM) {
|
|
len = len_nullterm(*(const char **)ptr,
|
|
pinfo[i].size, len);
|
|
}
|
|
p2.ptr_count--;
|
|
p2.dynamic_len = NULL;
|
|
if (gen_dump_array(mem_ctx, &p, &p2,
|
|
*(const char **)ptr,
|
|
len, indent) != 0) {
|
|
goto failed;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* don't dump zero elements */
|
|
if (!(pinfo[i].flags & FLAG_ALWAYS) && all_zero(ptr, size)) continue;
|
|
|
|
/* assume char* is a null terminated string */
|
|
if (pinfo[i].size == 1 && pinfo[i].ptr_count == 1 &&
|
|
pinfo[i].dump_fn == gen_dump_char) {
|
|
if (gen_dump_string(mem_ctx, &p, &pinfo[i], ptr, indent) != 0) {
|
|
goto failed;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* generic pointer dereference */
|
|
if (pinfo[i].ptr_count) {
|
|
ptr = *(const char **)ptr;
|
|
}
|
|
|
|
if (addtabbed(mem_ctx, &p, pinfo[i].name, indent) ||
|
|
addstr(mem_ctx, &p, " = ") ||
|
|
gen_dump_one(mem_ctx, &p, &pinfo[i], ptr, indent) ||
|
|
addstr(mem_ctx, &p, "\n")) {
|
|
goto failed;
|
|
}
|
|
}
|
|
return p.s;
|
|
|
|
failed:
|
|
return NULL;
|
|
}
|
|
|
|
/* search for a character in a string, skipping over sections within
|
|
matching braces */
|
|
static char *match_braces(char *s, char c)
|
|
{
|
|
int depth = 0;
|
|
while (*s) {
|
|
switch (*s) {
|
|
case '}':
|
|
depth--;
|
|
break;
|
|
case '{':
|
|
depth++;
|
|
break;
|
|
}
|
|
if (depth == 0 && *s == c) {
|
|
return s;
|
|
}
|
|
s++;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/* parse routine for enumerated types */
|
|
int gen_parse_enum(TALLOC_CTX *mem_ctx,
|
|
const struct enum_struct *einfo,
|
|
char *ptr,
|
|
const char *str)
|
|
{
|
|
unsigned v;
|
|
int i;
|
|
|
|
if (isdigit(*str)) {
|
|
if (sscanf(str, "%u", &v) != 1) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
*(unsigned *)ptr = v;
|
|
return 0;
|
|
}
|
|
|
|
for (i=0;einfo[i].name;i++) {
|
|
if (strcmp(einfo[i].name, str) == 0) {
|
|
*(unsigned *)ptr = einfo[i].value;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* unknown enum value?? */
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* parse all base types */
|
|
static int gen_parse_base(TALLOC_CTX *mem_ctx,
|
|
const struct parse_struct *pinfo,
|
|
char *ptr,
|
|
const char *str)
|
|
{
|
|
if (pinfo->parse_fn == gen_parse_char && pinfo->ptr_count==1) {
|
|
unsigned len;
|
|
char *s = decode_bytes(mem_ctx, str, &len);
|
|
if (!s) return -1;
|
|
*(char **)ptr = s;
|
|
return 0;
|
|
}
|
|
|
|
if (pinfo->ptr_count) {
|
|
unsigned size = pinfo->ptr_count>1?sizeof(void *):pinfo->size;
|
|
struct parse_struct p2 = *pinfo;
|
|
*(void **)ptr = talloc(mem_ctx, size);
|
|
if (! *(void **)ptr) {
|
|
return -1;
|
|
}
|
|
memset(*(void **)ptr, 0, size);
|
|
ptr = *(char **)ptr;
|
|
p2.ptr_count--;
|
|
return gen_parse_base(mem_ctx, &p2, ptr, str);
|
|
}
|
|
|
|
return pinfo->parse_fn(mem_ctx, ptr, str);
|
|
}
|
|
|
|
/* parse a generic array */
|
|
static int gen_parse_array(TALLOC_CTX *mem_ctx,
|
|
const struct parse_struct *pinfo,
|
|
char *ptr,
|
|
const char *str,
|
|
int array_len)
|
|
{
|
|
char *p, *p2;
|
|
unsigned size = pinfo->size;
|
|
|
|
/* special handling of fixed length strings */
|
|
if (array_len != 0 &&
|
|
pinfo->ptr_count == 0 &&
|
|
pinfo->dump_fn == gen_dump_char) {
|
|
unsigned len = 0;
|
|
char *s = decode_bytes(mem_ctx, str, &len);
|
|
if (!s || (len > array_len)) return -1;
|
|
memset(ptr, 0, array_len);
|
|
memcpy(ptr, s, len);
|
|
return 0;
|
|
}
|
|
|
|
if (pinfo->ptr_count) {
|
|
size = sizeof(void *);
|
|
}
|
|
|
|
while (*str) {
|
|
unsigned idx;
|
|
int done;
|
|
|
|
idx = atoi(str);
|
|
p = strchr(str,':');
|
|
if (!p) break;
|
|
p++;
|
|
p2 = match_braces(p, ',');
|
|
done = (*p2 != ',');
|
|
*p2 = 0;
|
|
|
|
if (*p == '{') {
|
|
p++;
|
|
p[strlen(p)-1] = 0;
|
|
}
|
|
|
|
if (gen_parse_base(mem_ctx, pinfo, ptr + idx*size, p) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (done) break;
|
|
str = p2+1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* parse one element, hanlding dynamic and static arrays */
|
|
static int gen_parse_one(TALLOC_CTX *mem_ctx,
|
|
const struct parse_struct *pinfo,
|
|
const char *name,
|
|
char *data,
|
|
const char *str)
|
|
{
|
|
int i;
|
|
for (i=0;pinfo[i].name;i++) {
|
|
if (strcmp(pinfo[i].name, name) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (pinfo[i].name == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (pinfo[i].array_len) {
|
|
return gen_parse_array(mem_ctx, &pinfo[i],
|
|
data+pinfo[i].offset,
|
|
str, pinfo[i].array_len);
|
|
}
|
|
|
|
if (pinfo[i].dynamic_len) {
|
|
int len = find_var(pinfo, data, pinfo[i].dynamic_len);
|
|
if (len < 0) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (len > 0) {
|
|
struct parse_struct p2 = pinfo[i];
|
|
char *ptr;
|
|
unsigned size = pinfo[i].ptr_count>1?sizeof(void*):pinfo[i].size;
|
|
ptr = talloc(mem_ctx, len*size);
|
|
if (!ptr) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
memset(ptr, 0, len*size);
|
|
*((char **)(data + pinfo[i].offset)) = ptr;
|
|
p2.ptr_count--;
|
|
p2.dynamic_len = NULL;
|
|
return gen_parse_array(mem_ctx, &p2, ptr, str, len);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return gen_parse_base(mem_ctx, &pinfo[i], data + pinfo[i].offset, str);
|
|
}
|
|
|
|
int gen_parse_struct(TALLOC_CTX * mem_ctx, const struct parse_struct *pinfo, char *ptr, const char *str)
|
|
{
|
|
return gen_parse(mem_ctx, pinfo, ptr, str);
|
|
}
|
|
|
|
/* the main parse routine */
|
|
int gen_parse(TALLOC_CTX *mem_ctx, const struct parse_struct *pinfo, char *data, const char *s)
|
|
{
|
|
char *str, *s0;
|
|
|
|
s0 = strdup(s);
|
|
str = s0;
|
|
|
|
while (*str) {
|
|
char *p;
|
|
char *name;
|
|
char *value;
|
|
|
|
/* skip leading whitespace */
|
|
while (isspace(*str)) str++;
|
|
|
|
p = strchr(str, '=');
|
|
if (!p) break;
|
|
value = p+1;
|
|
while (p > str && isspace(*(p-1))) {
|
|
p--;
|
|
}
|
|
|
|
*p = 0;
|
|
name = str;
|
|
|
|
while (isspace(*value)) value++;
|
|
|
|
if (*value == '{') {
|
|
str = match_braces(value, '}');
|
|
value++;
|
|
} else {
|
|
str = match_braces(value, '\n');
|
|
}
|
|
|
|
*str++ = 0;
|
|
|
|
if (gen_parse_one(mem_ctx, pinfo, name, data, value) != 0) {
|
|
free(s0);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
free(s0);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* for convenience supply some standard dumpers and parsers here */
|
|
|
|
int gen_parse_char(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
|
|
{
|
|
*(unsigned char *)ptr = atoi(str);
|
|
return 0;
|
|
}
|
|
|
|
int gen_parse_int(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
|
|
{
|
|
*(int *)ptr = atoi(str);
|
|
return 0;
|
|
}
|
|
|
|
int gen_parse_unsigned(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
|
|
{
|
|
*(unsigned *)ptr = strtoul(str, NULL, 10);
|
|
return 0;
|
|
}
|
|
|
|
int gen_parse_time_t(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
|
|
{
|
|
*(time_t *)ptr = strtoul(str, NULL, 10);
|
|
return 0;
|
|
}
|
|
|
|
int gen_parse_double(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
|
|
{
|
|
*(double *)ptr = atof(str);
|
|
return 0;
|
|
}
|
|
|
|
int gen_parse_float(TALLOC_CTX *mem_ctx, char *ptr, const char *str)
|
|
{
|
|
*(float *)ptr = atof(str);
|
|
return 0;
|
|
}
|
|
|
|
int gen_dump_char(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
|
|
{
|
|
return addshort(mem_ctx, p, "%u", *(unsigned char *)(ptr));
|
|
}
|
|
|
|
int gen_dump_int(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
|
|
{
|
|
return addshort(mem_ctx, p, "%d", *(int *)(ptr));
|
|
}
|
|
|
|
int gen_dump_unsigned(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
|
|
{
|
|
return addshort(mem_ctx, p, "%u", *(unsigned *)(ptr));
|
|
}
|
|
|
|
int gen_dump_time_t(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
|
|
{
|
|
return addshort(mem_ctx, p, "%u", *(time_t *)(ptr));
|
|
}
|
|
|
|
int gen_dump_double(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
|
|
{
|
|
return addshort(mem_ctx, p, "%lg", *(double *)(ptr));
|
|
}
|
|
|
|
int gen_dump_float(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent)
|
|
{
|
|
return addshort(mem_ctx, p, "%g", *(float *)(ptr));
|
|
}
|