/*
* Copyright (c) 2004-2006 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: sm-conf-type-section.c,v 1.23 2006/04/13 16:38:50 ca Exp $")
#if SM_LIBCONF_ALONE
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include "sm-conf.h"
#else /* SM_LIBCONF_ALONE */
#include "sm/string.h"
#include "sm/ctype.h"
#include "sm/memops.h"
#include "sm/sm-conf.h"
#endif /* SM_LIBCONF_ALONE */
#include "sm-conf-util.h"
#include "sm-conf-node.h"
#include "sm-conf-scan.h"
#include "sm-conf-state.h"
#include "sm-conf-type.h"
/*
** DEFINITION_FOR_SECTION -- (Utility) return the best definition
** for <kw>[ {<name>} ]
**
** We're looking at a section with a keyword and a title.
** There may be different definitions for sections
** with identical keywords but different titles.
**
** (That is, "server [smtp]" may be a completely different
** data type from "server [imap]".)
**
** An exact, more specific match overrides a generic,
** keyword-only match.
**
** Parameters:
** smc -- configuration parser state
** def -- definition for this section
** kw -- identifier we're lookign for
** kw_n -- # of bytes pointed to by <kw>, need
** not be '\0'-terminated
** name -- title after the identifier, or NULL
** name_n -- # of bytes pointed to by <name>, need
** not be '\0'-terminated.
**
** Returns:
** NULL if no matching definition is found,
** otherwise a pointer to the applicable definition.
*/
static sm_conf_definition_T const *
definition_for_section(
sm_conf_T *smc,
sm_conf_definition_T const *def,
char const *kw,
size_t kw_n,
char const *name,
size_t name_n)
{
char const *d, *p;
sm_conf_definition_T const *generic;
char const *kw_e;
char cl;
static char const obraces[] = "<({[\"'`",
cbraces[] = ">)}]\"''";
if (def == NULL)
return NULL;
SM_IS_CONF_DEF(def);
SM_REQUIRE(smc != NULL);
generic = NULL;
kw_e = (kw == NULL ? NULL : kw + kw_n);
while (def->scd_name != NULL)
{
p = kw;
d = def->scd_name;
while (isascii(*d) && (isalnum(*d) || *d == '_'))
{
if ( p >= kw_e
|| !isascii(*p)
|| tolower(*d) != tolower(*p))
goto next;
d++;
p++;
}
if (p != kw_e)
goto next;
if (name == NULL)
{
if (*d != '\0')
goto next;
return def;
}
if (*d == '\0')
{
generic = def;
goto next;
}
cl = 0;
if ((p = strchr(obraces, *d)) != NULL)
{
d++;
cl = cbraces[p - obraces];
}
p = d;
/* ignore closing bracket */
d += strlen(d);
if (d[-1] == cl)
d--;
if (sm_conf_token_match(smc, p, d - p, name, name_n))
return def;
next: def++;
}
return generic;
}
/*
** SECTION_ELEMENT_ERROR -- (Utility) print an error
**
** If name is non-NULL, the error is preceded not just
** by the ndoe location but also by the involved element name.
**
** Parameters:
** handle -- the configuration parser state
** node -- NULL or node that the error occured with
** name -- name of the section element, or NULL
** name_n -- if name is non-NULL, # of bytes pointed to by
** <name> (doesn't have to be '\0'-terminated)
** errstring -- error message to log
**
** Returns:
** None
**
** Side effect:
** Logs an error to the per-configuration-parser error
** state.
*/
static void
section_element_error(
sm_conf_T *handle,
sm_conf_node_T const *node,
char const *name,
size_t name_n,
char const *errstring)
{
char loc[SM_CONF_ERROR_BUFFER_SIZE];
SM_REQUIRE(handle != NULL);
if (name_n > 0 && name != NULL)
sm_conf_error_add(handle, "%s: %*s: %s",
sm_conf_node_location(handle, node, loc, sizeof loc),
(int)name_n, name, errstring);
else
sm_conf_error_add(handle, "%s: %s",
sm_conf_node_location(handle, node, loc, sizeof loc),
errstring);
}
/*
** SM_CONF_SECTION_ANONYMOUS_DEFAULT -- (Utility) find a node to
** default from (1)
**
** Look in this node's ancestral chain for sections of the
** specified type (keyword) with no name directly contained in
** an ancestor.
**
** Return the lowest section that is <node> or above it.
**
** Parameters:
** handle -- the context
** kw -- type (keyword) we're looking for
** kw_n -- length kw.
** node -- where to start looking
**
** Returns:
** The lowest section that is <node> or above it.
*/
sm_conf_node_T *
sm_conf_section_anonymous_default(
sm_conf_T *handle,
char const *kw,
size_t kw_n,
sm_conf_node_T const *node)
{
char const *snm;
size_t snm_n;
sm_conf_node_T *sib;
if (node == NULL)
return NULL;
while ( (node = sm_conf_node_parent(handle, node)) != NULL
&& sm_conf_node_type(handle, node) == SM_CONF_NODE_SECTION)
{
sib = NULL;
while ( (sib = sm_conf_section_next_subsection(handle,
node, kw, kw_n, "", 0, sib)) != NULL)
{
if (sm_conf_section_name(handle, sib, &snm, &snm_n) == 0
&& snm == NULL)
return sib;
}
}
return NULL;
}
/*
** SM_CONF_SECTION_ENVIRONMENT_DEFAULT -- (Utility) find a node
** to default from (2)
**
** Look in this node's ancestral chain for a containing
** section that contains the specified property.
** Return the lowest section that has it.
**
** Parameters:
** handle -- the context
** name -- property we're looking for
** name_n -- length of <name>.
** node -- where to start looking
**
** Returns:
** Lowest container with a suitable default value,
** or NULL if none was found.
*/
static sm_conf_node_T const *
sm_conf_section_environment_default(
sm_conf_T *handle,
char const *name,
size_t name_n,
sm_conf_node_T const *node)
{
while ( (node = sm_conf_node_parent(handle, node)) != NULL
&& sm_conf_node_type(handle, node) == SM_CONF_NODE_SECTION)
{
if (sm_conf_section_next_option(handle, node, name,
name_n, NULL) != NULL)
return node;
}
return NULL;
}
/*
** SM_CONF_SCAN_SECTION_DEFAULT_ELEMENT_NODE -- (Utility) scan default values
**
** We're trying to default one element of a section.
** (We've got its definition.) We've found another section
** that could serve as a template for the one we're parsing
** right now.
**
** Scout the template section for values to assing to the
** empty element. If you find one, use it. (If the element
** is multivalued, keep on scanning after finding one; there
** may be others.)
**
** Parameters:
** handle -- the configuration parser context
** def -- section definition for the element we're
** trying to assign.
** node -- the container section that we're pulling
** defaults out of
** data -- user data (begin of struct)
**
** Returns:
** If no elements could be defaulted form the surrounding
** section, the call returns SM_CONF_ERR_NOT_FOUND.
** Otherwise, it returns 0 on success,
** potentially other nonzero error codes on error.
*/
static int
sm_conf_scan_section_default_element_node(
sm_conf_T *handle,
sm_conf_definition_T const *def,
sm_conf_node_T const *node,
void *data)
{
size_t def_name_n;
int any = 0;
int err = 0;
sm_conf_node_T *elem;
sm_conf_node_T *pred;
SM_IS_CONF_DEF(def);
def_name_n = strlen(def->scd_name);
SM_LC_ISA(def, data);
pred = NULL;
for (;;)
{
elem = sm_conf_section_next_option(handle,
node, def->scd_name, def_name_n, pred);
if (elem == NULL)
break;
pred = elem;
any = 1;
err = sm_conf_scan_node_to_value(handle,
def->scd_name, strlen(def->scd_name),
def, elem,
data == NULL ? NULL : (char *)data + def->scd_offset);
if (err != 0)
return err;
if (!(def->scd_flags & SM_CONF_FLAG_MULTIPLE))
break;
}
if (!any)
return SM_CONF_ERR_NOT_FOUND;
if (data == NULL)
return 0;
#if SM_LIBCONF_ISSET
if (def->scd_isset_offset > 0)
*((uchar *)data + def->scd_isset_offset) = SM_LC_SET_FRM_ENV;
#endif
return sm_conf_scan_value_check(handle, def->scd_name,
strlen(def->scd_name), def, node, data);
}
/*
** SM_CONF_SCAN_SECTION_DEFAULT_ELEMENT -- (Utility) default an element.
**
** Find sections we might be defaulting from in the environment
** and feed them to sm_conf_scan_section_default_element_node()
** for closer examination, until we find something or run out.
**
** Parameters:
** handle -- the configuration parser context
** def -- section definition for the element we're
** trying to assign.
** section -- the section we're defaulting in.
** default_node -- corresponding anonymous default node
** in the same parent, if any.
** data -- user data (begin of struct), or NULL
**
** Returns:
** If no elements could be defaulted form the surrounding
** section, the call returns SM_CONF_ERR_NOT_FOUND.
** Otherwise, it returns 0 on success,
** potentially other nonzero error codes on error.
*/
static int
sm_conf_scan_section_default_element(
sm_conf_T *handle,
sm_conf_definition_T const *def,
sm_conf_node_T const *section,
sm_conf_node_T const *default_node,
void *data)
{
size_t def_name_n;
int err;
SM_IS_CONF_DEF(def);
err = 0;
def_name_n = strlen(def->scd_name);
/*
** Try defaulting the element using our corresponding
** anonymous default_node, if any.
*/
if (default_node != NULL)
{
err = sm_conf_scan_section_default_element_node(handle, def,
default_node, data);
if (err != SM_CONF_ERR_NOT_FOUND)
return err;
}
/*
** If that didn't find anything, and we've got a named property,
** and this particular property drifts down from the environment,
** look for a surrounding section that contains it, and use
** those section's settings.
*/
if ( !(def->scd_flags & SM_CONF_FLAG_DEFAULT_FROM_ENVIRONMENT)
|| (default_node = sm_conf_section_environment_default(handle,
def->scd_name, strlen(def->scd_name),
section)) == NULL)
return SM_CONF_ERR_NOT_FOUND;
return sm_conf_scan_section_default_element_node(handle, def,
default_node, data);
}
/*
** SM_CONF_TYPE_SECTION_TITLE_NODE_TO_VALUE -- (Method) store a title
**
** If specified in a section's definitions, convert the name
** of a section to a data string and store it.
**
** This is how you access the "bar" in
**
** foo "bar"
** {
** ...
** }
**
** Parameters:
** smc -- the configuration parser context
** def -- definition for the section title
** section -- the section whose title is being scanned
** data -- user data (element itself), or NULL
**
** Returns:
** 0 on success, a nonzero error on error.
*/
static int
sm_conf_type_section_title_node_to_value(
sm_conf_T *smc,
sm_conf_definition_T const *def,
sm_conf_node_T *section,
void *data)
{
int err;
char const *name;
size_t name_n;
char loc[SM_CONF_ERROR_BUFFER_SIZE];
SM_IS_CONF_DEF(def);
err = sm_conf_section_name(smc, section, &name, &name_n);
if (err != 0)
return err;
if (name_n > 0 && memchr(name, '\0', name_n) != NULL)
{
sm_conf_error_add(smc, "%s: NUL in section title '%.*s'",
sm_conf_node_location(smc, section, loc, sizeof loc),
(int)name_n, name);
return SM_CONF_ERR_TYPE;
}
if (data == NULL)
return 0;
SM_LC_ISA(def, data);
if (def->scd_size == 0)
*(char const **)data = name;
else
{
if (name_n >= def->scd_size)
{
sm_conf_error_add(smc, "%s: overflow error: section "
"title '%.*s' more than %lu character%s long",
sm_conf_node_location(smc, section,
loc, sizeof loc),
(int)name_n, name,
(unsigned long)def->scd_size - 1,
def->scd_size == 2 ? "" : "s");
return SM_CONF_ERR_TYPE;
}
if (name_n != 0)
memcpy(data, name, name_n);
((char *)data)[name_n] = '\0';
}
return 0;
}
/*
** SM_CONF_TYPE_SECTION_TITLE_VALUE_CHECK -- (Method) check a value
**
** (Not yet implemented/No-OP)
**
** Parameters:
** smc -- the configuration parser context
** def -- definition for the section title
** data -- user data, or NULL
**
** Returns:
** 0 on success, a nonzero error on error.
*/
static int
sm_conf_type_section_title_value_check(
sm_conf_T *smc,
sm_conf_definition_T const *def,
void const *data)
{
SM_IS_CONF_DEF(def);
return 0;
}
/*
** SM_CONF_TYPE_SECTION_TITLE_VALUE_NULL -- (Method) zero out a value
**
** Parameters:
** smc -- the configuration parser context
** def -- definition for the section title
** data -- user data (element itself), or NULL
**
** Returns:
** 0 on success, a nonzero error on error.
*/
static int
sm_conf_type_section_title_value_null(
sm_conf_T *smc,
sm_conf_definition_T const *def,
void *data)
{
SM_IS_CONF_DEF(def);
if (def->scd_size > 0)
sm_memset(data, 0, def->scd_size);
else
*(char const **)data = NULL;
return 0;
}
sm_conf_type_T const
sm_conf_type_section_title_data =
{
sm_conf_type_section_title_node_to_value,
sm_conf_type_section_title_value_check,
sm_conf_type_section_title_value_null
};
/*
** SM_CONF_TYPE_SECTION_NODE_TO_VALUE_TITLE -- (Utiltiy) convert section title
**
** This utility not only triggers conversion and storage
** of the title itself, it also checks for title-related
** constraint violation (titles of sections that mustn't
** have one, or the opposite.)
**
** Parameters:
** smc -- the configuration parser context
** defs -- array of definition for the section members
** flags -- section flags
** section -- section node
** data -- user data (begin of struct), or NULL
**
** Returns:
** 0 on success, a nonzero error on error.
*/
static int
sm_conf_type_section_node_to_value_title(
sm_conf_T *smc,
sm_conf_definition_T const *defs,
unsigned int flags,
sm_conf_node_T *section,
void *data)
{
int err;
char const *name;
size_t name_n;
sm_conf_definition_T const *sub;
/* Scan the section name, if there is one. */
err = sm_conf_section_name(smc, section, &name, &name_n);
if (err != 0)
return err;
/* check for constraints on the whole section. */
if ( (flags & SM_CONF_FLAG_SECTION_MUST_BE_NAMED)
&& name == NULL)
{
if (sm_conf_section_keyword(smc, section, &name, &name_n))
{
name = NULL;
name_n = 0;
}
section_element_error(smc, section,
name, name_n, "section must have a name");
return SM_CONF_ERR_TYPE;
}
else if ( (flags & SM_CONF_FLAG_SECTION_MUST_BE_ANONYMOUS)
&& name != NULL)
{
section_element_error(smc, section, name, name_n,
"section cannot have a name");
return SM_CONF_ERR_TYPE;
}
sub = sm_conf_subdef(defs, sm_conf_type_section_title, NULL, 0);
if (sub == NULL)
return 0;
return sm_conf_type_section_title_node_to_value(smc, sub, section,
data == NULL ? NULL : (char *)data + sub->scd_offset);
}
/*
** SM_CONF_TYPE_SECTION_NODE_TO_VALUE_SUBDEF --
** (Utiltiy) convert section members
**
** Parameters:
** smc -- the configuration parser context
** defs -- array of definition for the section members
** flags -- section flags
** section -- whole section node
** data -- user data (begin of struct), or NULL
**
** Returns:
** 0 on success, a nonzero error on error.
*/
int
sm_conf_type_section_node_to_value_subdef(
sm_conf_T *smc,
sm_conf_definition_T const *defs,
unsigned int flags,
sm_conf_node_T *section,
void *data)
{
sm_conf_definition_T const *def;
sm_conf_node_T *default_node;
sm_conf_node_T *sub;
char const *name;
size_t name_n;
int err, section_error;
char seen_buf[256], *seen_ptr;
size_t seen_m;
if (smc == NULL)
return SM_CONF_ERR_INVALID;
err = 0;
memset(seen_buf, 0, sizeof seen_buf);
seen_ptr = seen_buf;
seen_m = sizeof seen_buf;
if ( (flags & SM_CONF_FLAG_SECTION_MUST_BE_NAMED)
&& (flags & SM_CONF_FLAG_SECTION_MUST_BE_ANONYMOUS))
{
section_element_error(smc, section, NULL, 0, "definition "
"requires that section be both named and anonymous?");
return SM_CONF_ERR_INVALID;
}
/*
** If we default from anonymous sections, and this section
** isn't anonymous, find one we can default from.
*/
if ( (flags & SM_CONF_FLAG_SECTION_DEFAULT_FROM_ANONYMOUS)
&& section != NULL
&& sm_conf_section_name(smc, section, &name, &name_n) == 0
&& name != NULL
&& sm_conf_section_keyword(smc, section, &name, &name_n) == 0)
default_node = sm_conf_section_anonymous_default(smc,
name, name_n, section);
else
default_node = NULL;
/* Assign NULL values to anything that doesn't keep its default */
if (defs != NULL && data != NULL)
{
for (def = defs; def != NULL && def->scd_name != NULL; def++)
{
if (!( (flags | def->scd_flags)
& ( SM_CONF_FLAG_KEEP_DEFAULT
| SM_CONF_FLAG_PARSE_ONLY)))
{
SM_LC_ISA(def, data);
err = (* def->scd_type->sctp_value_null)(
smc, def,
(char *)data + def->scd_offset);
if (err != 0)
return err;
}
}
}
section_error = 0;
if (section != NULL)
{
err = sm_conf_type_section_node_to_value_title(
smc, defs, flags, section, data);
if (err != 0)
{
section_error = err;
err = 0;
}
/* Scan all section elements. */
sub = NULL;
while ((sub = sm_conf_section_next(smc, section,
&name, &name_n, sub)) != NULL)
{
char const *sub_kw, *sub_name;
size_t sub_kw_n, sub_name_n;
if (name_n == 0)
name = NULL;
def = NULL;
if (name != NULL)
def = sm_conf_subdef(defs, NULL, name, name_n);
else
{
if ( sm_conf_section_keyword(smc, sub,
&sub_kw, &sub_kw_n) == 0
&& sm_conf_section_name(smc, sub,
&sub_name, &sub_name_n) == 0)
{
def = definition_for_section(smc, defs,
sub_kw, sub_kw_n,
sub_name, sub_name_n);
}
}
/* def is now NULL or the applicable definition. */
if (def == NULL)
{
/* Undefined name. Do we allow that? */
if (!(flags & ( name == NULL
? SM_CONF_FLAG_ALLOW_ANY_SECTION
: SM_CONF_FLAG_ALLOW_ANY_OPTION)))
{
if (name == NULL)
section_element_error(smc, sub,
sub_kw, sub_kw_n,
"unexpected section");
else
section_element_error(smc, sub,
name, name_n,
"unexpected option");
if (section_error == 0)
section_error = SM_CONF_ERR_TYPE;
}
/*
** We have nowhere to store this value now,
** but other parts of the using application
** may ask for it later by name, e.g.
** based on user input.
*/
continue;
}
if (!(def->scd_flags & SM_CONF_FLAG_MULTIPLE))
{
size_t bit_i;
unsigned char bit_mask;
bit_i = (def - defs) / CHAR_BIT;
bit_mask = 1 << ((def - defs) % CHAR_BIT);
if (bit_i >= seen_m)
{
sm_conf_definition_T const *hi;
SM_ASSERT(seen_ptr == seen_buf);
for (hi = def;
hi->scd_name != NULL;
hi++)
;
seen_m = ((hi - defs) + (CHAR_BIT - 1))
/ CHAR_BIT;
seen_ptr = malloc(seen_m);
if (seen_ptr == NULL)
return SM_CONF_ERR_NO_MEMORY;
memset(seen_ptr, 0, seen_m);
memcpy(seen_ptr, seen_buf,
sizeof seen_buf);
}
if (seen_ptr[bit_i] & bit_mask)
{
section_element_error(smc, section,
def->scd_name,
strlen(def->scd_name),
name == NULL
? "duplicate section"
: "duplicate option");
section_error = SM_CONF_ERR_ALREADY;
}
seen_ptr[bit_i] |= bit_mask;
}
if ((def->scd_flags | flags) & SM_CONF_FLAG_PARSE_ONLY)
{
err = sm_conf_scan_node_to_value(smc, name,
name_n, def, sub, NULL);
}
else
{
SM_LC_ISA(def, data);
/*
** Inherit the default value for a multiple
** choice value now so it can be changed
** "locally".
*/
if (sm_conf_type_choice == def->scd_type &&
data != NULL &&
(def->scd_flags & SM_CONF_FLAG_OR) != 0 &&
(def->scd_flags &
SM_CONF_FLAG_STRICTLY_REQUIRED) == 0)
{
err = sm_conf_scan_section_default_element(
smc, def, section, default_node,
data);
}
err = sm_conf_scan_node_to_value(smc, name,
name_n, def, sub,
data == NULL ? NULL :
(char *)data + def->scd_offset);
#if SM_LIBCONF_ISSET
/*
** Use different values depending on how data
** got set??
*/
if (0 == err && data != NULL &&
def->scd_isset_offset > 0)
{
*((uchar *)data + def->scd_isset_offset)
= SM_LC_SET_DIRECT;
}
#endif
}
if (err != 0)
section_error = err;
/* If there was an error, find more. */
}
}
if (section_error != 0)
{
if (seen_ptr != seen_buf)
free(seen_ptr);
return section_error;
}
/*
** Confirm that all mandatory elements of the definition did occur.
** If we can default elements, default those that didn't occur.
*/
for (def = defs; def != NULL && def->scd_name != NULL; def++)
{
sm_conf_node_T const *elem;
elem = NULL;
if ( section != NULL
&& def->scd_type == sm_conf_type_section_title)
{
if ( (def->scd_flags & ( SM_CONF_FLAG_STRICTLY_REQUIRED
| SM_CONF_FLAG_REQUIRED))
&& sm_conf_section_name(smc, section, &name, &name_n)
== 0
&& name == NULL)
{
if (sm_conf_section_keyword(smc, section,
&name, &name_n))
{
name = NULL;
name_n = 0;
}
section_element_error(smc, section,
name, name_n,
"section must have a name");
return SM_CONF_ERR_TYPE;
}
err = sm_conf_scan_value_check(smc,
"section title", sizeof("section title") - 1,
def, section,
data == NULL ? NULL
: (char *)data + def->scd_offset);
if (err != 0)
section_error = err;
/* The section name is never defaulted. */
continue;
}
if (section != NULL)
elem = sm_conf_section_next_option(
smc, section, def->scd_name,
strlen(def->scd_name), NULL);
if (elem == NULL)
{
/*
** The real node didn't match this definition.
** See if we default from something.
*/
err = SM_CONF_ERR_NOT_FOUND;
if (!(def->scd_flags & SM_CONF_FLAG_STRICTLY_REQUIRED))
{
err = sm_conf_scan_section_default_element(
smc, def, section, default_node,
data);
if (err != 0)
{
if ( err == SM_CONF_ERR_NOT_FOUND
&& !( def->scd_flags
& SM_CONF_FLAG_REQUIRED))
/* it was optional. */
err = 0;
}
}
if (err != 0)
{
section_element_error(smc, section,
def->scd_name, strlen(def->scd_name),
def->scd_name[0] == '\0'
? "missing value"
: "missing property");
section_error = err;
}
}
/*
** Now that it's been fully converted, check the constraint
** for this element.
*/
if (section_error == 0 && data != NULL)
{
err = sm_conf_scan_value_check(smc,
def->scd_name, strlen(def->scd_name),
def, elem,
(char *)data + def->scd_offset);
if (err != 0)
section_error = err;
}
}
if (seen_ptr != seen_buf)
free(seen_ptr);
return section_error;
}
/*
** SM_CONF_TYPE_SECTION_NODE_TO_VALUE -- (Method) convert section
**
** Parameters:
** smc -- the configuration parser context
** section_def -- definition for the section
** section -- whole section node
** data -- user data (begin of struct), or NULL
**
** Returns:
** 0 on success, a nonzero error on error.
*/
static int
sm_conf_type_section_node_to_value(
sm_conf_T *smc,
sm_conf_definition_T const *section_def,
sm_conf_node_T *section,
void *data)
{
return sm_conf_type_section_node_to_value_subdef(
smc, section_def->scd_contents,
section_def->scd_flags, section, data);
}
/*
** SM_CONF_TYPE_SECTION_VALUE_CHECK -- (Method) check value against
** section constraints
**
** Parameters:
** smc -- the configuration parser context
** def -- definition for the section
** data -- user data (begin of struct), or NULL
**
** Returns:
** 0 on success, a nonzero error on error.
*/
static int
sm_conf_type_section_value_check(
sm_conf_T *smc,
sm_conf_definition_T const *def,
void const *data)
{
sm_conf_definition_T const *sub;
int err;
SM_IS_CONF_DEF(def);
/* If we have nothing to check, don't do anything. */
if (data == NULL)
return 0;
/* recursively check the section's contents. */
for (sub = def->scd_contents;
sub != NULL && sub->scd_name != NULL;
sub++)
{
err = (* sub->scd_type->sctp_value_check)(smc, sub,
(char *)data + sub->scd_offset);
if (err != 0)
return err;
}
/* if we have a check function, use it. */
if (def->scd_check != NULL)
return (* def->scd_check)(smc, def->scd_check_data, def, data);
return 0;
}
/*
** SM_CONF_TYPE_SECTION_VALUE_NULL -- (Method) zero out a data buffer
**
** Parameters:
** smc -- the configuration parser context
** def -- definition for the section
** data -- user data, or NULL
**
** Returns:
** 0 on success, a nonzero error on error.
*/
static int
sm_conf_type_section_value_null(
sm_conf_T *smc,
sm_conf_definition_T const *def,
void *data)
{
sm_conf_definition_T const *d;
int err;
SM_IS_CONF_DEF(def);
if (data == NULL)
return 0;
/*
** This zero's out the user struct; is this really necessary??
** It destroy any magic that's in there! It is only prevented if
** SM_CONF_FLAG_KEEP_DEFAULT (or SM_CONF_FLAG_PARSE_ONLY) is set!
*/
if (def->scd_size > 0)
sm_memset(data, 0, def->scd_size);
for (d = def->scd_contents; d != NULL && d->scd_name != NULL; d++)
{
SM_LC_ISA(d, data);
err = (* d->scd_type->sctp_value_null)(
smc, d, (char *)data + d->scd_offset);
if (err != 0)
return err;
}
return 0;
}
sm_conf_type_T const
sm_conf_type_section_data =
{
sm_conf_type_section_node_to_value,
sm_conf_type_section_value_check,
sm_conf_type_section_value_null
};
syntax highlighted by Code2HTML, v. 0.9.1