Files
microser/mmslib/util/cfg_util.c
2026-06-15 15:48:16 +08:00

890 lines
26 KiB
C

/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/* (c) Copyright Systems Integration Specialists Company, Inc., */
/* 1991-2006, All Rights Reserved */
/* */
/* MODULE NAME : cfg_util.c */
/* PRODUCT(S) : */
/* */
/* MODULE DESCRIPTION : */
/* */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 02/07/06 EJV 18 cfg_special_char_str: added '$'. */
/* 02/20/03 JRB 17 Del PSOS code. */
/* 11/29/01 EJV 16 Del code for old LATT, XENIX, ultrix, RMX86. */
/* Removed call to strcasecmp (sun) */
/* 10/18/01 JRB 15 Add str_util.h (for strcmpi, etc. protos) */
/* 01/19/01 EJV 14 Moved strcmpi,stricmp,strnicmp to str_util.c */
/* 11/07/00 JRB 13 Del QNX from ifdef. It supports stricmp, etc.*/
/* 04/28/00 JRB 12 Lint cleanup */
/* 09/13/99 MDE 11 Added SD_CONST modifiers */
/* 04/14/99 MDE 10 Replaced SYSTEM_SEL with compiler defines */
/* 10/08/98 MDE 09 Migrated to updated SLOG interface */
/* 08/24/98 EJV 08 Added __hpux to str* cmp functions */
/* 08/06/98 JRB 07 Added cfg_get_octet_string function. */
/* 06/15/98 MDE 06 Changes to allow compile under C++ */
/* 05/22/98 EJV 05 added _AIX, sun, and __alpha to */
/* stricmp, strcmpi, strnicmp functions */
/* 04/03/98 RKR 04 added stricmp, strcmpi, strnicmp */
/* 12/22/97 JRB 03 Clean up PSOS code. */
/* 12/04/97 KCR 02 Added cfg_goto_keyword function */
/* 11/05/97 MDE 01 Added VXWORKS support */
/* 04/02/97 DTL 7.00 MMSEASE 7.0 release. See MODL70.DOC for */
/* history. */
/************************************************************************/
#include "glbtypes.h"
#include "sysincs.h"
#include "mem_chk.h"
#include "cfg_util.h"
#include "cfglog.h"
#include "str_util.h"
#include <ctype.h>
#include "slog.h"
/************************************************************************/
/* #define DEBUG */
/************************************************************************/
/* For debug version, use a static pointer to avoid duplication of */
/* __FILE__ strings. */
#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif
/************************************************************************/
/* Externally visable variables */
ST_CHAR *cfg_line_buf; /* File line read buffer */
ST_INT cfg_curr_line; /* Current line number */
ST_INT cfg_line_offset; /* Offset into cfg_line_buf */
ST_CHAR *cfg_special_char_str;
ST_CHAR *cfg_end_of_rval_str;
ST_BOOLEAN config_stop;
ST_RET config_err;
ST_BOOLEAN config_eof;
ST_UINT cfg_log_mask;
#ifdef DEBUG_SISCO
SD_CONST ST_CHAR *SD_CONST _cfg_err_logstr = "CFG_LOG_ERR";
SD_CONST ST_CHAR *SD_CONST _cfg_flow_logstr = "CFG_LOG_FLOW";
#endif
/************************************************************************/
/* Internal definitions */
#define MAX_STRING_LEN 256
#define LINE_BUF_SIZE 256
ST_INT cfg_max_string_len;
ST_INT cfg_line_buf_size;
ST_INT cfg_max_rval_len;
#define MAX_CONFIG_NEST 10
/* Internal variables */
static ST_CHAR *cfg_string_buf;
static struct cfg_kw_el *curr_table;
static ST_BOOLEAN cfg_need_new_line;
static FILE *config_fptr; /* Configuration file handle */
/* Keyword table stack control */
static ST_INT num_on_stack;
static struct cfg_kw_el **cfg_kw_stack;
/* Internal funtions */
static struct cfg_kw_el *cfg_lookup_keyword (struct cfg_kw_el *, ST_CHAR *);
static ST_RET cfg_get_next_keyword (FILE *);
static ST_CHAR *cfg_get_rval (ST_VOID);
static ST_RET cfg_end_of_rval (ST_CHAR c);
static ST_RET cfg_special_char (ST_CHAR c);
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* cfg_process_file */
/************************************************************************/
ST_RET cfg_process_file (ST_CHAR *fileName, struct cfg_kw_el *root_kw_tbl)
{
ST_RET ret;
if (cfg_special_char_str == NULL)
cfg_special_char_str = ":\\/-_ .{}[]<>@,()$";
if (cfg_end_of_rval_str == NULL)
cfg_end_of_rval_str = "|";
if (cfg_max_string_len == 0)
cfg_max_string_len = MAX_STRING_LEN;
if (cfg_line_buf_size == 0)
cfg_line_buf_size = LINE_BUF_SIZE;
if (cfg_max_rval_len == 0)
cfg_max_rval_len = MAX_RVAL_LEN;
/* Open the configuration file */
if ((config_fptr = fopen (fileName,"r"))==NULL)
{
CFG_LOG_ERR1 ("Config File (%s) Open Error",fileName);
return (SD_FAILURE);
}
CFG_LOG_FLOW1 ("Config File (%s) Opened OK",fileName);
/* If a previous call to the function ended in error there may be some */
/* old keyword table pushed on the stack. The keywords table stack is */
/* initialized to zero to process the current configuration file */
num_on_stack = 0;
/* Allocate required buffers */
cfg_line_buf = (ST_CHAR *) chk_calloc (cfg_line_buf_size,
sizeof(ST_CHAR));
cfg_string_buf = (ST_CHAR *) chk_calloc (cfg_max_string_len+1,
sizeof(ST_CHAR));
cfg_kw_stack = (struct cfg_kw_el **) chk_calloc (MAX_CONFIG_NEST,
sizeof (struct cfg_kw_el *));
/* Start with the ROOT keyword table */
cfg_tbl_push (root_kw_tbl);
/* Process the configuration file */
cfg_need_new_line = SD_TRUE;
cfg_line_offset = 0;
cfg_curr_line = 0;
config_err = SD_FALSE;
config_stop = SD_FALSE;
config_eof = SD_FAILURE;
/* Process keywords while not done and no error is detected */
while ( ( config_stop == SD_FALSE ) && ( config_err == SD_FALSE ) )
{
if ( cfg_get_next_keyword( config_fptr ) )
break;
}
/* All done, see if it went OK */
if ( ( config_stop == SD_TRUE ) && ( config_err == SD_FALSE ) )
{
CFG_LOG_CFLOW0 ("Config File Read OK");
ret = SD_SUCCESS;
}
else
{
CFG_LOG_ERR3 ("Config Error, Line %d, \"%s\", Column %d",
cfg_curr_line, cfg_line_buf, cfg_line_offset);
ret = SD_FAILURE;
}
/* Free allocated buffers */
chk_free (cfg_line_buf);
chk_free (cfg_string_buf);
chk_free (cfg_kw_stack);
/* Close the file so the calling program can reopen it if necessary. */
fclose( config_fptr );
return (ret);
}
/************************************************************************/
/************************************************************************/
/* cfg_get_next_keyword */
/************************************************************************/
/* This function is used to get the next keyword */
static ST_RET cfg_get_next_keyword (FILE *fptr)
{
struct cfg_kw_el *ptr;
ST_INT i;
ST_CHAR c;
/* Look for 'yyy =' string */
while (SD_TRUE) /* While looking for the next word */
{
if (cfg_need_new_line)
{
if ( fgets( cfg_line_buf, cfg_line_buf_size - 1, fptr ) == NULL )
{
CFG_LOG_CFLOW0 ("No More Keywords : End Of File");
/* The following piece of logic exists to allow the state functions to */
/* declare when it is ok for the file to be out of keywords. If a user */
/* state function set 'config_eof == SD_SUCCESS' then config_stop is set */
/* to true when ENDFILE is encountered. */
if ( config_eof == SD_SUCCESS )
{
config_stop = SD_TRUE;
}
return( SD_FAILURE );
}
/* Wack the \n */
for (i = 0; i < cfg_line_buf_size; ++i)
{
if (cfg_line_buf[i] == '\n')
{
cfg_line_buf[i] = 0;
break;
}
}
cfg_line_offset = 0; /* Offset is 0 for new line */
++cfg_curr_line;
if (cfg_line_buf[0] == '#')
continue; /* Discard comment lines */
cfg_need_new_line = SD_FALSE; /* Got a new line */
}
/* We now have a line to work on, with cfg_line_offset the 1st char */
/* Extract the keyword from the string (alpha numeric characters) */
/* '=' means end of rval */
/* 0 is end of line */
i = 0;
c = cfg_line_buf[cfg_line_offset++];
while (c && c != '#' && /* End of line or comment start */
c != '=' && /* end of keyword */
c != '|' &&
i < cfg_max_string_len)
{
if (c != ' ' && c != '\t') /* Ignore spaces and tabs */
{
cfg_string_buf[i] = c;
++i;
}
c = cfg_line_buf[cfg_line_offset++];
}
if (i >= cfg_max_string_len)
{
CFG_LOG_ERR1 ("Error : Line %d too long", cfg_curr_line);
return (SD_FAILURE);
}
if (c == '#' || !c) /* See if we need a new line next time */
cfg_need_new_line = SD_TRUE;
/* i is the index to the char position that terminated the scan */
cfg_string_buf[i]=0x0; /* NULL terminate the keyword */
/* if we have a keyword, then search look it up in the currently active */
/* keyword table and execute the selected function */
if (strlen (cfg_string_buf))
{ /* Find the keyword */
if ((ptr = cfg_lookup_keyword (curr_table, cfg_string_buf)) != NULL)
{
CFG_LOG_CFLOW1 ("Keyword : %s",cfg_string_buf);
(*ptr->extract)();
break;
}
else /* invalid keyword */
{
CFG_LOG_ERR1 ("Unknown Keyword : %s",cfg_string_buf);
return (SD_FAILURE);
}
}
} /* While SD_TRUE */
return(SD_SUCCESS);
}
/************************************************************************/
/* cfg_get_rval() */
/************************************************************************/
static ST_CHAR *cfg_get_rval(ST_VOID)
{
ST_INT i;
ST_CHAR c;
cfg_string_buf[0]=0x0;
/* Now get the rval (value). */
/* search for 0 to note end of line */
i = 0;
c = cfg_line_buf[cfg_line_offset++];
/* First strip leading white space (' ', '\t') */
while (c == ' ' || c == '\t')
c = cfg_line_buf[cfg_line_offset++];
while (c &&
c != '#' &&
!cfg_end_of_rval (c) &&
i < cfg_max_rval_len-1)
{
if (isalnum (c) || cfg_special_char (c))
{
cfg_string_buf[i] = c;
++i;
}
c = cfg_line_buf[cfg_line_offset++];
}
if (c == '#' || !c) /* See if we need a new line next time */
cfg_need_new_line = SD_TRUE;
/* Strip trailing spaces and tabs */
while (i && (cfg_string_buf[i-1] == ' ' ||
cfg_string_buf[i-1] == '\t'))
i--;
/* Null terminate the string */
cfg_string_buf[i] = 0x0;
if (!strlen (cfg_string_buf))
{
CFG_LOG_ERR2 ("Bad rval, line #%d \"%s\"",cfg_curr_line,cfg_line_buf);
return (NULL);
}
CFG_LOG_CFLOW1 ("Rval : '%s'",cfg_string_buf);
return (cfg_string_buf);
}
/************************************************************************/
/* cfg_lookup_keyword */
/************************************************************************/
static struct cfg_kw_el *cfg_lookup_keyword(struct cfg_kw_el *tbl_ptr,
ST_CHAR *name)
{
ST_INT i;
struct cfg_kw_el *ret = NULL;
for (i = 0; i < MAX_NUM_KEYWORDS; ++i)
{
if (tbl_ptr[i].extract == NULL) /* End of table */
break;
else if (!strcmpi (name, tbl_ptr[i].name))
{ /* we have a match */
if (tbl_ptr[i].valid !=NULL) /* Want to validate? */
{
if ((*tbl_ptr[i].valid)())
ret = &tbl_ptr[i];
}
else
ret = &tbl_ptr[i];
break;
}
}
return(ret);
}
/************************************************************************/
/* cfg_end_of_rval */
/************************************************************************/
/* CONFIG calls back to this function while looking the rval over */
/* If this function returns SD_TRUE, CONFIG will assume that the */
/* character is a keyword/rval pair seperator */
/* Used to allow multiple pairs per line */
static ST_RET cfg_end_of_rval (ST_CHAR c)
{
ST_INT i;
ST_INT str_len;
str_len = strlen (cfg_end_of_rval_str);
for (i = 0; i < str_len; ++i)
{
if (c == cfg_end_of_rval_str[i])
return (SD_TRUE);
}
return (SD_FALSE);
}
/************************************************************************/
/* cfg_special_char */
/************************************************************************/
static ST_RET cfg_special_char (ST_CHAR c)
{
ST_INT i;
ST_INT str_len;
str_len = strlen (cfg_special_char_str);
for (i = 0; i < str_len; ++i)
{
if (c == cfg_special_char_str[i])
return (SD_TRUE);
}
return (SD_FALSE);
}
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* cfg_tbl_push (new_table) */
/************************************************************************/
ST_RET cfg_tbl_push (struct cfg_kw_el *new_table)
{
if (num_on_stack >= MAX_CONFIG_NEST)
{
CFG_LOG_ERR0 ("Too many pushes - configuration nesting exceeded");
config_stop = SD_TRUE;
config_err = CFG_UTIL_ERR;
return (SD_FAILURE);
}
cfg_kw_stack[num_on_stack] = new_table;
++num_on_stack;
curr_table = new_table;
return (SD_SUCCESS);
}
/************************************************************************/
/* cfg_tbl_pop (num_to_pop) */
/************************************************************************/
ST_RET cfg_tbl_pop (ST_INT num_to_pop)
{
if ((num_on_stack-num_to_pop-1)<0)
{
CFG_LOG_ERR0 ("Too many pops off configuration stack");
config_stop = SD_TRUE;
config_err = CFG_UTIL_ERR;
return (SD_FAILURE);
}
num_on_stack -= num_to_pop;
curr_table = cfg_kw_stack[num_on_stack-1];
return (SD_SUCCESS);
}
/************************************************************************/
/* cfg_get_short */
/************************************************************************/
ST_RET cfg_get_short (ST_INT16 *out_ptr)
{
ST_INT d;
ST_INT16 ret;
ret = cfg_get_value ("%d", &d);
if (!ret)
*out_ptr = (ST_INT16) d;
return (ret);
}
/************************************************************************/
/* cfg_get_ushort */
/************************************************************************/
ST_RET cfg_get_ushort (ST_UINT16 *out_ptr)
{
ST_UINT d;
ST_RET ret;
ret = cfg_get_value ("%u", &d);
if (!ret)
*out_ptr = (ST_UINT16) d;
return (ret);
}
/************************************************************************/
/* cfg_get_int */
/************************************************************************/
ST_RET cfg_get_int (ST_INT *out_ptr)
{
ST_INT d;
ST_RET ret;
ret = cfg_get_value ("%d", &d);
if (!ret)
*out_ptr = d;
return (ret);
}
/************************************************************************/
/* cfg_get_uint */
/************************************************************************/
ST_RET cfg_get_uint (ST_UINT *out_ptr)
{
ST_UINT d;
ST_RET ret;
ret = cfg_get_value ("%u", &d);
if (!ret)
*out_ptr = d;
return (ret);
}
/************************************************************************/
/* cfg_get_long */
/************************************************************************/
ST_RET cfg_get_long (ST_LONG *out_ptr)
{
return (cfg_get_value ("%ld", out_ptr));
}
/************************************************************************/
/* cfg_get_ulong */
/************************************************************************/
ST_RET cfg_get_ulong (ST_ULONG *out_ptr)
{
return (cfg_get_value ("%lu", out_ptr));
}
/************************************************************************/
/* cfg_get_double */
/************************************************************************/
ST_RET cfg_get_double (ST_DOUBLE *out_ptr)
{
return (cfg_get_value ("%lf", out_ptr));
}
/************************************************************************/
/* cfg_get_hex_ushort */
/************************************************************************/
ST_RET cfg_get_hex_ushort (ST_UINT16 *out_ptr)
{
ST_UINT d;
ST_RET ret;
ret = cfg_get_value ("%x", &d);
if (!ret)
*out_ptr = (ST_UINT16) d;
return (ret);
/* return (cfg_get_value ("%x", out_ptr)); */
}
/************************************************************************/
/* cfg_get_hex_uint */
/************************************************************************/
ST_RET cfg_get_hex_uint (ST_UINT *out_ptr)
{
ST_UINT d;
ST_RET ret;
ret = cfg_get_value ("%x", &d);
if (!ret)
*out_ptr = d;
return (ret);
/* return (cfg_get_value ("%x", out_ptr)); */
}
/************************************************************************/
/* cfg_get_hex_ulong */
/************************************************************************/
ST_RET cfg_get_hex_ulong (ST_ULONG *out_ptr)
{
return (cfg_get_value ("%lx", out_ptr));
}
/************************************************************************/
/* cfg_get_value */
/************************************************************************/
ST_RET cfg_get_value (ST_CHAR *format_string, ST_VOID *out_ptr)
{
ST_CHAR *rval;
rval = cfg_get_rval (); /* get the rvalue string */
if (!rval)
{
config_err = CFG_GET_RVAL_ERR;
CFG_LOG_ERR0 ("Get Rval Error");
}
else
{ /* Convert to desired data format*/
if (!sscanf (rval,format_string,out_ptr))
{
config_err = CFG_CONVERT_ERR;
CFG_LOG_ERR0 ("Data Conversion Error");
}
}
if (config_err) /* if error detected ... */
{
config_stop = SD_TRUE;
return (SD_FAILURE);
}
return (SD_SUCCESS);
}
/************************************************************************/
/************************************************************************/
/* *cfg_get_alloc_string */
/************************************************************************/
ST_CHAR *cfg_get_alloc_string (ST_VOID)
{
ST_CHAR *ret_ptr;
ST_CHAR *rval;
rval = cfg_get_rval (); /* get the rvalue string */
if (!rval)
{
config_stop = SD_TRUE;
config_err = CFG_GET_RVAL_ERR;
CFG_LOG_ERR0 ("Get Rval Error");
return (NULL);
}
/* allocate storage for string */
ret_ptr = (ST_CHAR *) chk_calloc (1,strlen (rval) +1);
strcpy (ret_ptr,rval);
return (ret_ptr);
}
/************************************************************************/
/* *cfg_get_string_ptr */
/************************************************************************/
ST_CHAR *cfg_get_string_ptr (ST_VOID)
{
ST_CHAR *rval;
rval = cfg_get_rval (); /* get the rvalue string */
if (!rval)
{
config_stop = SD_TRUE;
config_err = CFG_GET_RVAL_ERR;
CFG_LOG_ERR0 ("Get Rval Error");
return (NULL);
}
return (rval);
}
/************************************************************************/
/* cfg_get_octet_string */
/************************************************************************/
ST_RET cfg_get_octet_string (ST_UCHAR *ostr, /* ptr to user's ostr */
ST_UINT *len_out_ptr, /* addr of len var to be set */
ST_UINT len_max) /* maximum len to allow. */
{
ST_UINT j;
ST_INT digit;
ST_BOOLEAN nibble; /* SD_TRUE if nibble read, SD_FALSE if whole byte read*/
ST_CHAR *rval;
rval = cfg_get_rval (); /* get the rvalue string */
if (!rval)
{
config_stop = SD_TRUE;
config_err = CFG_GET_RVAL_ERR;
CFG_LOG_ERR0 ("Get Rval Error");
return (SD_FAILURE);
}
j = 0;
nibble = SD_FALSE;
while (isxdigit (*rval)) /* get hex number */
{
if (j >= len_max)
return (SD_FAILURE); /* Selector longer than allowed */
digit = *rval++; /* separate nibbles */
digit = isdigit (digit) ? digit - '0' : 10 + (toupper (digit) - 'A');
if (nibble)
{
nibble = SD_FALSE;
ostr[j] = (ostr[j] | (ST_UCHAR) digit); /* set low */
j++;
while (isspace (*rval) && *rval != '\n')
++rval;
}
else
{
nibble = SD_TRUE;
ostr[j] = (ST_UCHAR) digit << 4; /* set high byte */
}
}
if (nibble)
{ /* Only got half of byte. */
config_stop = SD_TRUE;
config_err = CFG_CONVERT_ERR;
CFG_LOG_ERR0 ("Incomplete byte in Octet string");
return (SD_FAILURE);
}
/* set selector length */
*len_out_ptr = j;
return (SD_SUCCESS);
}
/************************************************************************/
/* cfg_set_config_err */
/************************************************************************/
ST_VOID cfg_set_config_err(ST_VOID)
{
config_err = SD_TRUE;
}
/************************************************************************/
/* cfg_set_endfile_ok */
/************************************************************************/
ST_VOID cfg_set_endfile_ok(ST_VOID)
{
config_eof = SD_SUCCESS;
}
/************************************************************************/
/************************************************************************/
/* cfg_goto_keyword */
/************************************************************************/
/* This function is used to skip over a section to the specified keyword*/
ST_RET cfg_goto_keyword (ST_CHAR *keyword)
{
ST_INT i, cfgStringLen, keywordLen;
ST_CHAR c;
/* Look for 'yyy =' string */
keywordLen = strlen (keyword);
while (SD_TRUE) /* While looking for the specified word */
{
if (cfg_need_new_line)
{
if ( fgets( cfg_line_buf, cfg_line_buf_size - 1, config_fptr ) == NULL )
{
CFG_LOG_CFLOW0 ("No More Keywords : End Of File");
/* The following piece of logic exists to allow the state functions to */
/* declare when it is ok for the file to be out of keywords. If a user */
/* state function set 'config_eof == SD_SUCCESS' then config_stop is set */
/* to true when ENDFILE is encountered. */
if ( config_eof == SD_SUCCESS )
{
config_stop = SD_TRUE;
}
return( SD_FAILURE );
}
/* Wack the \n */
for (i = 0; i < cfg_line_buf_size; ++i)
{
if (cfg_line_buf[i] == '\n')
{
cfg_line_buf[i] = 0;
break;
}
}
cfg_line_offset = 0; /* Offset is 0 for new line */
++cfg_curr_line;
if (cfg_line_buf[0] == '#')
continue; /* Discard comment lines */
cfg_need_new_line = SD_FALSE; /* Got a new line */
}
/* We now have a line to work on, with cfg_line_offset the 1st char */
/* Extract the keyword from the string (alpha numeric characters) */
/* '=' means end of rval */
/* 0 is end of line */
i = 0;
c = cfg_line_buf[cfg_line_offset++];
while (c && c != '#' && /* End of line or comment start */
c != '=' && /* end of keyword */
c != '|' &&
i < cfg_max_string_len)
{
if (c != ' ' && c != '\t') /* Ignore spaces and tabs */
{
cfg_string_buf[i] = c;
++i;
}
c = cfg_line_buf[cfg_line_offset++];
}
if (i >= cfg_max_string_len)
{
CFG_LOG_ERR1 ("Error : Line %d too long", cfg_curr_line);
return (SD_FAILURE);
}
if (c == '#' || !c) /* See if we need a new line next time */
cfg_need_new_line = SD_TRUE;
/* i is the index to the char position that terminated the scan */
cfg_string_buf[i]=0x0; /* NULL terminate the keyword */
/* if we have a keyword, then search look it up in the currently active */
/* keyword table and execute the selected function */
if ((cfgStringLen = strlen (cfg_string_buf)) > 0)
{ /* Find the keyword */
if ((cfgStringLen == keywordLen) && !strcmpi (keyword, cfg_string_buf))
break;
else /* keyword not found */
cfg_need_new_line = SD_TRUE;
}
} /* While SD_TRUE */
return(SD_SUCCESS);
}