/**
* @file:    $RCSfile: logcfgx.c,v $
* @brief:   $IEC 61850 Protocol  
*
* @version: $Revision: 1.1 $
* @date:    $Date: 2018/11/24 06:54:50 $
* @author:  $Author: lizhongming $
* @state:   $State: Exp $
*
* @latest:  $Id: logcfgx.c,v 1.1 2018/11/24 06:54:50 lizhongming Exp $
*
*/
/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/*   (c) Copyright Systems Integration Specialists Company, Inc.,       */
/*          2000 - 2005, All Rights Reserved                            */
/*                                                                      */
/* MODULE NAME : logcfgx.c                                              */
/* PRODUCT(S)  :                                                        */
/*                                                                      */
/* MODULE DESCRIPTION :    This module processes each value parsed in   */
/*                         the logcfg.xml file .  The logcfg.xml file   */
/*                         assigns Log File Attributes and              */
/*                         Miscellaneous Control Flags as well as       */
/*                         Memory Use Logging and various Log Masks     */
/*                         to enable specific logging required.         */
/*                                                                      */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE :                            */
/*                                                                      */
/* MODIFICATION LOG :                                                   */
/*  Date     Who   Rev          Comments                                */
/* --------  ---  ------  --------------------------------------------  */
/* 08/10/05  MDE    13    Added logCfgRemoveAllMaskGroups		*/
/* 06/21/05  EJV    12    Deleted obsolete logcfgx function.		*/
/* 05/23/05  EJV    11    Moved xxxLogMaskMapCtrl to respective C files.*/
/*			  Del m_track_prev_free (not used anymore).	*/
/*			  Force user to use logcfgx_ex insted of logcfgx*/
/* 04/25/05  MDE    10    Added MMS_LOG_CLIENT & MMS_LOG_SERVER		*/
/* 03/31/05  MDE    09    Put suicacse.h back, for MAP30_ACSE		*/
/* 03/28/05  JRB    08    Del suicacse header.              		*/
/* 02/10/05  MDE    07    Changed MILOG_ to MI_LOG_			*/
/* 02/10/05  MDE    06    Added new DATATYPE's				*/
/* 01/27/05  MDE    05    DEBUG_SISCO #ifdefs, LINUX warning cleanup	*/
/* 01/20/05  MDE    04    Lot's more work ...				*/
/* 12/10/04  ASK    03    Added Slog IPC params, added 			*/
/*		          case _LOGCFG_DATATYPE_UINT32_MASK		*/
/*			  Modify params to use 'R'everse data type	*/
/*                        Update copyright year                         */
/* 11/16/04  MDE    02    Fixed to compile with MAP30_ACSE		*/
/* 10/12/04  MDE    01    Complete rewrite to work with SX changes,     */
/*                        make extendable				*/
/************************************************************************/

#include "glbtypes.h"
#include "sysincs.h"
#include "mem_chk.h"
#include "gen_list.h"
#include "str_util.h"
#include "slog.h"

#include "sx_defs.h"
#include "sx_log.h"

/************************************************************************/

/* For debug version, use a static pointer to avoid duplication of      */
/* __FILE__ strings.                                                    */

#if defined(DEBUG_SISCO)
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif

/************************************************************************/

LOGCFG_VALUE_GROUP *logCfgLogMaskGroupList;
static LOGCFGX_TAG_VAL *_tagValList;

/************************************************************************/
#if defined(DEBUG_SISCO)
static LOG_CTRL tmp_sLogCtrl;

ST_UINT logcfg_debug_sel;

/* Log type strings */
SD_CONST ST_CHAR *SD_CONST _logcfg_log_err_logstr 	= "LOGCFG_ERR";
SD_CONST ST_CHAR *SD_CONST _logcfg_log_nerr_logstr	= "LOGCFG_NERR";
SD_CONST ST_CHAR *SD_CONST _logcfg_log_flow_logstr	= "LOGCFG_FLOW";

LOGCFGX_VALUE_MAP logcfgMaskMaps[] =
  {
    {"LOGCFG_ERR",	LOGCFG_ERR,	&logcfg_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Error"},
    {"LOGCFG_NERR",	LOGCFG_NERR,	&logcfg_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Notice"},
    {"LOGCFG_FLOW",	LOGCFG_FLOW,	&logcfg_debug_sel, _LOGCFG_DATATYPE_UINT_MASK, "Flow"}
  };

LOGCFG_VALUE_GROUP logcfgMaskMapCtrl =
  {
  {NULL,NULL},
  "LOGCFG",
  sizeof(logcfgMaskMaps)/sizeof(LOGCFGX_VALUE_MAP),
  logcfgMaskMaps
  };

/************************************************************************/
/************************************************************************/

LOGCFGX_VALUE_MAP logCfgLogMaskMaps[] =
  {
/* SLOG Control */
    {"LogFileEnable", 		LOG_FILE_EN, 		&tmp_sLogCtrl.logCtrl, 		_LOGCFG_DATATYPE_UINT32_MASK},
    {"DestroyOldFile", 		FIL_CTRL_NO_APPEND, 	&tmp_sLogCtrl.fc.ctrl, 		_LOGCFG_DATATYPE_UINT_MASK},
    {"Setbuf", 			FIL_CTRL_SETBUF_EN, 	&tmp_sLogCtrl.fc.ctrl, 		_LOGCFG_DATATYPE_UINT_MASK},
    {"MsgHeader", 		FIL_CTRL_MSG_HDR_EN, 	&tmp_sLogCtrl.fc.ctrl, 		_LOGCFG_DATATYPE_UINT_MASK},
    {"Wipe", 			FIL_CTRL_WIPE_EN, 	&tmp_sLogCtrl.fc.ctrl, 		_LOGCFG_DATATYPE_UINT_MASK},
    {"Wrap", 			FIL_CTRL_WRAP_EN, 	&tmp_sLogCtrl.fc.ctrl, 		_LOGCFG_DATATYPE_UINT_MASK},
    {"HardFlush", 		FIL_CTRL_HARD_FLUSH, 	&tmp_sLogCtrl.fc.ctrl, 		_LOGCFG_DATATYPE_UINT_MASK},
    {"LogMemoryEnable", 	LOG_MEM_EN, 		&tmp_sLogCtrl.logCtrl, 		_LOGCFG_DATATYPE_UINT32_MASK},
    {"MemoryFileDump", 		MEM_CTRL_AUTODUMP_EN, 	&tmp_sLogCtrl.mc.ctrl, 		_LOGCFG_DATATYPE_UINT_MASK},
    {"LogIpcListenEnable", 	LOG_IPC_LISTEN_EN, 	&tmp_sLogCtrl.logCtrl, 		_LOGCFG_DATATYPE_UINT32_MASK},
    {"LogIpcCallEnable", 	LOG_IPC_CALL_EN, 	&tmp_sLogCtrl.logCtrl, 		_LOGCFG_DATATYPE_UINT32_MASK},
    {"LogIpcSmartMode", 	LOG_IPC_SMART, 	        &tmp_sLogCtrl.logCtrl, 		_LOGCFG_DATATYPE_UINT32_MASK},
    {"HeaderCr", 		LOG_NO_HEADER_CR, 	&tmp_sLogCtrl.logCtrl, 		_LOGCFG_DATATYPE_RUINT32_MASK},
    {"HeaderFilename", 		LOG_FILENAME_SUPPRESS, 	&tmp_sLogCtrl.logCtrl, 		_LOGCFG_DATATYPE_RUINT32_MASK},
    {"HeaderLogType", 		LOG_LOGTYPE_SUPPRESS, 	&tmp_sLogCtrl.logCtrl, 		_LOGCFG_DATATYPE_RUINT32_MASK},
    {"LogFileSize",    		0, 			&tmp_sLogCtrl.fc.maxSize, 	_LOGCFG_DATATYPE_ULONG},
    {"LogFileName",    		0, 			&tmp_sLogCtrl.fc.fileName, 	_LOGCFG_DATATYPE_FILENAME},
    {"LogMemoryItems", 		0, 			&tmp_sLogCtrl.mc.maxItems, 	_LOGCFG_DATATYPE_ULONG},
    {"MemoryFileName", 		0, 			&tmp_sLogCtrl.mc.dumpFileName,	_LOGCFG_DATATYPE_FILENAME},
    {"LogIpcAppId", 	        0, 			&tmp_sLogCtrl.ipc.appId, 	_LOGCFG_DATATYPE_STRING},
    {"LogIpcListenPort",        0, 			&tmp_sLogCtrl.ipc.port, 	_LOGCFG_DATATYPE_UINT16},
    {"LogIpcNumListenPorts",    0, 			&tmp_sLogCtrl.ipc.portCnt, 	_LOGCFG_DATATYPE_UINT16},
    {"LogIpcMaxListenConn",     0, 			&tmp_sLogCtrl.ipc.maxConns, 	_LOGCFG_DATATYPE_UINT},
    {"LogIpcCallingPort",       0, 			&tmp_sLogCtrl.ipc.callingPort, 	_LOGCFG_DATATYPE_UINT16},
    {"LogIpcCallingIp",         0, 			&tmp_sLogCtrl.ipc.callingIp, 	_LOGCFG_DATATYPE_STRING},
    {"LogIpcMaxQueCount",       0, 			&tmp_sLogCtrl.ipc.maxQueCnt, 	_LOGCFG_DATATYPE_UINT},
  };

LOGCFG_VALUE_GROUP logCfgLogCtrlMapCtrl =
  {
  {NULL,NULL},
  "",
  sizeof(logCfgLogMaskMaps)/sizeof(LOGCFGX_VALUE_MAP),
  logCfgLogMaskMaps
  };
#endif /* defined(DEBUG_SISCO) */


/************************************************************************/
/************************************************************************/

static ST_RET  _logcfg_data_start (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag);
static ST_RET  _logcfg_data_end (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag);


/************************************************************************/
/*			logCfgAddMaskGroup 				*/
/************************************************************************/

ST_VOID logCfgAddMaskGroup (LOGCFG_VALUE_GROUP *logMaskGroup)
  {
  if (list_find_node (logCfgLogMaskGroupList, logMaskGroup) != SD_SUCCESS)
    list_add_last (&logCfgLogMaskGroupList, logMaskGroup);
  }

/************************************************************************/
/*			logCfgRemoveMaskGroup 				*/
/************************************************************************/

ST_VOID logCfgRemoveMaskGroup (LOGCFG_VALUE_GROUP *logMaskGroup)
  {
  if (list_find_node (logCfgLogMaskGroupList, logMaskGroup) == SD_SUCCESS)
    list_unlink (&logCfgLogMaskGroupList, logMaskGroup);
  }

/************************************************************************/
/*			logCfgRemoveAllMaskGroups			*/
/************************************************************************/

ST_VOID logCfgRemoveAllMaskGroups ()
  {
  logCfgLogMaskGroupList = NULL;
  }

/************************************************************************/
/*			logCfgFindTagVal				*/
/************************************************************************/

LOGCFGX_TAG_VAL *logCfgFindTagVal (ST_CHAR *tag)
  {
LOGCFGX_TAG_VAL *tagVal;

  tagVal = _tagValList;
  while (tagVal != NULL)
    {
    if (!strcmp (tag, tagVal->tag))
      return (tagVal);

    tagVal =(LOGCFGX_TAG_VAL*) list_get_next (_tagValList, tagVal);
    }
  return (NULL);
  }

/************************************************************************/
/*			logCfgClearTagVals				*/
/************************************************************************/

ST_VOID logCfgClearTagVals ()
  {
LOGCFGX_TAG_VAL *tagVal;

  while (_tagValList)
    {
    tagVal = (LOGCFGX_TAG_VAL *) list_unlink (&_tagValList, _tagValList);
    if (tagVal->dataType == _LOGCFG_DATATYPE_STRING || 
        tagVal->dataType == _LOGCFG_DATATYPE_FILENAME)
      {
      chk_free (tagVal->u.str);
      }
    chk_free (tagVal);
    }
  }

/************************************************************************/
/************************************************************************/
/*                                logcfgx_ex                            */
/* User must call logCfgAddMaskGroup for each group of log masks to be	*/
/* configured BEFORE calling this function to parse the file.		*/
/************************************************************************/

typedef struct
  {
  LOG_CTRL *destLogCtrl;
  ST_INT     state;
  ST_CHAR   *logFileName; 
  ST_CHAR   *fileNamePrefix;
  ST_BOOLEAN masksOnly;
  ST_BOOLEAN saveTagVals;
  } LOGCFGX_CTRL;


ST_RET logcfgx_ex (LOG_CTRL *destLogCtrl, ST_CHAR *logFileName, ST_CHAR *fileNamePrefix, 
		   ST_BOOLEAN masksOnly, ST_BOOLEAN saveTagVals)
  {
LOGCFGX_CTRL logCfgxCtrl;
ST_UINT sx_debug_sel_save;
ST_RET rc;
#if defined(DEBUG_SISCO)
ST_CHAR *savedFileName;
#endif

  logCfgxCtrl.destLogCtrl     = destLogCtrl;
  logCfgxCtrl.logFileName     =	logFileName; 
  logCfgxCtrl.fileNamePrefix  =	fileNamePrefix; 
  logCfgxCtrl.masksOnly       =	masksOnly;
  logCfgxCtrl.saveTagVals     =	saveTagVals;

#if defined(DEBUG_SISCO)
  logcfg_debug_sel |= LOGCFG_ERR;
  logcfg_debug_sel |= LOGCFG_NERR;
  sx_debug_sel     |= SX_LOG_ERR;
  sx_debug_sel     |= SX_LOG_NERR;

  if (masksOnly)
    logCfgRemoveMaskGroup (&logCfgLogCtrlMapCtrl);
  else
    logCfgAddMaskGroup (&logCfgLogCtrlMapCtrl);

/* Always allow LOGCFG & SX logging ... */
  logCfgAddMaskGroup (&logcfgMaskMapCtrl);
  logCfgAddMaskGroup (&sxLogMaskMapCtrl);

  savedFileName = sLogCtrl->fc.fileName;

  /* Copy original "sLogCtrl" to temporary struct which may be modified */
  /* by the configuration.                                              */
  /* This prevents logging control changes while there may be logging.  */

  memcpy (&tmp_sLogCtrl, sLogCtrl, sizeof (LOG_CTRL));
#endif

  rc = sx_parseEx_mt (logFileName, 0, NULL, &logCfgxCtrl, _logcfg_data_start, _logcfg_data_end);
  if (rc != SD_SUCCESS)
    {
    /* Config failed: Do not modify "sLogCtrl".                         */
    /* Turn on cfg logging and parse file again.                        */
    sx_debug_sel_save = sx_debug_sel;

    sx_debug_sel |= SX_LOG_DEC | SX_LOG_ENC | SX_LOG_FLOW | SX_LOG_DEBUG;
    LOGCFG_ERR0 ("ERROR Parsing Logging Configuration File: Trying again w/debug on ... ");
    rc = sx_parseEx_mt (logFileName, 0,NULL,&logCfgxCtrl, _logcfg_data_start, _logcfg_data_end);
    sx_debug_sel = sx_debug_sel_save;
    }
  else    /* rc == SD_SUCCESS */
    {
    LOGCFG_FLOW0 ("Logging configuration complete");
    }
  return (rc);
  }

/************************************************************************/
/************************************************************************/
/*			_logcfg_data_start				*/
/************************************************************************/

#define LOGCFGX_STATE_NONE      0
#define LOGCFGX_STATE_UNKNOWN	1
#define LOGCFGX_STATE_LOGCTRL	2
#define LOGCFGX_STATE_LOGMASKS	3

static ST_RET _logcfg_data_start (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag)
  {
LOGCFGX_CTRL *logCfgxCtrl;

  logCfgxCtrl =(LOGCFGX_CTRL*) sxDecCtrl->usr;
  if (!strcmp (tag, "LogControl"))
    logCfgxCtrl->state = LOGCFGX_STATE_LOGCTRL;
  else if (!strcmp (tag, "LogMasks"))
    logCfgxCtrl->state = LOGCFGX_STATE_LOGMASKS;

  return (SD_SUCCESS);
  }

/************************************************************************/
/*			_logcfg_data_end				*/
/************************************************************************/


static ST_RET _logcfg_data_end (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag)
  {
LOGCFGX_CTRL *logCfgxCtrl;
LOGCFG_VALUE_GROUP *slogMaskGroup;
LOG_CTRL *destLogCtrl;
LOGCFGX_TAG_VAL *tagVal;
SX_DEC_ELEMENT_INFO *sxDecElInfo; 
ST_VOID (*logCfgCallbackFun) (SX_DEC_CTRL *sxDecCtrl, ST_CHAR *tag, 
			      LOGCFGX_VALUE_MAP *valMap);
ST_CHAR *cp;
ST_CHAR *str;
ST_BOOLEAN *bp;
ST_BOOLEAN b;
ST_INT i;
ST_INT strLen;
ST_RET rc;
ST_UINT *up;
ST_UINT32 *u32p;
ST_UINT16 *u16p;
ST_ULONG *ulp;
ST_CHAR **cpp;
ST_DOUBLE *dp;
#if defined(DEBUG_SISCO)
ST_CHAR *oldFileName;
ST_BOOLEAN logFileChanged;
#endif
ST_BOOLEAN found;
ST_CHAR *p;

  logCfgxCtrl =(LOGCFGX_CTRL*) sxDecCtrl->usr;

  if (!strcmp (tag, "LogMasks"))
    {
    logCfgxCtrl->state = LOGCFGX_STATE_NONE;
    return (SD_SUCCESS);
    }

  destLogCtrl = logCfgxCtrl->destLogCtrl;
  sxDecElInfo = &sxDecCtrl->sxDecElInfo; 

  if (!strcmp (tag, "LogControl"))
    {
#if defined(DEBUG_SISCO)
    logFileChanged = SD_FALSE;
    if (logCfgxCtrl->masksOnly == SD_FALSE)
      {
      /* If the log file name has changed and the log file is open, 	*/
      /* close the log file and clear state.				*/
      
      if (destLogCtrl->fc.state & FIL_STATE_OPEN)
        {                 
        oldFileName = destLogCtrl->fc.fileName;
#ifdef _WIN32   /* Filenames NOT case sensitive on Windows  */
        if (_stricmp (tmp_sLogCtrl.fc.fileName, oldFileName) != 0)
#else
        if (strcmp (tmp_sLogCtrl.fc.fileName, oldFileName) != 0)
#endif
          {   /* NEW log file name different from OLD.    */
          fclose (destLogCtrl->fc.fp);           /* close it */
          destLogCtrl->fc.state &= ~(FIL_STATE_OPEN);    /* clear state  */
          logFileChanged = SD_TRUE;
          }
        }
      if (tmp_sLogCtrl.fc.ctrl & FIL_CTRL_MSG_HDR_EN)
        tmp_sLogCtrl.mc.ctrl |= MEM_CTRL_MSG_HDR_EN;
      else
        tmp_sLogCtrl.mc.ctrl &= ~MEM_CTRL_MSG_HDR_EN;
  
      destLogCtrl->logCtrl         = tmp_sLogCtrl.logCtrl;
      destLogCtrl->fc.ctrl         = tmp_sLogCtrl.fc.ctrl;
      destLogCtrl->fc.fileName     = tmp_sLogCtrl.fc.fileName;
      destLogCtrl->fc.maxSize      = tmp_sLogCtrl.fc.maxSize;
      destLogCtrl->mc.ctrl         = tmp_sLogCtrl.mc.ctrl;
      destLogCtrl->mc.dumpFileName = tmp_sLogCtrl.mc.dumpFileName;
      destLogCtrl->mc.maxItems     = tmp_sLogCtrl.mc.maxItems;
      destLogCtrl->ipc.appId 	   = tmp_sLogCtrl.ipc.appId; 	
      destLogCtrl->ipc.port 	   = tmp_sLogCtrl.ipc.port; 	
      destLogCtrl->ipc.portCnt     = tmp_sLogCtrl.ipc.portCnt; 	
      destLogCtrl->ipc.maxConns    = tmp_sLogCtrl.ipc.maxConns; 	
      destLogCtrl->ipc.callingIp   = tmp_sLogCtrl.ipc.callingIp; 
      destLogCtrl->ipc.callingPort = tmp_sLogCtrl.ipc.callingPort;
      destLogCtrl->ipc.maxQueCnt   = tmp_sLogCtrl.ipc.maxQueCnt; 
  
      }
    LOGCFG_FLOW2 ("LogCfg loading file %s, prefix %s", 
		      logCfgxCtrl->logFileName, logCfgxCtrl->fileNamePrefix);
    if (logFileChanged)
      {
      _slog (destLogCtrl,_logcfg_log_flow_logstr, thisFileName,__LINE__, 
        	"See the file '%s' for messages logged before or during Logging config",
                  oldFileName);
      }
#endif
    logCfgxCtrl->state = LOGCFGX_STATE_NONE;
    return (SD_SUCCESS);
    }


/* Get the pointer to the contents */
  strLen = 0;
  rc = sx_get_string_ptr (sxDecCtrl, &str, &strLen);
  if (rc != SD_SUCCESS)
    return (rc);

/* OK, this might be an Log Mask or other value of interest */
/* If we are to save this in a list, start here */
  if (logCfgxCtrl->saveTagVals && logCfgxCtrl->state == LOGCFGX_STATE_LOGMASKS)
    {
    tagVal = logCfgFindTagVal (tag);
    if (tagVal)
      {
      list_unlink (&_tagValList, tagVal);
      if (tagVal->dataType == _LOGCFG_DATATYPE_STRING || 
          tagVal->dataType == _LOGCFG_DATATYPE_FILENAME)
        {
        chk_free (tagVal->u.str);
        }
      chk_free (tagVal);
      }
    
    tagVal = (LOGCFGX_TAG_VAL*)chk_calloc (1, sizeof (LOGCFGX_TAG_VAL) + strlen (tag) + 1);
    p = (ST_CHAR *) (tagVal + 1);
    tagVal->tag = p;
    strcpy (p, tag);
    list_add_last (&_tagValList, tagVal);
    }
  else
    tagVal = NULL;

/* Now see if we can find it ... */
  found = SD_FALSE;
  slogMaskGroup = logCfgLogMaskGroupList;
  while (slogMaskGroup)
    {
    for (i = 0; i < slogMaskGroup->numMaskMap; ++i)
      {
      if (!strcmp (tag, slogMaskGroup->maskMapTbl[i].tag))
        {
        found = SD_TRUE;
        if (tagVal != NULL)
	  tagVal->dataType = slogMaskGroup->maskMapTbl[i].dataType;

	switch (slogMaskGroup->maskMapTbl[i].dataType)
	  {
	  case _LOGCFG_DATATYPE_UINT_MASK:
            up =(ST_UINT*) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_string_OnOff_bool (sxDecCtrl, &b, SX_ERR_CONVERT);
            if (b)
              *up |= slogMaskGroup->maskMapTbl[i].mask; /* Set the bit */
            else
              *up &= ~slogMaskGroup->maskMapTbl[i].mask; /* Clear the bit */

            LOGCFG_CFLOW2 ("Setting log mask %-16s %s", tag, b ? "ON" : "OFF");

            if (tagVal != NULL)
              tagVal->u.b = b;
	  break;

	  case _LOGCFG_DATATYPE_UINT32_MASK:
            u32p =(ST_UINT32 *) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_string_OnOff_bool (sxDecCtrl, &b, SX_ERR_CONVERT);
            if (b)
              *u32p |= slogMaskGroup->maskMapTbl[i].mask; /* Set the bit */
            else
              *u32p &= ~slogMaskGroup->maskMapTbl[i].mask; /* Clear the bit */

            LOGCFG_CFLOW2 ("Setting log mask %-16s %s", tag, b ? "ON" : "OFF");
            if (tagVal != NULL)
              tagVal->u.b = b;
	  break;

          /* 'R'everse mask settings */
          case _LOGCFG_DATATYPE_RUINT32_MASK:
            up =(ST_UINT *) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_string_OnOff_bool (sxDecCtrl, &b, SX_ERR_CONVERT);
            if (b)
              *up &= ~slogMaskGroup->maskMapTbl[i].mask; /* Clear the bit */
            else
              *up |= slogMaskGroup->maskMapTbl[i].mask; /* Set the bit */

            LOGCFG_CFLOW2 ("Setting log mask %-16s %s", tag, b ? "ON" : "OFF");
            if (tagVal != NULL)
              tagVal->u.b = b;
	  break;

	  case _LOGCFG_DATATYPE_BOOLEAN:
            bp = (ST_BOOLEAN *) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_string_OnOff_bool (sxDecCtrl, bp, SX_ERR_CONVERT);
            LOGCFG_CFLOW2 ("Setting boolean  %-16s %s", tag, *bp ? "ON" : "OFF");
            if (tagVal != NULL)
              tagVal->u.b = *bp;
          break;

	  case _LOGCFG_DATATYPE_INT:
	  case _LOGCFG_DATATYPE_UINT:
            up =(ST_UINT *) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_uint (sxDecCtrl, up);
            LOGCFG_CFLOW2 ("Setting %16s to %d", tag, (int) *up);
            if (tagVal != NULL)
              tagVal->u.uInt = *up;
          break;

	  case _LOGCFG_DATATYPE_LONG:
	  case _LOGCFG_DATATYPE_ULONG:
            ulp =(ST_ULONG *) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_ulong (sxDecCtrl, ulp);
            LOGCFG_CFLOW2 ("Setting %16s to %ld", tag, (long int) *ulp);
            if (tagVal != NULL)
              tagVal->u.uLong = *ulp;
          break;

	  case _LOGCFG_DATATYPE_INT16:
	  case _LOGCFG_DATATYPE_UINT16:
            u16p =(ST_UINT16*) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_uint16 (sxDecCtrl, u16p);
            LOGCFG_CFLOW2 ("Setting %16s to %d", tag, (int) *u16p);
            if (tagVal != NULL)
              tagVal->u.uInt16 = *u16p;
          break;

	  case _LOGCFG_DATATYPE_INT32:
	  case _LOGCFG_DATATYPE_UINT32:
            u32p = (ST_UINT32 *)slogMaskGroup->maskMapTbl[i].addr;
            sx_get_ulong (sxDecCtrl, u32p);
            LOGCFG_CFLOW2 ("Setting %16s to %d", tag, (int) *u32p);
            if (tagVal != NULL)
              tagVal->u.uInt32 = *u32p;
          break;

	  case _LOGCFG_DATATYPE_DOUBLE:
            dp =(ST_DOUBLE *) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_double (sxDecCtrl, dp);
            LOGCFG_CFLOW2 ("Setting %16s to %.4f", tag, *dp);
            if (tagVal != NULL)
              tagVal->u.uInt32 = *u32p;
          break;

	  case _LOGCFG_DATATYPE_STRING:
            cpp =(ST_CHAR **) slogMaskGroup->maskMapTbl[i].addr;
            sx_get_alloc_string (sxDecCtrl, cpp);
            LOGCFG_CFLOW2 ("Setting %16s to '%s'", tag, *cpp);
            if (tagVal != NULL)
              tagVal->u.str = *cpp;
          break;

	  case _LOGCFG_DATATYPE_STRINGBUF:
            cp =(ST_CHAR *) slogMaskGroup->maskMapTbl[i].addr;
	    strLen = 0;
            sx_get_string_ptr (sxDecCtrl, &str, &strLen);
            LOGCFG_CFLOW2 ("Setting %16s to '%s'", tag, str);
            cp =(ST_CHAR *) slogMaskGroup->maskMapTbl[i].addr;
            strncpy_safe (cp, str, slogMaskGroup->maskMapTbl[i].mask);

            if (tagVal != NULL)
              tagVal->u.str = cp;
          break;

	  case _LOGCFG_DATATYPE_FILENAME:
            cpp = (ST_CHAR **)slogMaskGroup->maskMapTbl[i].addr;

 	  /* The user might want a prefix for this file name */
            strLen = 0;
            sx_get_string_ptr (sxDecCtrl, &str, &strLen);
            if (logCfgxCtrl->fileNamePrefix)
              strLen += strlen (logCfgxCtrl->fileNamePrefix);
            p =(ST_CHAR *) chk_malloc (strLen+1);
            *cpp = p;
            if (logCfgxCtrl->fileNamePrefix)
              strcpy (p, logCfgxCtrl->fileNamePrefix);
	    else
              *p = 0;
            strcat (p, str);

            LOGCFG_CFLOW2 ("Setting %-16s to '%s'", tag, p);
            if (tagVal != NULL)
              tagVal->u.str = p;
          break;

	  case _LOGCFG_DATATYPE_CALLBACK:
            logCfgCallbackFun =	(ST_VOID(*)(SX_DEC_CTRL*,ST_CHAR*,LOGCFGX_VALUE_MAP*)) slogMaskGroup->maskMapTbl[i].addr;
            if (logCfgCallbackFun != NULL)
	      		(*logCfgCallbackFun) (sxDecCtrl, tag, &slogMaskGroup->maskMapTbl[i]);
          break;
	  }
        break;
        }
      }
    slogMaskGroup =(LOGCFG_VALUE_GROUP*) list_get_next (logCfgLogMaskGroupList, slogMaskGroup);
    }

/* If we did not find it but are supposed to get it's value anyway ... */
  if (tagVal != NULL && found == SD_FALSE)
    {
    strLen = 0;
    sx_get_string_ptr (sxDecCtrl, &str, &strLen);
    if (!stricmp (str, "On"))
      {
      LOGCFG_CFLOW1 ("Setting log mask %-16s ON", tag);
      tagVal->u.b = SD_TRUE;
      tagVal->dataType = _LOGCFG_DATATYPE_BOOLEAN;
      }
    else if (!stricmp (str, "Off"))
      {
      LOGCFG_CFLOW1 ("Setting log mask %-16s OFF", tag);
      tagVal->u.b = SD_FALSE;
      tagVal->dataType = _LOGCFG_DATATYPE_BOOLEAN;
      }
    else
      {
      tagVal->u.str = chk_strdup (p);;
      tagVal->dataType = _LOGCFG_DATATYPE_STRING;
      }
    }

  return (SD_SUCCESS);
  }

