/*
* Copyright (c) 2004 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-u32.c,v 1.4 2004/09/02 01:14:31 ca Exp $")
#if SM_LIBCONF_ALONE
#include <ctype.h>
#include <errno.h>
#include "sm-conf.h"
#else /* SM_LIBCONF_ALONE */
#include "sm/ctype.h"
#include "sm/error.h"
#include "sm/sm-conf.h"
#endif /* SM_LIBCONF_ALONE */
#include "sm-conf-u32.h"
#include "sm-conf-util.h"
#include "sm-conf-state.h"
/*
** SM_MEMTOU32 -- strtoul without the nullbyte and the sign, sort of.
**
** Convert at most <text_n> bytes pointed to by <text> into
** an unsigned long no larger than 2^32-1.
**
** Assign a pointer to the first unconverted byte to
** *endptr.
**
** Parameters:
** text -- the text to be converted
** text_n -- # of bytes pointed to by text
** endptr -- if non-NULL, a pointer to the first
** unconverted byte is stored here.
** base -- 0 for dynamic, otherwise the base
** of the number. For bases above 10,
** an optional leading 0x is skipped.
** val_out -- value is stored here.
**
** Returns:
** EINVAL for a format error
** ERANGE for overflow
** 0 for success.
*/
int
sm_memtou32(
char const *text,
size_t text_n,
char **endptr,
int base,
unsigned long *val_out)
{
unsigned long val, n;
size_t i;
if (endptr != NULL)
*endptr = NULL;
if (val_out != NULL)
*val_out = 0;
i = 0;
n = 0;
/* Skip leading spaces. */
while (i < text_n && ISSPACE(text[i]))
i++;
if (text_n > i && text[i] == '0')
{
if ( text_n > 1
&& (base > 10 || base == 0)
&& (text[i + 1] == 'x' || text[i + 1] == 'X'))
{
if (base == 0)
base = 16;
i += 2;
}
else
{
if (base == 0)
base = 8;
}
}
else
{
if (base == 0)
base = 10;
}
if ( i >= text_n
|| !isascii(text[i])
|| !(base > 10 ? isalnum(text[i]) : isdigit(text[i])))
return EINVAL;
for (; i < text_n; i++)
{
if (!isascii(text[i]) || !isalnum(text[i]))
break;
if (isdigit(text[i]))
{
if ((val = text[i] - '0') >= base)
return EINVAL;
}
else if (base > 10)
{
char const *ptr;
char const *abc = "abcdefghijklmnopqrstuvwxyz";
ptr = strchr(abc, tolower(text[i]));
if (ptr == NULL)
break;
if (10 + (ptr - abc) >= base)
break;
val = 10 + (ptr - abc);
}
else
break;
if ((UINT32_MAX - val) / base < n)
return ERANGE;
n = n * base + val;
}
if (endptr != NULL)
*endptr = (char *)(text + i);
if (val_out != NULL)
*val_out = n;
return 0;
}
/*
** SM_CONF_U32_SCAN -- scan an integer into an ulong, possibly with suffixes.
**
** Civilized version of sm_memtou32. Prints error messages
** and evaluates suffixes under control of a definition.
**
** Parameters:
** smc -- context
** node -- NULL or node, for error messages
** def -- definition of the value; def->scd_contents are used
** for suffix values
** text -- text to scan
** text_n -- # of bytes we can access
** val_out -- result is stored here
**
** Returns:
** 0 on sucecss, an error code on error.
**
** Note: should it be optional to have additive suffixes?
*/
int
sm_conf_u32_scan(
sm_conf_T *smc,
sm_conf_node_T const *node,
sm_conf_definition_T const *def,
char const *text,
size_t text_n,
unsigned long *val_out)
{
char loc[SM_CONF_ERROR_BUFFER_SIZE];
size_t i, offset;
int err;
unsigned long val;
char *endptr;
SM_IS_CONF_DEF(def);
SM_REQUIRE(val_out != NULL);
offset = 0;
val = 0;
*val_out = 0;
do
{
SM_ASSERT(offset <= text_n);
err = sm_memtou32(text + offset, text_n - offset, &endptr, 0,
&val);
if (err != 0)
{
if (err == ERANGE)
sm_conf_error_add(smc,
"%s: overflow error in %s '%.*s'",
sm_conf_node_location(smc, node,
loc, sizeof loc),
def->scd_name[0] == '\0' ? "value"
: def->scd_name,
(int)text_n, text);
else
sm_conf_error_add(smc,
"%s: expected number, got '%.*s'",
sm_conf_node_location(smc, node,
loc, sizeof loc),
(int)text_n, text);
return SM_CONF_ERR_TYPE;
}
i = endptr - text;
/* skip over leading white space */
while (i < text_n && ISSPACE(text[i]))
i++;
/* If there's something left, and we have suffixes, use them. */
if (i < text_n)
{
sm_conf_definition_T const * suffix;
size_t len;
suffix = sm_conf_subdef_prefix(
def->scd_contents, sm_conf_type_u32_suffix,
text + i, text_n - i, &len);
SM_IS_CONF_DEF(def);
if (suffix == NULL || suffix->scd_offset == 0)
{
sm_conf_error_add(smc,
"%s: unexpected trailing characters in"
" '%.*s'",
sm_conf_node_location(smc, node,
loc, sizeof loc),
(int)text_n, text);
return SM_CONF_ERR_TYPE;
}
if ((UINT32_MAX / suffix->scd_offset) < val)
{
sm_conf_error_add(smc,
"%s: overflow error in %s '%.*s'",
sm_conf_node_location(smc, node,
loc, sizeof loc),
def->scd_name[0] == '\0'
? "value"
: def->scd_name,
(int)text_n, text);
return SM_CONF_ERR_TYPE;
}
val = val * suffix->scd_offset;
i += len;
}
*val_out += val;
offset = i;
} while (i < text_n);
return 0;
}
/*
** SM_CONF_U32_STORE -- store an unsigned long at a location
**
** Parameters:
** data -- the location to store at
** size -- # of bytes pointed to by <data>
** val -- the value to store
**
** Returns:
** 0 if the size is one of the supported integer
** sizes, otherwise SM_CONF_ERR_INVALID
*/
int
sm_conf_u32_store(
void *data,
size_t size,
unsigned long val)
{
if (size == 1)
*(unsigned char *)data = val;
else if (size == sizeof(unsigned short))
*(unsigned short *)data = val;
else if (size == sizeof(unsigned int))
*(unsigned int *)data = val;
else if (size == sizeof(unsigned long))
*(unsigned long *)data = val;
else
return SM_CONF_ERR_INVALID;
return 0;
}
/*
** SM_CONF_U32_LOAD -- load an unsigned long from a location
**
** Parameters:
** data -- the location to load from
** size -- # of bytes pointed to by <data>
** val -- the loaded value is assigned to this address
**
** Returns:
** 0 if the size is one of the supported integer
** sizes, otherwise SM_CONF_ERR_INVALID
*/
int
sm_conf_u32_load(
void const *data,
size_t size,
unsigned long *val)
{
if (size == 1)
*val = *(unsigned char const *)data;
else if (size == sizeof(unsigned short))
*val = *(unsigned short const *)data;
else if (size == sizeof(unsigned int))
*val = *(unsigned int const *)data;
else if (size == sizeof(unsigned long))
*val = *(unsigned long const *)data;
else
return SM_CONF_ERR_INVALID;
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1