/*
* 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-scan.c,v 1.13 2006/04/13 19:00:15 ca Exp $")
#if SM_LIBCONF_ALONE
#include <string.h>
#include "sm-conf.h"
#else /* SM_LIBCONF_ALONE */
#include "sm/string.h"
#include "sm/memops.h"
#include "sm/sm-conf.h"
#endif /* SM_LIBCONF_ALONE */
#include "sm-conf-scan.h"
#include "sm-conf-state.h"
#include "sm-conf-type.h"
/*
** SM_CONF_SCAN_VALUE_CHECK -- an error with a name, if one is there.
**
** Parameters:
** handle -- the overall handle of the configuration file
** node -- current node
** name -- name of option
** name_n -- # of bytes pointed to by <name>
** errstring -- error string
**
** Returns:
** none
*/
static void
named_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];
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_SCAN_VALUE_CHECK -- check validity of value (via callback)
**
** Parameters:
** handle -- the overall handle of the configuration file
** name -- name of option
** name_n -- # of bytes pointed to by <name>
** def -- definition
** node -- the node we're checking
** data -- user data (element itself), or NULL
**
** Returns:
** 0 on success, an error value on error.
*/
int
sm_conf_scan_value_check(
sm_conf_T *handle,
char const *name,
size_t name_n,
sm_conf_definition_T const *def,
sm_conf_node_T const *node,
void *data)
{
size_t n_err_before;
int err;
SM_IS_CONF_DEF(def);
/* Don't check if there's nothing to check. */
if (data == NULL)
return 0;
n_err_before = handle->smc_error_n;
err = (* def->scd_type->sctp_value_check)(handle, def, data);
/* there was an error, but it wasn't logged? */
if (err && n_err_before == handle->smc_error_n)
{
char errbuf[SM_CONF_ERROR_BUFFER_SIZE];
/* log it ourselves. */
named_error(handle, node, name, name_n,
sm_conf_strerror(err, errbuf, sizeof errbuf));
}
return err;
}
/*
** SM_CONF_SCAN_NODE_TO_VALUE -- convert content of node into a value
**
** Parameters:
** handle -- the overall handle of the configuration file
** name -- name of option
** name_n -- # of bytes pointed to by <name>, need
** not be '\0'-terminated.
** def -- definition
** node -- the node we're scanning
** data -- user data (element itself), or NULL
**
** Returns:
** 0 on success, an error value on error.
*/
int
sm_conf_scan_node_to_value(
sm_conf_T *handle,
char const *name,
size_t name_n,
sm_conf_definition_T const *def,
sm_conf_node_T *node,
void *data)
{
size_t n_err_before;
int err;
SM_IS_CONF_DEF(def);
n_err_before = handle->smc_error_n;
err = (* def->scd_type->sctp_node_to_value)(handle, def, node, data);
/* there was an error, but it wasn't logged? */
if (err && n_err_before == handle->smc_error_n)
{
char errbuf[SM_CONF_ERROR_BUFFER_SIZE];
/* log it ourselves. */
named_error(handle, node, name, name_n,
sm_conf_strerror(err, errbuf, sizeof errbuf));
}
return err;
}
/*
** SM_CONF_SCAN_NODE -- fill out a structure according to definitions
**
** Use the data and callbacks in <def> to translate
** the parse tree in <handle> into values assigned to the
** struct(s) pointed to by <data>.
**
** Parameters:
** handle -- the overall handle of the configuration file
** definitions -- list of names and their meanings.
** node -- the node we're scanning
** data -- base pointer of a structure into which
** values are copied.
**
** Returns:
** 0 on success, an error value on error.
*/
int
sm_conf_scan_node(
sm_conf_T *handle,
sm_conf_definition_T const *def,
sm_conf_node_T *node,
void *data)
{
int err;
if (handle == NULL || def == NULL)
return SM_CONF_ERR_INVALID;
if (def->scd_name == NULL)
{
char loc[SM_CONF_ERROR_BUFFER_SIZE];
sm_conf_error_add(handle, "%s: unexpected value "
"(NULL definition list)",
sm_conf_node_location(handle, node, loc, sizeof loc));
return SM_CONF_ERR_INVALID;
}
SM_IS_CONF_DEF(def);
err = sm_conf_scan_node_to_value(handle,
def->scd_name, strlen(def->scd_name), def, node, data);
if (err != 0)
return err;
return sm_conf_scan_value_check(handle,
def->scd_name, strlen(def->scd_name), def, node, data);
}
/*
** SM_CONF_SCAN -- fill out a structure according to definitions
**
** Use the data and callbacks in <definitions> to translate
** the parse tree in <handle> into values assigned to the
** struct(s) pointed to by <data>.
**
** Parameters:
** handle -- the overall handle of the configuration file
** definitions -- list of names and their meanings.
** If it starts with a node whose name is "",
** it's a definition for the whole node;
** otherwise, the node must be a section, and
** the definitions are for the section contents.
** flags -- parameters of the node as a whole
** data -- base pointer of a structure into which
** values are copied.
*/
int
sm_conf_scan(
sm_conf_T *handle,
sm_conf_definition_T const *definitions,
unsigned int flags,
void *data)
{
sm_conf_definition_T section_def[2];
if (handle == NULL)
return SM_CONF_ERR_INVALID;
if (definitions == NULL || definitions->scd_name == NULL)
return SM_CONF_ERR_INVALID;
if (definitions->scd_name[0] != '\0')
{
sm_memset(§ion_def, 0, sizeof section_def);
section_def[0].sm_magic = SM_CONF_DEF_MAGIC;
section_def[0].scd_name = "";
section_def[0].scd_type = sm_conf_type_section;
section_def[0].scd_default = NULL;
section_def[0].scd_flags = flags;
section_def[0].scd_contents = definitions;
section_def[1].scd_name = NULL;
definitions = section_def;
}
return sm_conf_scan_node(handle, definitions, handle->smc_root, data);
}
syntax highlighted by Code2HTML, v. 0.9.1