tools-2.0.4/ 0000775 0001750 0001750 00000000000 12551123006 011374 5 ustar vogu vogu tools-2.0.4/toolcfg.cpp 0000664 0001750 0001750 00000257306 12551122733 013560 0 ustar vogu vogu // ****************************************************************************
// Project: libguytools
// ****************************************************************************
// Programmer: Guy Voncken
// Police Grand-Ducale
// Service de Police Judiciaire
// Section Nouvelles Technologies
// ****************************************************************************
// Module: Configuration utility
// ****************************************************************************
// Copyright 2008, 2009, 2010, 2011, 2012 Guy Voncken
//
// This file is part of libguytools.
//
// libguytools is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// libguytools is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with libguytools. If not, see .
/* ------------------------------ */
/* Includes */
/* ------------------------------ */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "tooltypes.h"
#include "toolglobalid.h"
#include "toolconstants.h"
#include "toolerror.h"
#include "toolcfg.h"
/* ------------------------------ */
/* Constants */
/* ------------------------------ */
const t_char CHAR_LF = 0x0A;
const t_char CHAR_CR = 0x0D;
const t_char CHAR_EOF = 0x1A;
const t_char CHAR_APPEND_LINE = '\\';
const t_char STRING_DELIMITER = '\'';
const t_int MAX_CFG_NESTING_LEVEL = 6; /* maximum number of nested INCLUDE directives */
/* reserved keywords */
static t_pcchar KEYWORD_TABLESTART = "TABLE";
static t_pcchar KEYWORD_TABLEEND = "ENDTABLE";
static t_pcchar KEYWORD_SECTIONSTART = "SECTION";
static t_pcchar KEYWORD_SECTIONEND = "ENDSECTION";
static t_pcchar KEYWORD_INCLUDE = "INCLUDE";
static t_pcchar KEYWORD_INCLUDE_OPT = "INCLUDE_OPTIONAL";
static t_pcchar KEYWORD_REMARK = "REM";
static t_pcchar KEYWORD_DEFINE = "DEFINE";
static t_pcchar KEYWORD_UNDEFINE = "UNDEFINE";
// static t_pcchar MINUS_LINE = "------------------------------------------------------------------------------"
// "------------------------------------------------------------------------------"
// "------------------------------------------------------------------------------";
/* ------------ */
/* Memory IDs */
/* ------------ */
static const t_int MemIdCfgBuffer = MEMID_BASE_TOOL_CFG + 0;
static const t_int MemIdCfgErrorHeader = MEMID_BASE_TOOL_CFG + 1;
static const t_int MemIdCfgContextStack = MEMID_BASE_TOOL_CFG + 2;
static const t_int MemIdCfgTemplateHeader = MEMID_BASE_TOOL_CFG + 3;
static const t_int MemIdCfgHelpBuff = MEMID_BASE_TOOL_CFG + 4;
static const t_int MemIdCfgHelpString = MEMID_BASE_TOOL_CFG + 5;
static const t_int MemIdCfgHelpInt = MEMID_BASE_TOOL_CFG + 6;
static const t_int MemIdCfgHelpTable = MEMID_BASE_TOOL_CFG + 7;
static const t_int MemIdCfgTableType = MEMID_BASE_TOOL_CFG + 8;
static const t_int MemIdCfgTableName = MEMID_BASE_TOOL_CFG + 9;
static const t_int MemIdCfgLogConfiguration = MEMID_BASE_TOOL_CFG + 10;
/* ------------------------------ */
/* Type & structure definitions */
/* ------------------------------ */
typedef enum
{ /*! \brief Command line parameter priority */
PRIORITY_HIGH, /*!< Command line parameters have high priority */
PRIORITY_LOW /*!< Command line parameters have low priority */
} t_Priority;
typedef enum /*! \brief States for CFG parser state machine */
{
CFGSTATE_INCLUDENEWFILE,
CFGSTATE_INCLUDENEWFILE_OPT,
CFGSTATE_GETNEWLINE,
CFGSTATE_CHECKINCLUDE,
CFGSTATE_CHECKSECTION,
CFGSTATE_LINEREAD,
CFGSTATE_COMPLETED,
CFGSTATE_CHECKEOF,
CFGSTATE_SEARCHSECTIONEND,
CFGSTATE_CHECKSECTIONEND
} t_ToolCfgState;
#define MAX_SECTIONNAME_LEN 63
#define MAX_FILENAME_LEN 4095
#define MAX_SECTIONNAMES 16
#define MAX_GLOBALSECTIONNAMES 16
typedef char t_ToolCfgSectionName[MAX_SECTIONNAME_LEN+1];
typedef struct
{
t_int BufferLen;
t_int ActLineLen;
t_int ActLineNr;
t_pchar pActLine;
t_pchar pBuffer;
t_char FileName [MAX_FILENAME_LEN +1];
t_ToolCfgSectionName SectionNameArr[MAX_SECTIONNAMES]; // These section names are only valid during the the scanning of one include file
t_int SectionNesting;
t_ToolCfgState State;
} t_ToolCfgContext, *t_pToolCfgContext;
typedef struct
{
int argc;
char **argv;
t_Priority Priority;
t_pToolCfgUserLogFn pUserLogFn;
t_pToolCfgContext pCfgContextStack;
t_pToolCfgContext pActCfgContext;
t_int IncludeNestingLevel;
t_int MaxIncludeNestingLevel;
t_char TempFileName[MAX_FILENAME_LEN+1];
t_ToolCfgSectionName GlobalSectionNameArr[MAX_GLOBALSECTIONNAMES]; // These section names remain defined during the whole cfg sanning time
} t_ToolCfgLocal;
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
/* ------------------------------ */
/* Variables */
/* ------------------------------ */
t_ToolCfgLocal ToolCfgLocal;
/* ------------------------------ */
/* Functions */
/* ------------------------------ */
/* -------------------------------------- */
/* Memory access with / without ToolMem */
/* -------------------------------------- */
#ifdef TOCFG_COMPILE_FOR_USE_WITHOUT_TOOLBOX
#define MEM_OPT_NONE 0
#define MEM_REGISTER_MEMID(MemId) NO_ERROR
#endif
static APIRET ToolCfgMemAlloc (t_pvoid *ppMem, t_uint Size, t_uint Options, t_int MemId)
{
APIRET rc;
#ifdef TOCFG_COMPILE_FOR_USE_WITHOUT_TOOLBOX
rc = Options; // To prevent from compiler warning "unused..."
rc = MemId; // To prevent from compiler warning "unused..."
*ppMem = malloc (Size);
if (*ppMem == NULL)
rc = TOOLCFG_ERROR_MALLOC_FAILED;
else rc = NO_ERROR;
#else
rc = ToolMemAlloc (ppMem, Size, Options, MemId);
#endif
return rc;
}
static APIRET ToolCfgMemFree (t_pvoid pMem, t_int MemId)
{
APIRET rc;
#ifdef TOCFG_COMPILE_FOR_USE_WITHOUT_TOOLBOX
rc = MemId; // To prevent from compiler warning "unused..."
free (pMem);
rc = NO_ERROR;
#else
rc = ToolMemFree (pMem, MemId);
#endif
return rc;
}
/* -------------------- */
/* Error management */
/* -------------------- */
/* Error return values in this module are simply raised to the calling function. */
/* This way, the module CFG does not depend on any log management. */
#define CFG_CHK_APP(Fn) \
{ \
APIRET ec; \
\
if ((ec=Fn) != NO_ERROR) \
{ \
if (ec != TOOLCFG_ERROR_CONFIG_ERROR) \
(void) ToolCfgLogEntry(__FFL__, "Error %d.", ec); \
return ec; \
} \
}
#define CFG_CHK_FPRINTF(Fn) \
{ \
if ((Fn) < 1) \
return TOOLCFG_ERROR_FPRINTF_FAILED; \
}
static APIRET ToolCfgLogEntry (t_pcchar pFileName, t_pcchar pFunctionName, t_int LineNr, t_pcchar pFormat, ...)
{
// APIRET rc=1;
va_list VaList;
va_start(VaList, pFormat); /* VaList points to the argument following pFormat */
if (ToolCfgLocal.pUserLogFn)
(*ToolCfgLocal.pUserLogFn)(pFileName, pFunctionName, LineNr, pFormat, VaList);
// if (rc)
// (void) vfprintf (stderr, pFormat, VaList);
va_end(VaList);
return NO_ERROR;
}
static APIRET ToolCfgStdErrorHeader (t_pcchar pActCursor)
{
t_pToolCfgContext pCfgContext;
t_pchar pEndOfLine;
t_pchar pBuff;
t_int Cursor;
t_int LineLen;
pCfgContext = ToolCfgLocal.pActCfgContext;
if (pCfgContext->FileName[0] == '\0')
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Configuration error in command line. Parameter %d", pCfgContext->ActLineNr))
else CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Configuration error in file %s line %d" , &pCfgContext->FileName[0], pCfgContext->ActLineNr))
if (pCfgContext->pActLine)
{
pEndOfLine = pCfgContext->pActLine + pCfgContext->ActLineLen;
*pEndOfLine = '\0';
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "[%s]", pCfgContext->pActLine))
}
if (pActCursor && pCfgContext->pActLine)
{
LineLen = (t_int) strlen (pCfgContext->pActLine);
Cursor = pActCursor - pCfgContext->pActLine;
Cursor = max (Cursor, 0 );
Cursor = min (Cursor, LineLen-1);
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pBuff, (t_uint)(LineLen+3), MEM_OPT_NONE, MemIdCfgErrorHeader)) /* +3 for [ ] and '\0' */
(void) sprintf (pBuff, "[%*s^%*s]", Cursor, "", LineLen-Cursor-1, "");
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pBuff))
CFG_CHK_APP (ToolCfgMemFree (pBuff, MemIdCfgErrorHeader))
}
return NO_ERROR;
}
/* ------------------------------------- */
/* Utility functions */
/* ------------------------------------- */
static t_int ToolCfgStrCmpNoCase (const char *pStr1, const char *pStr2)
{
#ifdef _WIN32
return strcmpi (pStr1, pStr2);
#else
return strcasecmp (pStr1, pStr2);
#endif
}
static t_int ToolCfgStrNCmpNoCase (const char *pStr1, const char *pStr2, t_int Len)
{
#ifdef _WIN32
return strnicmp (pStr1, pStr2, Len);
#else
return strncasecmp (pStr1, pStr2, (size_t)Len);
#endif
}
static t_pchar ToolCfgStrMaxCpy (t_pchar pDest, t_pcchar pSrc, t_int DestLen)
{
if (DestLen == 0)
return pDest;
pDest[DestLen-1] = '\0';
return strncpy (pDest, pSrc, DestLen-1);
}
static APIRET ToolCfgCopyName (t_pcchar pSrc, t_pchar pDst, t_int DstLen)
{
t_int SrcLen;
if (pSrc == NULL)
pDst[0] = '\0';
else
{
SrcLen = (t_int)strlen(pSrc);
if (SrcLen > DstLen)
{
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "SrcLen: %d DstLen: %d", SrcLen, DstLen))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "SrcString: %50.50s", pSrc))
return TOOLCFG_ERROR_NAME_TOO_LONG;
}
else
(void) strcpy (pDst, pSrc);
}
return NO_ERROR;
}
static APIRET ToolCfgFindFirstWord (t_pcchar pActLine, const char **ppFirstWord, t_int LineLen, t_pint pRemLineLen)
{
for ( *ppFirstWord = pActLine;
((**ppFirstWord == ' ') || (**ppFirstWord == '\t')) && (LineLen > 0);
( *ppFirstWord)++, LineLen--)
{
}
if ((LineLen <= 0) || (**ppFirstWord == CHAR_LF) || (**ppFirstWord == CHAR_CR))
*ppFirstWord = NULL;
*pRemLineLen = LineLen;
return NO_ERROR;
}
static APIRET ToolCfgCompareKeyWord (t_pcchar pTableKeyWord, t_pchar pCheckKeyWord, t_int LineLen, t_pint pEq, t_pchar *ppNextChar)
{
t_pchar pNextChar;
t_int TableKeyLen;
t_int CheckKeyLen;
t_pchar pCh;
pNextChar = NULL;
*pEq = FALSE;
TableKeyLen = (t_int) strlen (pTableKeyWord);
if (pCheckKeyWord && (LineLen >= TableKeyLen))
{
CheckKeyLen = 0;
for (pCh = pCheckKeyWord;
(*pCh != ' ') && (*pCh != CHAR_CR) &&
(*pCh != '=') && (*pCh != CHAR_LF) && (*pCh != '\t') && (*pCh != '\0');
pCh++)
CheckKeyLen++;
if (CheckKeyLen == TableKeyLen)
{
if (ToolCfgStrNCmpNoCase (pTableKeyWord, pCheckKeyWord, CheckKeyLen) == 0)
{
pNextChar = &pCheckKeyWord[CheckKeyLen];
*pEq = TRUE;
}
}
}
if (ppNextChar)
*ppNextChar = pNextChar;
return NO_ERROR;
}
static APIRET ToolCfgGetParamLen (t_pcchar pParam, t_pint pParamLen)
{
t_int LoopEnd;
/* count param len */
*pParamLen = 0;
LoopEnd = FALSE;
if (*pParam == STRING_DELIMITER)
{
pParam++;
(*pParamLen)++;
while (!LoopEnd)
{
if (*pParam == '\0')
LoopEnd = TRUE;
else if (*pParam == STRING_DELIMITER)
{
if (*(pParam+1) == STRING_DELIMITER)
{
pParam++;
(*pParamLen)++;
}
else
{
LoopEnd = TRUE;
}
}
if (!LoopEnd)
{
pParam++;
(*pParamLen)++;
}
}
}
else
{
while ((*pParam != ' ') && (*pParam != '\t') && (*pParam != '\0') && (*pParam != CHAR_CR) && (*pParam != CHAR_LF))
{
pParam++;
(*pParamLen)++;
}
}
if (*pParam == STRING_DELIMITER) /* is there a string end delimiter? */
{
pParam++;
(*pParamLen)++;
}
/* was there a param? */
// if ((*pParam == '\0') && (*pParamLen == 0))
if (*pParamLen == 0)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam-1))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Parameter expected."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
return NO_ERROR;
}
static APIRET ToolCfgCheckIfOnlyOneParam (t_pchar pParam, t_pint pParamLen)
{
CFG_CHK_APP (ToolCfgGetParamLen (pParam, pParamLen))
pParam += *pParamLen;
/* skip trailing spaces */
while (((*pParam == ' ') || (*pParam == '\t')) && (*pParam != '\0'))
pParam++;
/* is there a second param? */
if (*pParam != '\0')
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "No further parameter expected."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
return NO_ERROR;
}
static APIRET ToolCfgCheckIfNoParam (t_pchar pCh)
{
while (((*pCh == ' ') || (*pCh == '\t')) && (*pCh != '\0'))
pCh++;
if (*pCh != '\0')
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pCh))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "No further parameter expected."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
return NO_ERROR;
}
/* ----------------------------------------------------------------------------------- */
/* Help text builder. It is used to help the user enter the correct parameter values */
/* ----------------------------------------------------------------------------------- */
static APIRET ToolCfgChkStrCpy (t_pchar pDstStr, t_pcchar pSrcStr, t_pint pCumulLen)
{
if (pDstStr)
(void) strcpy (pDstStr + *pCumulLen, pSrcStr);
(*pCumulLen) += (t_int)strlen (pSrcStr);
return NO_ERROR;
}
static APIRET ToolCfgBuildHelpHMS(t_pToolCfgDataDesc pCfgDataDesc, t_pchar pHelpBuff, t_pint pHelpBuffLen)
{
t_pchar pTmp;
t_int MinVal;
t_int MaxVal;
MinVal = (t_int)pCfgDataDesc->MinValue;
MaxVal = (t_int)pCfgDataDesc->MaxValue;
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp, 256, MEM_OPT_NONE, MemIdCfgHelpInt))
(void) sprintf (pTmp, "[%02d:%02d:%02d..%02d:%02d:%02d]", MinVal/3600, (MinVal/60)%60, MinVal%60,
MaxVal/3600, (MaxVal/60)%60, MaxVal%60);
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, pTmp, pHelpBuffLen))
CFG_CHK_APP (ToolCfgMemFree (pTmp, MemIdCfgHelpInt))
return NO_ERROR;
}
static APIRET ToolCfgBuildHelpPresence (t_pToolCfgDataDesc /*pCfgDataDesc*/, t_pchar pHelpBuff, t_pint pHelpBuffLen)
{
t_pcchar pTmp;
pTmp = "Optional";
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, pTmp, pHelpBuffLen))
return NO_ERROR;
}
static APIRET ToolCfgBuildHelpInteger (t_pToolCfgDataDesc pCfgDataDesc, t_pchar pHelpBuff, t_pint pHelpBuffLen)
{
t_pchar pTmp;
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp, 256, MEM_OPT_NONE, MemIdCfgHelpInt))
(void) sprintf (pTmp, "[%d..%d] | [0x%X..0x%X]",
(t_int)pCfgDataDesc->MinValue, (t_int)pCfgDataDesc->MaxValue,
(t_int)pCfgDataDesc->MinValue, (t_int)pCfgDataDesc->MaxValue);
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, pTmp, pHelpBuffLen))
CFG_CHK_APP (ToolCfgMemFree (pTmp, MemIdCfgHelpInt))
return NO_ERROR;
}
static APIRET ToolCfgBuildHelpDouble (t_pToolCfgDataDesc pCfgDataDesc, t_pchar pHelpBuff, t_pint pHelpBuffLen)
{
t_pchar pTmp;
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp, 256, MEM_OPT_NONE, MemIdCfgHelpInt))
(void) sprintf (pTmp, "[%G..%G]", pCfgDataDesc->MinValue, pCfgDataDesc->MaxValue);
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, pTmp, pHelpBuffLen))
CFG_CHK_APP (ToolCfgMemFree (pTmp, MemIdCfgHelpInt))
return NO_ERROR;
}
static APIRET ToolCfgBuildHelpString (t_pToolCfgDataDesc pCfgDataDesc, t_pchar pHelpBuff, t_pint pHelpBuffLen)
{
t_pchar pTmp;
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp, 256, MEM_OPT_NONE, MemIdCfgHelpString))
(void) sprintf (pTmp, "''", (t_int)pCfgDataDesc->DestLen);
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, pTmp, pHelpBuffLen))
CFG_CHK_APP (ToolCfgMemFree (pTmp, MemIdCfgHelpString))
return NO_ERROR;
}
static APIRET ToolCfgBuildHelpSet (t_pToolCfgDataDesc pCfgDataDesc, t_pchar pHelpBuff, t_pint pHelpBuffLen)
{
t_pToolCfgSet pSetArray;
t_int i;
pSetArray = pCfgDataDesc->pSetArray;
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, "[", pHelpBuffLen))
for (i=0; ; i++)
{
if (pSetArray[i].pSetString == NULL) /* end of array? */
break;
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, pSetArray[i].pSetString, pHelpBuffLen))
if (pSetArray[i+1].pSetString)
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, ", ", pHelpBuffLen))
}
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, "]", pHelpBuffLen))
return NO_ERROR;
}
static APIRET ToolCfgBuildHelpRange (t_pToolCfgDataDesc pCfgDataDesc, t_pchar pHelpBuff, t_pint pHelpBuffLen)
{
switch (pCfgDataDesc->CfgType)
{
case CFGTYPE_PRESENCE: CFG_CHK_APP (ToolCfgBuildHelpPresence (pCfgDataDesc, pHelpBuff, pHelpBuffLen)) break;
case CFGTYPE_INTEGER: CFG_CHK_APP (ToolCfgBuildHelpInteger (pCfgDataDesc, pHelpBuff, pHelpBuffLen)) break;
case CFGTYPE_DOUBLE: CFG_CHK_APP (ToolCfgBuildHelpDouble (pCfgDataDesc, pHelpBuff, pHelpBuffLen)) break;
case CFGTYPE_STRING: CFG_CHK_APP (ToolCfgBuildHelpString (pCfgDataDesc, pHelpBuff, pHelpBuffLen)) break;
case CFGTYPE_SET: CFG_CHK_APP (ToolCfgBuildHelpSet (pCfgDataDesc, pHelpBuff, pHelpBuffLen)) break;
case CFGTYPE_HMS: CFG_CHK_APP (ToolCfgBuildHelpHMS (pCfgDataDesc, pHelpBuff, pHelpBuffLen)) break;
case CFGTYPE_NULL: break;
default:
return TOOLCFG_ERROR_INVALID_CFGTYPE;
}
return NO_ERROR;
}
static APIRET ToolCfgBuildHelp (t_pToolCfgDataDesc pCfgDataDesc, t_pchar pHelpBuff, t_pint pHelpBuffLen)
{
*pHelpBuffLen = 0;
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, pCfgDataDesc->pName, pHelpBuffLen))
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff, " = " , pHelpBuffLen))
CFG_CHK_APP (ToolCfgBuildHelpRange (pCfgDataDesc, pHelpBuff, pHelpBuffLen))
(*pHelpBuffLen)++;
return NO_ERROR;
}
static APIRET ToolCfgBuildTableHelp (t_pToolCfgTableDesc pCfgTableDesc,
t_pchar pHelpBuff1, t_pchar pHelpBuff2, t_pint pHelpBuffLen)
{
t_pToolCfgDataDesc pCfgDataDesc;
t_pchar pTmp;
t_int i;
t_int NameLen;
t_int RangeLen;
t_int Spaces;
t_int HelpBuffLenDummy;
t_int PrevLen;
*pHelpBuffLen = 0;
HelpBuffLenDummy = 0;
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp, 4096, MEM_OPT_NONE, MemIdCfgHelpTable))
for (i=0;;i++)
{
pCfgDataDesc = &pCfgTableDesc->pDataDescArray[i];
if (pCfgDataDesc->pName == NULL)
break;
NameLen = (t_int)strlen (pCfgDataDesc->pName);
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff1, pCfgDataDesc->pName, pHelpBuffLen))
PrevLen = HelpBuffLenDummy;
CFG_CHK_APP (ToolCfgBuildHelpRange (pCfgDataDesc, pHelpBuff2, &HelpBuffLenDummy))
RangeLen = HelpBuffLenDummy - PrevLen;
if (RangeLen != NameLen)
{
Spaces = abs (RangeLen - NameLen);
memset (pTmp, ' ', Spaces);
pTmp[Spaces] = '\0';
if (RangeLen > NameLen)
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff1, pTmp, pHelpBuffLen ))
else CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff2, pTmp, &HelpBuffLenDummy))
}
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff1, " ", pHelpBuffLen ))
CFG_CHK_APP (ToolCfgChkStrCpy (pHelpBuff2, " ", &HelpBuffLenDummy))
}
CFG_CHK_APP (ToolCfgMemFree (pTmp, MemIdCfgHelpTable))
(*pHelpBuffLen)++;
return NO_ERROR;
}
static APIRET ToolCfgQueryFileInfo (t_pchar pFileName, t_pint pYear, t_pint pMonth , t_pint pDay,
t_pint pHour, t_pint pMinute, t_pint pSize)
{
// OS/2 code
// ---------
// FILEFINDBUF3 FindBuff;
// HDIR hDir;
// ULONG Count;
//
// hDir = HDIR_SYSTEM;
// Count = 1; // Search for only 1 entry
// CFG_CHK_APP(DosFindFirst(pFileName, &hDir, FILE_NORMAL, &FindBuff, sizeof(FILEFINDBUF3), &Count, FIL_STANDARD))
// CFG_CHK_APP(DosFindClose(hDir))
//
// if (pYear ) *pYear = FindBuff.fdateLastWrite.year + OS2DOS_YEAROFFSET;
// if (pMonth ) *pMonth = FindBuff.fdateLastWrite.month;
// if (pDay ) *pDay = FindBuff.fdateLastWrite.day;
// if (pHour ) *pHour = FindBuff.ftimeLastWrite.hours;
// if (pMinute) *pMinute = FindBuff.ftimeLastWrite.minutes;
// if (pSize ) *pSize = (t_int)FindBuff.cbFile;
// Linux code
// ----------
struct stat FileInfo;
struct tm* LastModified = NULL;
memset (&FileInfo, 0, sizeof(FileInfo));
// Get file statistics
if (((stat (pFileName, &FileInfo)) == -1) || (!(FileInfo.st_mode & S_IFREG)))
{
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Could not stat configuration file %s: file not found", pFileName))
return TOOLCFG_ERROR_FILE_NOT_FOUND;
}
LastModified = localtime (&(FileInfo.st_mtime));
if (pYear ) *pYear = LastModified->tm_year + 1900;
if (pMonth ) *pMonth = LastModified->tm_mon + 1;
if (pDay ) *pDay = LastModified->tm_mday;
if (pHour ) *pHour = LastModified->tm_hour;
if (pMinute) *pMinute = LastModified->tm_min;
if (pSize ) *pSize = FileInfo.st_size;
return NO_ERROR;
}
static APIRET ToolCfgReadCmdLine (t_pToolCfgContext pCfgContext)
{
t_pchar pTmp;
t_int i;
t_uint Alloc;
t_int SpaceSplit;
/* Find size */
pCfgContext->BufferLen = 0;
for (i=1; iBufferLen += (t_int) strlen (ToolCfgLocal.argv[i]) + 1; /* +1 for CR */
}
pCfgContext->BufferLen++; /* ++ for ending '\0' */
/* Alloc memory */
Alloc = pCfgContext->BufferLen;
if (Alloc == sizeof(t_pvoid))
Alloc++;
CFG_CHK_APP (ToolCfgMemAlloc((void **)&pCfgContext->pBuffer, Alloc, MEM_OPT_NONE, MemIdCfgBuffer))
// Read command line into buffer, seperate arguments by a spaces
pTmp = pCfgContext->pBuffer;
for (i=1; ipBuffer;
*pTmp != '\0';
pTmp++)
{
if (*pTmp == STRING_DELIMITER)
SpaceSplit = !SpaceSplit;
if (SpaceSplit && (*pTmp == ' '))
*pTmp = CHAR_CR;
}
// pTmp = pCfgContext->pBuffer;
// for (i=1; iActLineLen = 0;
pCfgContext->ActLineNr = 1;
pCfgContext->pActLine = pCfgContext->pBuffer;
return NO_ERROR;
}
static APIRET ToolCfgReadCfgFile (t_pToolCfgContext pCfgContext)
{
FILE *pCfgFile;
t_int SizeRead;
t_int rc;
t_int Year, Month , Day;
t_int Hour, Minute;
t_int Size;
/* Expand filename (only possible when using the toolbox) */
#ifndef TOCFG_COMPILE_FOR_USE_WITHOUT_TOOLBOX
(void) strcpy (&ToolCfgLocal.TempFileName[0], &pCfgContext->FileName[0]);
CFG_CHK_APP (ToolEnvExpand (&ToolCfgLocal.TempFileName[0], &pCfgContext->FileName[0], MAX_FILENAME_LEN))
#endif
/* Find size */
pCfgFile = fopen (&pCfgContext->FileName[0], "rb");
if (pCfgFile == NULL)
{
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Could not open configuration file %s", &pCfgContext->FileName[0]))
return TOOLCFG_ERROR_OPEN_FAILED;
}
rc = setvbuf (pCfgFile, NULL, _IOFBF, 32768);
if (rc)
return TOOLCFG_ERROR_SETBUF_FAILED;
rc = fseek (pCfgFile, 0, SEEK_END);
if (rc)
return TOOLCFG_ERROR_SEEKEND_FAILED;
pCfgContext->BufferLen = (t_int) ftell (pCfgFile) + 1; /* +1 for ending '\0' */
/* Alloc memory */
CFG_CHK_APP (ToolCfgMemAlloc((void **)&pCfgContext->pBuffer, (t_uint)pCfgContext->BufferLen, MEM_OPT_NONE, MemIdCfgBuffer))
/* Read command line into buffer */
rc = fseek (pCfgFile, 0, SEEK_SET);
if (rc)
return TOOLCFG_ERROR_SEEKSET_FAILED;
SizeRead = (t_int) fread (pCfgContext->pBuffer, 1, (size_t)pCfgContext->BufferLen, pCfgFile);
if (SizeRead > pCfgContext->BufferLen)
return TOOLCFG_ERROR_READ_FAILED;
rc = fclose (pCfgFile);
if (rc)
return TOOLCFG_ERROR_CLOSE_FAILED;
pCfgContext->pBuffer[SizeRead] = '\0';
CFG_CHK_APP (ToolCfgQueryFileInfo (&pCfgContext->FileName[0], &Year, &Month, &Day, &Hour, &Minute, &Size))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Scanning configuration file %s (%d bytes %02d.%02d.%d %02d:%02d)",
&pCfgContext->FileName[0], Size, Day, Month, Year, Hour, Minute))
/* Set initial context */
pCfgContext->ActLineLen = 0;
pCfgContext->ActLineNr = 1;
pCfgContext->pActLine = pCfgContext->pBuffer;
return NO_ERROR;
}
static APIRET ToolCfgGetLineLen (t_pToolCfgContext pCfgContext)
{
t_pchar pEol;
t_pchar pLastBackslash;
t_int CopyLen;
t_int KeepRunning;
pLastBackslash = NULL;
KeepRunning = TRUE;
pEol = pCfgContext->pActLine;
while (KeepRunning)
{
switch (*pEol)
{
case CHAR_APPEND_LINE:
pLastBackslash = pEol++;
break;
case ' ' :
case '\t' : pEol++; break;
case CHAR_CR:
case CHAR_LF: if (pLastBackslash)
{
if (((*pEol == CHAR_CR) && (pEol[1] == CHAR_LF)) ||
((*pEol == CHAR_LF) && (pEol[1] == CHAR_CR)))
pEol++;
pEol++;
CopyLen = pCfgContext->pBuffer + pCfgContext->BufferLen - pEol;
memmove (pLastBackslash, pEol, CopyLen);
pEol = pLastBackslash;
pLastBackslash = NULL;
pCfgContext->ActLineNr++;
}
else
KeepRunning = FALSE;
break;
case '\0' : KeepRunning = FALSE;
break;
default : pLastBackslash = NULL;
pEol++;
}
}
pCfgContext->ActLineLen = pEol - pCfgContext->pActLine;
return NO_ERROR;
}
static APIRET ToolCfgSearchLine (t_pToolCfgContext pCfgContext)
{
t_pchar pTmp;
pTmp = pCfgContext->pActLine + pCfgContext->ActLineLen;
if (*pTmp != '\0')
{
if (((pTmp[0] == CHAR_LF) && (pTmp[1] == CHAR_CR)) ||
((pTmp[1] == CHAR_LF) && (pTmp[0] == CHAR_CR)))
pTmp += 2;
else pTmp += 1;
}
pCfgContext->ActLineNr++;
pCfgContext->pActLine = pTmp;
CFG_CHK_APP (ToolCfgGetLineLen (pCfgContext))
return NO_ERROR;
}
/* CfgNoFurtherParamsExpected reports an error if further */
/* parameters are found between pStart and the end of line. */
static APIRET ToolCfgNoFurtherParamsExpected (t_pcchar pStart, t_pcchar pCorrectSyntaxText)
{
while ((*pStart == ' ') || (*pStart == '\t'))
pStart++;
if ((*pStart != CHAR_CR) &&
(*pStart != CHAR_LF) &&
(*pStart != '\0'))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pStart))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "No further parameter expected."))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pCorrectSyntaxText))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
return NO_ERROR;
}
//static t_pchar ToolCfgFindEndOfString (t_pchar pString)
//{
// t_pchar pTmp;
//
// for ( pTmp = pString;
// (*pTmp != CHAR_CR) && (*pTmp != ' ') &&
// (*pTmp != CHAR_LF) && (*pTmp != '\t') && (*pTmp != '\0');
// pTmp++)
// {
// }
// return pTmp-1;
//}
static t_int ToolCfgScanningCmdLine (void)
{
if (ToolCfgLocal.pActCfgContext->FileName[0] == '\0')
return TRUE;
else return FALSE;
}
static APIRET ToolCfgDropContext (t_pToolCfgContext pCfgContext)
{
CFG_CHK_APP (ToolCfgMemFree (pCfgContext->pBuffer, MemIdCfgBuffer))
return NO_ERROR;
}
/* CfgGetNextLine is the core function of the configuration scanner. From the calling */
/* function's point of view, it simply reads the next line (or returns ppLine = NULL if */
/* no more data can be found). Internally it manages the INCLUDE and SECTION statements */
/* as well as trailing backslashes (for joining lines). */
static APIRET ToolCfgGetNextLine (t_pchar *ppLine, t_pint pLineLen)
{
t_pToolCfgContext pContext;
t_pchar pEol, pTmp, pKeyWord, pFirstWord;
t_int ParamLen;
t_int RemLineLen;
char TmpChar;
t_int KeyLen;
t_int KeyLenSectionStart;
t_int KeyLenSectionEnd;
t_int SectionNameFound;
t_int i;
t_int SectionSubNesting;
bool ChkInclude;
bool ChkIncludeOpt;
APIRET rc;
char Space[] = " ";
pTmp = Space;
pContext = ToolCfgLocal.pActCfgContext;
while ((pContext->State != CFGSTATE_LINEREAD) &&
(pContext->State != CFGSTATE_COMPLETED))
{
switch (pContext->State)
{
case CFGSTATE_INCLUDENEWFILE:
case CFGSTATE_INCLUDENEWFILE_OPT:
if (strlen (pContext->FileName) == 0)
rc = ToolCfgReadCmdLine (pContext); /* The cmd line has to be read into pBuffer */
else rc = ToolCfgReadCfgFile (pContext); /* The cfg file has to be read into pBuffer */
if ((rc == TOOLCFG_ERROR_OPEN_FAILED) && (pContext->State == CFGSTATE_INCLUDENEWFILE_OPT))
{
ToolCfgLocal.IncludeNestingLevel--;
ToolCfgLocal.pActCfgContext = &ToolCfgLocal.pCfgContextStack[ToolCfgLocal.IncludeNestingLevel];
pContext = ToolCfgLocal.pActCfgContext;
pContext->State = CFGSTATE_GETNEWLINE;
}
else
{
CFG_CHK_APP (rc)
pTmp = pContext->pActLine;
CFG_CHK_APP (ToolCfgGetLineLen (pContext))
pContext->State = CFGSTATE_CHECKEOF;
}
break;
case CFGSTATE_GETNEWLINE:
CFG_CHK_APP (ToolCfgSearchLine (pContext))
pContext->State = CFGSTATE_CHECKEOF;
break;
case CFGSTATE_CHECKEOF:
pTmp = pContext->pActLine;
if ((*pTmp == '\0') || (*pTmp == CHAR_EOF))
{
if (pContext->SectionNesting != 0)
{
pContext->pActLine = NULL;
CFG_CHK_APP (ToolCfgStdErrorHeader (NULL))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Missing statement %s before end of file.", KEYWORD_SECTIONEND))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
CFG_CHK_APP (ToolCfgDropContext (pContext))
ToolCfgLocal.IncludeNestingLevel--;
if (ToolCfgLocal.IncludeNestingLevel == -1) /* did we leave the last nesting level */
{
pTmp = NULL;
pContext->pActLine = NULL;
pContext->ActLineLen = 0;
pContext->State = CFGSTATE_COMPLETED;
}
else
{
ToolCfgLocal.pActCfgContext = &ToolCfgLocal.pCfgContextStack[ToolCfgLocal.IncludeNestingLevel];
pContext = ToolCfgLocal.pActCfgContext;
pContext->State = CFGSTATE_GETNEWLINE;
}
}
else
pContext->State = CFGSTATE_CHECKINCLUDE;
break;
case CFGSTATE_CHECKINCLUDE:
for ( pKeyWord = pTmp;
(*pKeyWord == ' ') || (*pKeyWord == '\t');
pKeyWord++)
{
}
ChkInclude = ToolCfgStrNCmpNoCase (pKeyWord, KEYWORD_INCLUDE , (t_int) strlen (KEYWORD_INCLUDE )) == 0;
ChkIncludeOpt = ToolCfgStrNCmpNoCase (pKeyWord, KEYWORD_INCLUDE_OPT, (t_int) strlen (KEYWORD_INCLUDE_OPT)) == 0;
if (ChkInclude || ChkIncludeOpt)
{
if (++ToolCfgLocal.IncludeNestingLevel >= ToolCfgLocal.MaxIncludeNestingLevel)
return TOOLCFG_ERROR_INCLUDE_NESTING_OVERFLOW;
pEol = pContext->pActLine + pContext->ActLineLen;
TmpChar = *pEol;
*pEol = '\0'; /* set to 0 to have sscanf stop at the end of line */
ToolCfgLocal.pActCfgContext = &ToolCfgLocal.pCfgContextStack[ToolCfgLocal.IncludeNestingLevel];
pContext = ToolCfgLocal.pActCfgContext;
if (ChkIncludeOpt)
{
pContext->State = CFGSTATE_INCLUDENEWFILE_OPT;
pFirstWord = pKeyWord + strlen (KEYWORD_INCLUDE_OPT);
}
else
{
pContext->State = CFGSTATE_INCLUDENEWFILE;
pFirstWord = pKeyWord + strlen (KEYWORD_INCLUDE);
}
// Initialize for parameter scanning
ParamLen = 0;
RemLineLen = strlen (pFirstWord);
// Get the filename
CFG_CHK_APP (ToolCfgFindFirstWord (pFirstWord + ParamLen, (const char **) &pFirstWord, RemLineLen, &RemLineLen))
CFG_CHK_APP (ToolCfgGetParamLen (pFirstWord, &ParamLen))
ToolCfgStrMaxCpy (&pContext->FileName[0], pFirstWord, min(MAX_FILENAME_LEN, ParamLen+1));
RemLineLen -= ParamLen;
// Get the section names
for (i=0; ;i++)
{
CFG_CHK_APP (ToolCfgFindFirstWord (pFirstWord + ParamLen, (const char **) &pFirstWord, RemLineLen, &RemLineLen))
if (pFirstWord == NULL)
break;
if (i >= MAX_SECTIONNAMES)
{
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Too many parameters for keyword %s or %s", KEYWORD_INCLUDE, KEYWORD_INCLUDE_OPT))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "The correct syntax is: %s [SectionName1] [SectionName2] ... [SectionName16]", KEYWORD_INCLUDE))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
CFG_CHK_APP (ToolCfgGetParamLen (pFirstWord, &ParamLen))
ToolCfgStrMaxCpy (&(pContext->SectionNameArr[i][0]), pFirstWord, min(MAX_SECTIONNAME_LEN, ParamLen)+1);
RemLineLen -= ParamLen;
}
*pEol = TmpChar;
while (iSectionNameArr[i++])[0] = '\0';
pContext->SectionNesting = 0;
}
else
pContext->State = CFGSTATE_CHECKSECTION;
break;
case CFGSTATE_CHECKSECTION:
for ( pKeyWord = pTmp; /* lint ?????????? */
(*pKeyWord == ' ') || (*pKeyWord == '\t');
pKeyWord++)
{
}
if (ToolCfgStrNCmpNoCase (pKeyWord, KEYWORD_SECTIONSTART, (t_int) strlen (KEYWORD_SECTIONSTART)) == 0)
{
// if (pContext->SectionNesting >0)
// {
// CFG_CHK_APP (ToolCfgStdErrorHeader (pKeyWord))
// CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "SECTION statements are not allowed to be nested within one file."))
// return TOOLCFG_ERROR_CONFIG_ERROR;
// }
pFirstWord = pKeyWord + strlen (KEYWORD_SECTIONSTART);
RemLineLen = strlen (pFirstWord);
CFG_CHK_APP (ToolCfgFindFirstWord (pFirstWord, (const char **) &pFirstWord, RemLineLen, &RemLineLen))
if (pFirstWord == NULL)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pFirstWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Section name expected."))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "The correct syntax is: SECTION [SectionName1] [SectionName2] ..."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
SectionNameFound = FALSE;
while (pFirstWord != NULL)
{
CFG_CHK_APP (ToolCfgGetParamLen (pFirstWord, &ParamLen))
TmpChar = pFirstWord[ParamLen];
pFirstWord[ParamLen] = '\0';
for (i=0; (iSectionNameArr[i][0]), pFirstWord) == 0); // pFirstWord may have less chars than SectionNameArr[i],
} // but in that case, ToolCfgStrCmpNoCase will no return 0 (eq)
if (!SectionNameFound)
{
for (i=0; (iSectionNesting++;
pContext->State = CFGSTATE_GETNEWLINE;
}
else
{
pContext->State = CFGSTATE_SEARCHSECTIONEND;
}
}
else
{
pContext->State = CFGSTATE_CHECKSECTIONEND;
}
break;
case CFGSTATE_CHECKSECTIONEND:
KeyLen = (t_int) strlen (KEYWORD_SECTIONEND);
for ( pKeyWord = pTmp; /* lint: ???? */
(*pKeyWord == ' ') || (*pKeyWord == '\t');
pKeyWord++)
{
}
if (ToolCfgStrNCmpNoCase (pKeyWord, KEYWORD_SECTIONEND, KeyLen) == 0)
{
CFG_CHK_APP (ToolCfgNoFurtherParamsExpected (pKeyWord + KeyLen, "ENDSECTION requires no parameters."))
if (pContext->SectionNesting <= 0)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pKeyWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "No corresponding SECTION statement encountered."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
else
{
pContext->SectionNesting--;
pContext->State = CFGSTATE_GETNEWLINE;
}
}
else
pContext->State = CFGSTATE_LINEREAD;
break;
case CFGSTATE_SEARCHSECTIONEND:
KeyLenSectionStart = (t_int) strlen (KEYWORD_SECTIONSTART);
KeyLenSectionEnd = (t_int) strlen (KEYWORD_SECTIONEND );
for (SectionSubNesting = 0;;)
{
CFG_CHK_APP (ToolCfgSearchLine (pContext))
if (*pContext->pActLine == '\0')
{
pContext->pActLine = NULL;
CFG_CHK_APP (ToolCfgStdErrorHeader (NULL))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Missing statement ENDSECTION before end of file."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
pTmp = pContext->pActLine;
while ((*pTmp != '\0') && ((*pTmp == ' ') || (*pTmp == '\t')))
pTmp++;
if (ToolCfgStrNCmpNoCase (pTmp, KEYWORD_SECTIONEND, KeyLenSectionEnd) == 0)
{
CFG_CHK_APP (ToolCfgNoFurtherParamsExpected (pTmp + KeyLenSectionEnd, "ENDSECTION requires no parameters."))
if (SectionSubNesting == 0)
{
pContext->State = CFGSTATE_GETNEWLINE;
break;
}
SectionSubNesting--;
}
else if (ToolCfgStrNCmpNoCase (pTmp, KEYWORD_SECTIONSTART, KeyLenSectionStart) == 0)
{
SectionSubNesting++;
}
}
break;
default:
return TOOLCFG_ERROR_INVALID_STATE;
}
}
pContext->State = CFGSTATE_GETNEWLINE; /* This will be our task on the next call of this function */
*ppLine = pContext->pActLine;
*pLineLen = pContext->ActLineLen;
return NO_ERROR;
}
/* ----------------------------------- */
/* Conversion functions */
/* ----------------------------------- */
static APIRET ToolCfgConvertpParamToHMS (t_pchar pParam, t_int /*ParamLen*/, t_pint pValue)
{
t_int rc;
t_int Hour, Min, Sec;
if (((pParam[0] >= '0') && (pParam[0] <= '9')))
{
rc = sscanf (pParam, "%d:%d:%d", &Hour, &Min, &Sec);
if (rc!=3)
{
Sec = 0;
rc = sscanf (pParam, "%d:%d", &Hour, &Min); // Check reduced HH:MM format
if (rc!=2)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid hh:mm:ss value."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
}
*pValue = Hour*3600 + Min*60 + Sec; // convert to seconds
}
else
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid entry, hh:mm:ss expected."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
return NO_ERROR;
}
static APIRET ToolCfgConvertpParamToInteger (t_pchar pParam, t_int ParamLen, t_pint pValue, t_pint pDecConv)
{
t_int rc;
t_int i;
t_int MinLen;
if ( ((pParam[0] == '0') && ((pParam[1] == 'x') || (pParam[1] == 'X'))) ||
(pParam[0] == '$'))
{
if (pParam[0] == '$')
MinLen = 1;
else MinLen = 2;
for (i=MinLen; i= '0') && (pParam[i] <= '9')) &&
!((pParam[i] >= 'a') && (pParam[i] <= 'f')) &&
!((pParam[i] >= 'A') && (pParam[i] <= 'F')))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam+i))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid hexadecimal value."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
}
if (ParamLen > MinLen)
rc = sscanf (&pParam[MinLen], "%x", pValue);
else rc = 0;
if (rc!=1)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid hexadecimal value."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
*pDecConv=FALSE;
}
else if (((pParam[0] >= '0') && (pParam[0] <= '9')) || (pParam[0] == '-'))
{
for (i=1; i '9'))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam+i))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid decimal value."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
}
rc = sscanf (pParam, "%d", pValue);
if (rc!=1)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid decimal value."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
*pDecConv=TRUE;
}
else
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid entry, decimal or hexadecimal number expected."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
return NO_ERROR;
}
static APIRET ToolCfgConvertpParamToDouble (t_pchar pParam, t_int ParamLen, t_pdouble pValue)
{
t_int rc;
long double LongDoubleVal;
t_pchar pOldLocale;
t_pchar pSavedLocale;
t_int i;
t_int DecimalPoint;
t_int Exponent;
// Check all the chars in the param to detect entry errors
// Convert ',' to '.'
DecimalPoint = FALSE;
Exponent = FALSE;
for (i=0; i '9'))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam+i))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid character encountered"))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
}
// switch the 'locale' to accept '.' as decimal point,
// scan the double value and switch back.
pOldLocale = setlocale (LC_NUMERIC, NULL);
pSavedLocale = strdup (pOldLocale);
(void) setlocale (LC_NUMERIC, "C");
rc = sscanf (pParam, "%LG", &LongDoubleVal);
(void) setlocale (LC_NUMERIC, pSavedLocale);
free (pSavedLocale);
if (rc!=1)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid double value."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
*pValue = (t_double) LongDoubleVal;
return NO_ERROR;
}
static APIRET ToolCfgReadParameterHMS (t_pchar pParam, t_int ParamLen, t_pToolCfgDataDesc pCfgDataDesc, long BaseAddr, t_int Assign)
{
t_pcchar pFormatStr;
t_int Value;
t_int MinVal, MaxVal;
CFG_CHK_APP (ToolCfgConvertpParamToHMS (pParam, ParamLen, &Value))
if ((Value < (t_int)pCfgDataDesc->MinValue) || (Value > (t_int)pCfgDataDesc->MaxValue))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
MinVal = (t_int)pCfgDataDesc->MinValue;
MaxVal = (t_int)pCfgDataDesc->MaxValue;
pFormatStr = "Value out of range: %02d:%02d:%02d <= %s <= %02d:%02d:%02d";
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pFormatStr, MinVal/3600, (MinVal/60)%60, MinVal%60, pCfgDataDesc->pName,
MaxVal/3600, (MaxVal/60)%60, MaxVal%60))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
if (Assign)
*((t_pint)((t_pchar)pCfgDataDesc->DestAddr + BaseAddr)) = Value;
return NO_ERROR;
}
static APIRET ToolCfgReadParameterInteger (t_pchar pParam, t_int ParamLen, t_pToolCfgDataDesc pCfgDataDesc, long BaseAddr, t_int Assign)
{
t_pcchar pFormatStr;
t_int Value;
t_int DecConv; /* To check whether a decimal or hexadecimal conversion had be performed */
CFG_CHK_APP (ToolCfgConvertpParamToInteger (pParam, ParamLen, &Value, &DecConv))
if ((Value < (t_int)pCfgDataDesc->MinValue) || (Value > (t_int)pCfgDataDesc->MaxValue))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
if (DecConv)
pFormatStr = "Value out of range: %d <= %s <= %d";
else pFormatStr = "Value out of range: 0x%X <= %s <= 0x%X";
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pFormatStr, (t_int)pCfgDataDesc->MinValue, pCfgDataDesc->pName, (t_int)pCfgDataDesc->MaxValue))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
if (Assign)
*((t_pint)((t_pchar)pCfgDataDesc->DestAddr + BaseAddr)) = Value;
return NO_ERROR;
}
static APIRET ToolCfgReadParameterDouble (t_pchar pParam, t_int ParamLen, t_pToolCfgDataDesc pCfgDataDesc, long BaseAddr, t_int Assign)
{
t_pcchar pFormatStr;
t_double Value;
CFG_CHK_APP (ToolCfgConvertpParamToDouble (pParam, ParamLen, &Value))
if ((Value < pCfgDataDesc->MinValue) || (Value > pCfgDataDesc->MaxValue))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
pFormatStr = "Value out of range: %G <= %s <= %G";
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pFormatStr, pCfgDataDesc->MinValue, pCfgDataDesc->pName, pCfgDataDesc->MaxValue))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
if (Assign)
*((t_pdouble)((t_pchar)pCfgDataDesc->DestAddr + BaseAddr)) = Value;
return NO_ERROR;
}
static APIRET ToolCfgConvertpParamToString (t_pchar pParam, t_int ParamLen, t_pchar *ppString, t_pint pStringLen)
{
if (pParam[0] != STRING_DELIMITER)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "String expected. Use %c %c as string delimiters.", STRING_DELIMITER, STRING_DELIMITER))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
if (pParam[ParamLen-1] != STRING_DELIMITER)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam+ParamLen-1))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "String exceeds end of line, use %c %c as string delimiters, or %c to append next line.", STRING_DELIMITER, STRING_DELIMITER, CHAR_APPEND_LINE))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
*ppString = pParam+1;
*pStringLen = ParamLen-2;
return NO_ERROR;
}
static APIRET ToolCfgReadParameterString (t_pchar pParam, t_int ParamLen, t_pToolCfgDataDesc pCfgDataDesc, long BaseAddr, t_int Assign)
{
t_pchar pString;
t_int StringLen;
t_pchar pDest;
t_int Src, Dst;
CFG_CHK_APP (ToolCfgConvertpParamToString (pParam, ParamLen, &pString, &StringLen))
if (StringLen > pCfgDataDesc->DestLen)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "String too long. The maximum length of the string is %d", pCfgDataDesc->DestLen))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
if (Assign)
{
/* Copy the string, replace duplicate '' by single' */
pDest = (t_pchar)pCfgDataDesc->DestAddr + BaseAddr;
for (Src=0, Dst=0; SrcDestAddr + BaseAddr, pString, (size_t) StringLen);
// ((t_pchar)pCfgDataDesc->DestAddr + BaseAddr)[StringLen] = '\0';
}
return NO_ERROR;
}
static APIRET ToolCfgConvertpParamToSet (t_pchar pParam, t_int ParamLen, t_pToolCfgDataDesc pCfgDataDesc, t_pint pSetValue)
{
t_pchar pTmp;
t_int i;
t_int Len;
t_pToolCfgSet pSetArray;
pSetArray = pCfgDataDesc->pSetArray;
for (i=0; ; i++)
{
if (pSetArray[i].pSetString == NULL)
break; /* end of array */
if (ParamLen == (t_int)strlen (pSetArray[i].pSetString))
if (ToolCfgStrNCmpNoCase (pSetArray[i].pSetString, pParam, ParamLen) == 0)
break; /* set entry found */
}
if (pSetArray[i].pSetString == NULL)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pParam))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid set value."))
CFG_CHK_APP (ToolCfgBuildHelp (pCfgDataDesc, NULL, &Len))
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp, (t_uint)Len, MEM_OPT_NONE, MemIdCfgHelpBuff))
CFG_CHK_APP (ToolCfgBuildHelp (pCfgDataDesc, pTmp, &Len))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pTmp))
CFG_CHK_APP (ToolCfgMemFree (pTmp, MemIdCfgHelpBuff))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
*pSetValue = pSetArray[i].SetValue;
return NO_ERROR;
}
static APIRET ToolCfgReadParameterSet (t_pchar pParam, t_int ParamLen, t_pToolCfgDataDesc pCfgDataDesc, long BaseAddr, t_int Assign)
{
t_int SetValue;
CFG_CHK_APP (ToolCfgConvertpParamToSet (pParam, ParamLen, pCfgDataDesc, &SetValue))
if (Assign)
*((t_pint)((t_pchar)pCfgDataDesc->DestAddr + BaseAddr)) = SetValue;
return NO_ERROR;
}
static APIRET ToolCfgReadParameter0 (t_pchar pFirstParamChar, t_int ParamLen, t_pToolCfgDataDesc pCfgDataDesc, long BaseAddr, t_int Assign)
{
if (BaseAddr == (long)INT_MIN)
Assign = FALSE;
switch (pCfgDataDesc->CfgType)
{
case CFGTYPE_INTEGER: CFG_CHK_APP (ToolCfgReadParameterInteger (pFirstParamChar, ParamLen, pCfgDataDesc, BaseAddr, Assign)) break;
case CFGTYPE_DOUBLE : CFG_CHK_APP (ToolCfgReadParameterDouble (pFirstParamChar, ParamLen, pCfgDataDesc, BaseAddr, Assign)) break;
case CFGTYPE_STRING : CFG_CHK_APP (ToolCfgReadParameterString (pFirstParamChar, ParamLen, pCfgDataDesc, BaseAddr, Assign)) break;
case CFGTYPE_SET : CFG_CHK_APP (ToolCfgReadParameterSet (pFirstParamChar, ParamLen, pCfgDataDesc, BaseAddr, Assign)) break;
case CFGTYPE_HMS : CFG_CHK_APP (ToolCfgReadParameterHMS (pFirstParamChar, ParamLen, pCfgDataDesc, BaseAddr, Assign)) break;
case CFGTYPE_NULL : break;
default:
return TOOLCFG_ERROR_INVALID_CFGTYPE;
}
return NO_ERROR;
}
/* ---------------------------------------------- */
/* Table scanning functions */
/* ---------------------------------------------- */
APIRET ToolCfgAddGlobalSectionName (t_pcchar pSectionName)
{
t_int i;
if (strlen (pSectionName) > MAX_SECTIONNAME_LEN)
return TOOLCFG_ERROR_SECTIONNAME_TOO_LONG;
for (i=0; i=MAX_GLOBALSECTIONNAMES)
return TOOLCFG_ERROR_TOO_MANY_SECTIONNAMES;
return NO_ERROR;
}
APIRET ToolCfgDelGlobalSectionName (t_pcchar pSectionName)
{
t_int i;
if (strlen (pSectionName) > MAX_SECTIONNAME_LEN)
return TOOLCFG_ERROR_SECTIONNAME_TOO_LONG;
for (i=0; i=MAX_GLOBALSECTIONNAMES)
return TOOLCFG_ERROR_SECTIONNAME_NOTFOUND;
return NO_ERROR;
}
static APIRET ToolCfgScanTableAnalyseLine (t_pToolCfgTableDesc pCfgTableDesc, t_pchar pFirstWord, t_int RemLineLen,
long BaseAddr, t_pint pLineOk)
{
t_int i;
t_int ParamLen;
t_pToolCfgDataDesc pCfgDataDesc;
*pLineOk = FALSE;
/* printf ("\r\nTable entry: %*.*s", RemLineLen, RemLineLen, pFirstWord); */
if (RemLineLen == 0)
return NO_ERROR;
ParamLen = 0;
for (i=0; ;i++)
{
pCfgDataDesc = &pCfgTableDesc->pDataDescArray[i];
if (pCfgDataDesc->pName == NULL)
break; /* Array ends here */
CFG_CHK_APP (ToolCfgFindFirstWord (pFirstWord + ParamLen, (const char **) &pFirstWord, RemLineLen, &RemLineLen))
CFG_CHK_APP (ToolCfgGetParamLen (pFirstWord, &ParamLen))
CFG_CHK_APP (ToolCfgReadParameter0 (pFirstWord, ParamLen, pCfgDataDesc, BaseAddr, TRUE))
}
*pLineOk = TRUE;
return NO_ERROR;
}
static APIRET ToolCfgScanTable (t_pchar pActLine, t_int LineLen, t_pToolCfgTableDesc pCfgTableDescArray)
{
t_pchar pFirstWord;
t_int RemLineLen;
t_int i, rcs, Eq;
t_int LineOk;
t_int Found;
t_pchar pTableType;
t_pchar pTableName;
long BaseAddr;
t_pcchar pErrorText;
t_char TmpChar;
t_pToolCfgTableDesc pCfgTableDesc = NULL;
TmpChar = pActLine[LineLen]; /* set end of line to '\0' to ease processing */
pActLine[LineLen] = '\0';
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTableType, 64, MEM_OPT_NONE, MemIdCfgTableType))
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTableName, 64, MEM_OPT_NONE, MemIdCfgTableName))
CFG_CHK_APP (ToolCfgFindFirstWord (pActLine, (const char **) &pFirstWord, LineLen, &RemLineLen))
rcs = sscanf (pActLine, "%*s %s %s", pTableType, pTableName);
if (rcs != 2)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pFirstWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid parameters for keyword %s", KEYWORD_TABLESTART))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "The correct syntax is: %s ", KEYWORD_TABLESTART))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
Found = FALSE;
if (pCfgTableDescArray != NULL)
{
for (i=0; ;i++)
{
pCfgTableDesc = &pCfgTableDescArray[i];
if (pCfgTableDesc->pTableType == NULL) /* End of array reached? */
break;
if (ToolCfgStrCmpNoCase(pCfgTableDesc->pTableType, pTableType) == 0) /* Table type found? */
{
Found = TRUE;
break;
}
}
}
if (!Found)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pFirstWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid table type: %s", pTableType))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
CFG_CHK_APP ((*pCfgTableDesc->pStartFn) (pTableName, &BaseAddr, &pErrorText))
if (pErrorText)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pActLine))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pErrorText))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
pActLine[LineLen] = TmpChar;
for (LineLen=0;;)
{
CFG_CHK_APP (ToolCfgGetNextLine (&pActLine, &LineLen))
TmpChar = pActLine[LineLen]; /* set end of line to '\0' to ease processing */
pActLine[LineLen] = '\0';
if (pActLine == NULL)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (NULL))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Missing statement %s before end of file.", KEYWORD_TABLEEND))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
CFG_CHK_APP (ToolCfgFindFirstWord (pActLine, (const char **) &pFirstWord, LineLen, &RemLineLen))
CFG_CHK_APP (ToolCfgCompareKeyWord (KEYWORD_TABLEEND, pFirstWord, RemLineLen, &Eq, NULL))
if (Eq)
{
if (pCfgTableDesc->pEndFn)
{
CFG_CHK_APP ((*pCfgTableDesc->pEndFn) (&pErrorText))
if (pErrorText)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pActLine))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pErrorText))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
}
pActLine[LineLen] = TmpChar;
break;
}
CFG_CHK_APP (ToolCfgCompareKeyWord (KEYWORD_REMARK, pFirstWord, RemLineLen, &Eq, NULL))
if (!Eq)
{
CFG_CHK_APP (ToolCfgScanTableAnalyseLine (pCfgTableDesc, pFirstWord, RemLineLen, BaseAddr, &LineOk))
if (LineOk)
{
CFG_CHK_APP ((*pCfgTableDesc->pSaveAndNextFn) (&BaseAddr, &pErrorText))
if (pErrorText)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pActLine))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pErrorText))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
}
}
pActLine[LineLen] = TmpChar;
}
CFG_CHK_APP (ToolCfgMemFree (pTableType, MemIdCfgTableType))
CFG_CHK_APP (ToolCfgMemFree (pTableName, MemIdCfgTableName))
return NO_ERROR;
}
/* ---------------------------------------------- */
/* Parameter scanning functions */
/* ---------------------------------------------- */
static APIRET ToolCfgCheckAssignment (t_pchar pKeyWord, t_pToolCfgParamDesc pCfgParamDesc, t_pint pAssign)
{
t_ToolCfgAssignment AssignSource;
t_ToolCfgAssignment AssignCount;
AssignSource = (t_ToolCfgAssignment)(pCfgParamDesc->Assign & CFGASN_SOURCE);
AssignCount = (t_ToolCfgAssignment)(pCfgParamDesc->Assign & CFGASN_COUNT );
if ((AssignSource == CFGASN_CMD) && !ToolCfgScanningCmdLine())
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pKeyWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Assignment for this parameter is not allowed in configuration file (only on command line)."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
if ((AssignSource == CFGASN_CFG) && ToolCfgScanningCmdLine())
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pKeyWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Assignment for this parameter is not allowed on command line (only in configuration file)."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
if ((AssignCount == CFGASN_ONCE) && ((pCfgParamDesc->CfgAssignments + pCfgParamDesc->CmdAssignments) >= 1))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pKeyWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Assignment for this parameter is only allowed once"))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
if (AssignCount == CFGASN_TWICE)
{
if (((pCfgParamDesc->CfgAssignments>0) && !ToolCfgScanningCmdLine()) ||
((pCfgParamDesc->CmdAssignments>0) && ToolCfgScanningCmdLine()))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pKeyWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Assignment for this parameter is only allowed once in configuration file."))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "The assignment in configuration file may be replaced by a command line"))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "assignment"))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
}
if (ToolCfgScanningCmdLine())
*pAssign = TRUE;
else *pAssign = pCfgParamDesc->CmdAssignments ? FALSE : TRUE;
return NO_ERROR;
}
static APIRET ToolCfgCheckEqualSign (t_pcchar pNextChar, t_pcchar *ppFirstParamChar)
{
while (((*pNextChar == ' ') || (*pNextChar == '\t')) && (*pNextChar != '\0'))
pNextChar++;
if ((*pNextChar == '\0') || (*pNextChar != '='))
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pNextChar-1))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Equal sign '=' expected."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
for ( *ppFirstParamChar = pNextChar+1;
((**ppFirstParamChar == ' ') || (**ppFirstParamChar == '\t')) && (**ppFirstParamChar != '\0');
( *ppFirstParamChar)++)
{
}
if (**ppFirstParamChar == '\0')
{
CFG_CHK_APP (ToolCfgStdErrorHeader ((*ppFirstParamChar)-1))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Parameter expected."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
return NO_ERROR;
}
static APIRET ToolCfgReadParameter (t_pchar pKeyWord, t_pchar pNextChar, t_pToolCfgParamDesc pCfgParamDesc)
{
t_pToolCfgDataDesc pCfgDataDesc;
t_pchar pFirstParamChar;
t_pchar pErrorText;
t_int Assign;
t_int ParamLen;
if (pCfgParamDesc)
CFG_CHK_APP (ToolCfgCheckAssignment (pKeyWord, pCfgParamDesc, &Assign))
pCfgDataDesc = &pCfgParamDesc->DataDesc;
if (pCfgDataDesc->CfgType == CFGTYPE_PRESENCE)
{
CFG_CHK_APP (ToolCfgCheckIfNoParam (pNextChar))
*((t_pint)(pCfgParamDesc->DataDesc.DestAddr)) = TRUE;
}
else
{
CFG_CHK_APP (ToolCfgCheckEqualSign (pNextChar, (const char **) &pFirstParamChar))
CFG_CHK_APP (ToolCfgCheckIfOnlyOneParam (pFirstParamChar, &ParamLen))
CFG_CHK_APP (ToolCfgReadParameter0 (pFirstParamChar, ParamLen, pCfgDataDesc, 0, Assign))
}
if (Assign)
{
if (ToolCfgScanningCmdLine())
pCfgParamDesc->CmdAssignments++;
else pCfgParamDesc->CfgAssignments++;
}
if (pCfgParamDesc->pCallOnInitFn)
{
CFG_CHK_APP ((*pCfgParamDesc->pCallOnInitFn)(pCfgParamDesc, &pErrorText))
if (pErrorText)
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pKeyWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, pErrorText))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
}
return NO_ERROR;
}
static APIRET ToolCfgAnalyseEntry (t_pchar pActLine, t_int LineLen,
t_pToolCfgParamDesc pParamDescArray,
t_pToolCfgTableDesc pTableDescArray)
{
t_pchar pKeyWord;
t_pchar pNextChar;
t_pToolCfgDataDesc pCfgDataDesc;
t_int i;
t_int RemLineLen;
t_int Eq, EqDef, EqUnDef;
t_char TmpChar;
t_pchar pSectionName;
t_int SectionNameLen;
APIRET rc;
if (LineLen <=0) /* it's an empty line, unnecessary to continue */
return NO_ERROR;
TmpChar = pActLine[LineLen]; /* set end of line to '\0' to ease processing */
pActLine[LineLen] = '\0';
CFG_CHK_APP (ToolCfgFindFirstWord (pActLine, (const char **) &pKeyWord, LineLen, &RemLineLen))
if (pKeyWord == NULL) // Were there just spaces or tabs in this line ?
{
pActLine[LineLen] = TmpChar;
return NO_ERROR;
}
CFG_CHK_APP (ToolCfgCompareKeyWord (KEYWORD_TABLESTART, pKeyWord, RemLineLen, &Eq, NULL))
if (Eq)
{
pActLine[LineLen] = TmpChar;
CFG_CHK_APP (ToolCfgScanTable(pActLine, LineLen, pTableDescArray))
return NO_ERROR;
}
CFG_CHK_APP (ToolCfgCompareKeyWord (KEYWORD_REMARK, pKeyWord, RemLineLen, &Eq, NULL))
if (Eq)
{
pActLine[LineLen] = TmpChar;
return NO_ERROR;
}
CFG_CHK_APP (ToolCfgCompareKeyWord (KEYWORD_DEFINE , pKeyWord, RemLineLen, &EqDef , &pSectionName))
if (!EqDef)
CFG_CHK_APP (ToolCfgCompareKeyWord (KEYWORD_UNDEFINE, pKeyWord, RemLineLen, &EqUnDef, &pSectionName))
if (EqDef || EqUnDef)
{
while (((*pSectionName == ' ') || (*pSectionName == '\t')) && (*pSectionName != '\0'))
pSectionName++;
CFG_CHK_APP (ToolCfgCheckIfOnlyOneParam (pSectionName, &SectionNameLen))
pActLine[LineLen] = TmpChar;
TmpChar = pSectionName[SectionNameLen];
pSectionName[SectionNameLen] = '\0';
if (EqDef)
rc = ToolCfgAddGlobalSectionName (pSectionName);
else rc = ToolCfgDelGlobalSectionName (pSectionName);
switch (rc)
{
case TOOLCFG_ERROR_SECTIONNAME_TOO_LONG :
CFG_CHK_APP (ToolCfgStdErrorHeader (pSectionName))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Section name too long (Max. %d characters).", MAX_SECTIONNAME_LEN))
return TOOLCFG_ERROR_CONFIG_ERROR;
case TOOLCFG_ERROR_TOO_MANY_SECTIONNAMES:
CFG_CHK_APP (ToolCfgStdErrorHeader (pSectionName))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Too many global section names defined (Max. is %d).", MAX_GLOBALSECTIONNAMES))
return TOOLCFG_ERROR_CONFIG_ERROR;
case TOOLCFG_ERROR_SECTIONNAME_NOTFOUND:
CFG_CHK_APP (ToolCfgStdErrorHeader (pSectionName))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "The section name %s is not defined.", pSectionName))
return TOOLCFG_ERROR_CONFIG_ERROR;
default: CFG_CHK_APP (rc)
}
pSectionName[SectionNameLen] = TmpChar;
return NO_ERROR;
}
Eq = FALSE;
if (pParamDescArray != NULL)
{
for (i=0; ; i++)
{
pCfgDataDesc = &pParamDescArray[i].DataDesc;
if (pCfgDataDesc->pName == NULL)
break;/* end of array */
CFG_CHK_APP (ToolCfgCompareKeyWord (pCfgDataDesc->pName, pKeyWord, RemLineLen, &Eq, &pNextChar))
if (Eq)
{
CFG_CHK_APP (ToolCfgReadParameter (pKeyWord, pNextChar, &pParamDescArray[i]))
break;
}
}
}
if (!Eq) /* keyword not found in table */
{
CFG_CHK_APP (ToolCfgStdErrorHeader (pKeyWord))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Invalid keyword."))
return TOOLCFG_ERROR_CONFIG_ERROR;
}
pActLine[LineLen] = TmpChar;
return NO_ERROR;
}
/* CfgFreeContextBuffers: Free all context buffers that are still in use */
static APIRET ToolCfgFreeContextBuffers (void)
{
t_pToolCfgContext pCfgContext;
t_int i;
for (i=ToolCfgLocal.IncludeNestingLevel; i>0; i--)
{
pCfgContext = &ToolCfgLocal.pCfgContextStack[i];
if (pCfgContext->pBuffer)
CFG_CHK_APP (ToolCfgMemFree (pCfgContext->pBuffer, MemIdCfgBuffer))
}
return NO_ERROR;
}
static APIRET ToolCfgScanParams (t_pToolCfgParamDesc pParamDescArray, t_pToolCfgTableDesc pTableDescArray)
{
t_pchar pActLine;
t_int LineLen;
APIRET rc;
CFG_CHK_APP (ToolCfgGetNextLine (&pActLine, &LineLen))
rc = NO_ERROR;
while (pActLine && !rc)
{
rc = ToolCfgAnalyseEntry(pActLine, LineLen, pParamDescArray, pTableDescArray);
if (!rc)
CFG_CHK_APP (ToolCfgGetNextLine (&pActLine, &LineLen))
}
CFG_CHK_APP (ToolCfgFreeContextBuffers())
CFG_CHK_APP (rc)
return NO_ERROR;
}
static APIRET ToolCfgScanSource (t_pcchar pFileName,
t_pcchar pSectionName,
t_pToolCfgParamDesc pParamDescArray,
t_pToolCfgTableDesc pTableDescArray)
{
APIRET rc;
t_int ContextStackSize;
t_int i;
ContextStackSize = ToolCfgLocal.MaxIncludeNestingLevel * (t_int) sizeof (t_ToolCfgContext);
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&ToolCfgLocal.pCfgContextStack, (t_uint)ContextStackSize, MEM_OPT_NONE, MemIdCfgContextStack))
ToolCfgLocal.pActCfgContext = &ToolCfgLocal.pCfgContextStack[0];
ToolCfgLocal.IncludeNestingLevel = 0;
/* initialise first context stack entry */
ToolCfgLocal.pActCfgContext->BufferLen = 0;
ToolCfgLocal.pActCfgContext->ActLineNr = 0;
ToolCfgLocal.pActCfgContext->pActLine = NULL;
ToolCfgLocal.pActCfgContext->pBuffer = NULL;
ToolCfgLocal.pActCfgContext->SectionNesting = 0;
ToolCfgLocal.pActCfgContext->State = CFGSTATE_INCLUDENEWFILE;
CFG_CHK_APP (ToolCfgCopyName (pFileName , & ToolCfgLocal.pActCfgContext->FileName [0] , MAX_FILENAME_LEN ))
CFG_CHK_APP (ToolCfgCopyName (pSectionName, &(ToolCfgLocal.pActCfgContext->SectionNameArr[0][0]), MAX_SECTIONNAME_LEN))
for (i=1; iSectionNameArr[i][0] = '\0';
rc = ToolCfgScanParams (pParamDescArray, pTableDescArray);
CFG_CHK_APP (ToolCfgMemFree (ToolCfgLocal.pCfgContextStack, MemIdCfgContextStack))
CFG_CHK_APP (rc)
return NO_ERROR;
}
/* CfgCheckInitialisation: Check whether all parameters have been initialized. */
static APIRET ToolCfgCheckInitialisation(t_pToolCfgParamDesc pParamDescArray)
{
t_int i, Err;
t_pToolCfgParamDesc pCfgParamDesc;
t_pToolCfgDataDesc pCfgDataDesc;
Err = FALSE;
for (i=0; ;i++)
{
pCfgParamDesc = &pParamDescArray[i];
pCfgDataDesc = &pCfgParamDesc->DataDesc;
if (pCfgDataDesc->pName == NULL)
break; /* end of array reached */
if (( pCfgParamDesc->CfgAssignments == 0 ) &&
( pCfgParamDesc->CmdAssignments == 0 ) &&
( pCfgParamDesc->DataDesc.CfgType != CFGTYPE_NULL ) &&
( pCfgParamDesc->DataDesc.CfgType != CFGTYPE_PRESENCE) && // Parameters of type 'presence' are always optional
((pCfgParamDesc->Assign & CFGASN_OPTIONAL) == 0 ))
{
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Configuration error: Parameter %s has not been initialized.", pCfgDataDesc->pName))
Err = TRUE;
}
}
if (Err)
return TOOLCFG_ERROR_CONFIG_ERROR;
return NO_ERROR;
}
static APIRET ToolCfgLogGetSetName (t_pToolCfgSet pSetArray, t_int SetValue, t_pcchar *ppSetString)
{
t_int i;
*ppSetString = NULL;
for (i=0; ; i++)
{
if (pSetArray[i].pSetString == NULL)
break; /* end of array */
if (pSetArray[i].SetValue == SetValue)
{
*ppSetString = pSetArray[i].pSetString;
break;
}
}
return NO_ERROR;
}
static APIRET ToolCfgPrintContents (t_pchar pBuff, t_pToolCfgParamDesc pCfgParamDesc)
{
t_pToolCfgDataDesc pCfgDataDesc;
t_pchar pSetString;
t_int Hms;
t_int SetValue;
if ((pCfgParamDesc->CfgAssignments == 0) &&
(pCfgParamDesc->CmdAssignments == 0))
{
sprintf (pBuff, "not initialized");
}
else
{
pCfgDataDesc = &pCfgParamDesc->DataDesc;
switch (pCfgDataDesc->CfgType)
{
case CFGTYPE_PRESENCE:sprintf (pBuff, "%s" , *(int *)pCfgDataDesc->DestAddr ? "present" : "not present"); break;
case CFGTYPE_INTEGER: sprintf (pBuff, "%d (0x%X)", *(int *)pCfgDataDesc->DestAddr, *(int *)pCfgDataDesc->DestAddr); break;
case CFGTYPE_DOUBLE: sprintf (pBuff, "%G" , *(double*)pCfgDataDesc->DestAddr); break;
case CFGTYPE_STRING: sprintf (pBuff, "%s" , (char *)pCfgDataDesc->DestAddr); break;
case CFGTYPE_SET: SetValue = *(int *)pCfgDataDesc->DestAddr;
CFG_CHK_APP (ToolCfgLogGetSetName (pCfgDataDesc->pSetArray, SetValue, (const char **) &pSetString))
if (pSetString == NULL)
sprintf (pBuff, "Set str unknown for value %d", SetValue);
else sprintf (pBuff, "%s", pSetString);
break;
case CFGTYPE_HMS: Hms = (*(int *)pCfgDataDesc->DestAddr);
sprintf (pBuff, "%02d:%02d:%02d", Hms/3600, (Hms/60)%60, Hms%60);
break;
case CFGTYPE_NULL: break;
default:
return TOOLCFG_ERROR_INVALID_CFGTYPE;
}
}
return NO_ERROR;
}
APIRET ToolCfgPrintParamContents (t_pToolCfgParamDesc pParamDescArray, t_pchar pName, t_pchar pBuff)
{
t_pToolCfgParamDesc pCfgParamDesc;
t_pToolCfgDataDesc pCfgDataDesc;
t_int i;
if (pBuff)
pBuff[0] = '\0';
for (i=0; ;i++)
{
pCfgParamDesc = &pParamDescArray[i];
pCfgDataDesc = &pCfgParamDesc->DataDesc;
if (pCfgDataDesc->pName == NULL)
return TOOLCFG_ERROR_UNKNOWN_PARAMETER;
if (ToolCfgStrCmpNoCase (pCfgDataDesc->pName, pName) == 0)
{
if (pBuff)
CFG_CHK_APP (ToolCfgPrintContents (pBuff, pCfgParamDesc))
break;
}
}
return NO_ERROR;
}
/* ToolCfgLogConfiguration: Write all the configuration parameters with their values to the log file */
APIRET ToolCfgLogConfiguration (t_pToolCfgParamDesc pParamDescArray)
{
t_pToolCfgParamDesc pCfgParamDesc;
t_pToolCfgDataDesc pCfgDataDesc;
t_pchar pBuff;
t_int i, Err;
t_int wr;
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pBuff, 4096, MEM_OPT_NONE, MemIdCfgLogConfiguration))
Err = FALSE;
for (i=0; ;i++)
{
pCfgParamDesc = &pParamDescArray[i];
pCfgDataDesc = &pCfgParamDesc->DataDesc;
if (pCfgDataDesc->pName == NULL)
break; /* end of array reached */
if (( pCfgParamDesc->CfgAssignments == 0 ) &&
( pCfgParamDesc->CmdAssignments == 0 ) &&
( pCfgParamDesc->DataDesc.CfgType != CFGTYPE_NULL ) &&
( pCfgParamDesc->DataDesc.CfgType != CFGTYPE_PRESENCE) && // Parameters of type 'presence' are always optional
((pCfgParamDesc->Assign & CFGASN_OPTIONAL) == 0 ))
{
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "Parameter %s has not been initialized.", pCfgDataDesc->pName))
Err = TRUE;
}
else
{
wr = sprintf (pBuff, "%s = ", pCfgDataDesc->pName);
CFG_CHK_APP (ToolCfgPrintContents (&pBuff[wr], pCfgParamDesc))
CFG_CHK_APP (ToolCfgLogEntry(__FFL__, "%s", pBuff))
}
}
CFG_CHK_APP (ToolCfgMemFree (pBuff, MemIdCfgLogConfiguration))
if (Err)
return TOOLCFG_ERROR_CONFIG_ERROR;
return NO_ERROR;
}
/* ToolCfgResetAssignCounters: Reset all assignment counters for all keywords */
static APIRET ToolCfgResetAssignCounters (t_pToolCfgParamDesc pParamDescArray)
{
t_int i;
for (i=0; ; i++)
{
if (pParamDescArray[i].DataDesc.pName == NULL)
break; /* end of array reached */
pParamDescArray[i].CmdAssignments = 0;
pParamDescArray[i].CfgAssignments = 0;
}
return NO_ERROR;
}
/* CfgGetCmdLineOption: Read an option from the command line. This function is */
/* usually called to get the configuration or log file name. */
APIRET ToolCfgGetCmdLineOption (t_pcchar pParamName, t_pcchar *ppValue)
{
t_int i, Eq;
t_int LineLen = 0;
t_pchar pNextChar = NULL;
t_ToolCfgContext CfgContext;
*ppValue = NULL;
Eq = 0;
for (i=1; i 0) && (LineFlag))
{
LineLen = (t_int) strlen (pRemark);
rcp = fprintf (pFile, "\r\n%*s%s ", Indent, "", KEYWORD_REMARK);
CFG_CHK_FPRINTF(rcp)
for (i=0; ipName == NULL)
break; /* end of array reached */
Source = (t_ToolCfgAssignment) (pParamDescArray[i].Assign & CFGASN_SOURCE);
if (((Source & CFGASN_CMD) && !(Source & CFGASN_CFG) && (CfgParams == FALSE)) ||
((Source & CFGASN_CFG) && (CfgParams == TRUE )))
{
CFG_CHK_APP (ToolCfgBuildHelp (pCfgDataDesc, NULL, &Len))
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp1, (t_uint)Len, MEM_OPT_NONE, MemIdCfgHelpBuff))
CFG_CHK_APP (ToolCfgBuildHelp (pCfgDataDesc, pTmp1, &Len))
CFG_CHK_FPRINTF (fprintf (pFile, "\r\n %s", pTmp1))
CFG_CHK_APP (ToolCfgMemFree (pTmp1, MemIdCfgHelpBuff))
(*pEntries)++;
}
}
}
if (CfgParams && pTableDescArray)
{
for (i=0; ; i++)
{
pCfgTableDesc = &pTableDescArray[i];
if (pCfgTableDesc->pTableType == NULL)
break; /* end of array reached */
CFG_CHK_APP (ToolCfgBuildTableHelp (pCfgTableDesc, NULL, NULL, &Len))
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp1, (t_uint)Len, MEM_OPT_NONE, MemIdCfgHelpBuff))
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp2, (t_uint)Len, MEM_OPT_NONE, MemIdCfgHelpBuff))
CFG_CHK_APP (ToolCfgBuildTableHelp (pCfgTableDesc, pTmp1, pTmp2, &Len))
CFG_CHK_FPRINTF (fprintf (pFile, "\r\n\r\n %s %s ", KEYWORD_TABLESTART, pCfgTableDesc->pTableType))
CFG_CHK_APP (ToolCfgEnterRemark (pFile, pTmp1, 6, TRUE ))
CFG_CHK_APP (ToolCfgEnterRemark (pFile, pTmp2, 6, FALSE))
CFG_CHK_FPRINTF (fprintf (pFile, "\r\n %s", KEYWORD_TABLEEND))
CFG_CHK_APP (ToolCfgMemFree (pTmp1, MemIdCfgHelpBuff))
CFG_CHK_APP (ToolCfgMemFree (pTmp2, MemIdCfgHelpBuff))
(*pEntries)++;
}
}
return NO_ERROR;
}
APIRET ToolCfgBuildTemplate (t_pcchar pFileName, t_pcchar pComment,
t_pcchar pSectionName,
t_ToolCfgParamDesc *pParamDescArray,
t_ToolCfgTableDesc *pTableDescArray)
{
FILE *pFile;
t_int Entries, rc;
t_pchar pTmp;
const t_int TmpLen = 256;
struct tm *NowTM;
time_t NowT;
pFile = fopen(pFileName, "wb");
if (pFile == NULL)
return TOOLCFG_ERROR_TEMPLATE_OPEN_FAILED;
setbuf (pFile, NULL);
CFG_CHK_APP (ToolCfgMemAlloc ((void **)&pTmp, TmpLen, MEM_OPT_NONE, MemIdCfgTemplateHeader))
(void) time (&NowT);
NowTM = localtime (&NowT);
rc = sprintf (pTmp, "Configuration file template, created on ");
(void) strftime (pTmp+rc, (size_t)(TmpLen-rc), "%d/%m/%Y %H:%M:%S", NowTM);
CFG_CHK_APP (ToolCfgEnterRemark (pFile, pTmp, 0, TRUE))
CFG_CHK_APP (ToolCfgMemFree (pTmp, MemIdCfgTemplateHeader))
if(pComment)
CFG_CHK_APP (ToolCfgEnterRemark (pFile, pComment, 0, TRUE))
if (pSectionName)
CFG_CHK_FPRINTF (fprintf (pFile, "\r\n\r\n%s %s\r\n", KEYWORD_SECTIONSTART, pSectionName))
CFG_CHK_APP (ToolCfgBuildTemplate0 (pFile, TRUE, &Entries, pParamDescArray, pTableDescArray))
if (pSectionName)
CFG_CHK_FPRINTF (fprintf (pFile, "\r\n\r\n%s", KEYWORD_SECTIONEND))
CFG_CHK_APP (ToolCfgEnterEmptyLine (pFile))
CFG_CHK_APP (ToolCfgEnterRemark (pFile, "Options, that can only be entered on command line", 0, TRUE))
CFG_CHK_APP (ToolCfgBuildTemplate0 (pFile, FALSE, &Entries, pParamDescArray, pTableDescArray))
if (Entries == 0)
CFG_CHK_APP (ToolCfgEnterRemark (pFile, "There are no such options", 0, FALSE))
CFG_CHK_APP (ToolCfgEnterEmptyLine (pFile))
CFG_CHK_APP (ToolCfgEnterEmptyLine (pFile))
rc = fclose(pFile);
if (rc)
return TOOLCFG_ERROR_CLOSE_FAILED;
return NO_ERROR;
}
/* ToolCfgSetErrLogFn: The application can specify the desired logging */
/* function here (for example vprintf, or an own function). */
APIRET ToolCfgSetLogFn (t_pToolCfgUserLogFn pUserLogFn)
{
ToolCfgLocal.pUserLogFn = pUserLogFn;
return NO_ERROR;
}
APIRET ToolCfgGetSetString (t_pToolCfgSet pSetArray, int SetValue, const char **ppSetString)
{
t_pToolCfgSet pSet;
*ppSetString = NULL;
for (pSet = &pSetArray[0]; pSet->pSetString != NULL; pSet++)
{
if (pSet->SetValue == SetValue)
{
*ppSetString = pSet->pSetString;
break;
}
}
return NO_ERROR;
}
/* ------------------------------ */
/* Module initialisation */
/* ------------------------------ */
static int IsInit = 0;
APIRET ToolCfgInit (int argc, char *argv[])
{
if(IsInit == 1)
return NO_ERROR;
IsInit = 1;
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (ERROR_BASE_TOOL_CFG ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_OPEN_FAILED ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_READ_FAILED ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_CLOSE_FAILED ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_SEEKEND_FAILED ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_SEEKSET_FAILED ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_INVALID_STATE ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_NAME_TOO_LONG ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_INCLUDE_NESTING_OVERFLOW ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_CONFIG_ERROR ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_INVALID_ASSIGNMENT_OPTION))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_INVALID_CFGTYPE ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_TEMPLATE_OPEN_FAILED ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_FPRINTF_FAILED ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_CMDLINE_OPTION_NOT_FOUND ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_MALLOC_FAILED ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_SECTIONNAME_TOO_LONG ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_TOO_MANY_SECTIONNAMES ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_SECTIONNAME_NOTFOUND ))
CFG_CHK_APP (TOOL_ERROR_REGISTER_CODE (TOOLCFG_ERROR_UNKNOWN_PARAMETER ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgBuffer ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgErrorHeader ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgContextStack ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgTemplateHeader ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgHelpBuff ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgHelpString ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgHelpInt ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgHelpTable ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgTableType ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgTableName ))
CFG_CHK_APP (MEM_REGISTER_MEMID (MemIdCfgLogConfiguration))
ToolCfgLocal.argc = argc;
ToolCfgLocal.argv = argv;
ToolCfgLocal.pUserLogFn = NULL;
ToolCfgLocal.MaxIncludeNestingLevel = MAX_CFG_NESTING_LEVEL;
memset (&ToolCfgLocal.GlobalSectionNameArr[0], 0, sizeof (ToolCfgLocal.GlobalSectionNameArr));
return NO_ERROR;
}
APIRET ToolCfgUseAdjustedCommandLine (int argc, char *argv[])
{
ToolCfgLocal.argc = argc;
ToolCfgLocal.argv = argv;
return NO_ERROR;
}
APIRET ToolCfgDeInit (void)
{
if(IsInit == 0)
return NO_ERROR;
CFG_CHK_APP (ToolCfgFreeContextBuffers ())
IsInit = 0;
return NO_ERROR;
}
tools-2.0.4/toolsysinfo.cpp 0000664 0001750 0001750 00000010074 12551122733 014500 0 ustar vogu vogu // ****************************************************************************
// Project: libguytools
// ****************************************************************************
// Programmer: Guy Voncken
// Police Grand-Ducale
// Service de Police Judiciaire
// Section Nouvelles Technologies
// ****************************************************************************
// Module: System information
// ****************************************************************************
// Copyright 2008, 2009, 2010, 2011, 2012 Guy Voncken
//
// This file is part of libguytools.
//
// libguytools is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// libguytools is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with libguytools. If not, see .
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include "toolconstants.h"
#include "toolglobalid.h"
#include "toolerror.h"
#include "toolsysinfo.h"
// ------------------------------------
// Constants
// ------------------------------------
// ------------------------------------
// Type definitions
// ------------------------------------
// ------------------------------------
// Local variables
// ------------------------------------
static bool ToolSysInfoInitialized = false;
// ------------------------------------
// Functions
// ------------------------------------
APIRET ToolSysInfoGetMacAddr (t_pToolSysInfoMacAddr pMacAddr)
{
struct ifreq Ifr;
struct ifreq *pIfr;
struct ifconf Ifc;
char buf[1024];
int s, i, wr;
bool ok = false;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s==-1)
return TOOLSYSINFO_ERROR_SOCKET;
Ifc.ifc_len = sizeof(buf);
Ifc.ifc_buf = buf;
ioctl(s, SIOCGIFCONF, &Ifc);
pIfr = Ifc.ifc_req;
for (i = Ifc.ifc_len / sizeof(struct ifreq); --i >= 0; pIfr++)
{
strcpy (Ifr.ifr_name, pIfr->ifr_name);
if (ioctl (s, SIOCGIFFLAGS, &Ifr) == 0)
{
if (! (Ifr.ifr_flags & IFF_LOOPBACK))
{
if (ioctl(s, SIOCGIFHWADDR, &Ifr) == 0)
{
ok = true;
break;
}
}
}
}
close(s);
if (!ok)
return TOOLSYSINFO_ERROR_NO_ADDR;
bcopy (Ifr.ifr_hwaddr.sa_data, &pMacAddr->AddrVal[0], TOOLSYSINFO_MACADDRLEN_VAL);
wr = 0;
for (int i=0; iAddrStr[wr], "%02X", pMacAddr->AddrVal[i]);
return NO_ERROR;
}
APIRET ToolSysInfoUname (QString &Uname)
{
struct utsname name;
if (uname (&name) == -1)
return TOOLSYSINFO_ERROR_UNAME;
Uname = QString(name.sysname) + " " + name.nodename + " " + name.release + " " + name.version + " " + name.machine;
return NO_ERROR;
}
// ------------------------------
// Module initialisation
// ------------------------------
APIRET ToolSysInfoInit (void)
{
if (ToolSysInfoInitialized)
return TOOLSYSINFO_ALREADY_INITIALISED;
TOOL_CHK (TOOL_ERROR_REGISTER_CODE (ERROR_BASE_TOOL_SYSINFO))
TOOL_CHK (TOOL_ERROR_REGISTER_CODE (TOOLSYSINFO_ALREADY_INITIALISED))
TOOL_CHK (TOOL_ERROR_REGISTER_CODE (TOOLSYSINFO_ERROR_SOCKET))
TOOL_CHK (TOOL_ERROR_REGISTER_CODE (TOOLSYSINFO_ERROR_NO_ADDR))
TOOL_CHK (TOOL_ERROR_REGISTER_CODE (TOOLSYSINFO_ERROR_UNAME))
ToolSysInfoInitialized = true;
return NO_ERROR;
}
APIRET ToolSysInfoDeInit (void)
{
return NO_ERROR;
}
tools-2.0.4/tools.pro 0000664 0001750 0001750 00000001676 12551122733 013276 0 ustar vogu vogu TEMPLATE = lib
DESTDIR = ./lib
TARGET = guytools
include( ./libguytools_version.pro.inc )
# The following line allows the software to see its own version
# (just for logging purpose). Many slashes and quotes... look at
# result of it during compilation
DEFINES += "LIBGUYTOOLS_VERSION=\\\""$$VERSION"\\\""
# Use the standard Qt configuration but remove the GUI part, as we do not need it.
CONFIG += qt
QT -= gui
CONFIG += warn_on thread release
DEFINES += TOCFG_COMPILE_FOR_USE_WITHOUT_TOOLBOX
DEPENDPATH += ./include
INCLUDEPATH += ./include
QMAKE_CXXFLAGS_WARN_ON += -Wno-strict-aliasing # Switch off warning "dereferencing type-punned pointer will break strict-aliasing rules"
QMAKE_CXXFLAGS_WARN_ON += -fmessage-length=0 # Tell g++ not to split messages into different lines
QMAKE_CXXFLAGS_RELEASE += -O3
SOURCES += toollog.cpp
SOURCES += toolerror.cpp
SOURCES += toolsysinfo.cpp
SOURCES += toolsignal.cpp
SOURCES += toolcfg.cpp
tools-2.0.4/toolsignal.cpp 0000664 0001750 0001750 00000026574 12551122733 014277 0 ustar vogu vogu // ****************************************************************************
// Project: libguytools
// ****************************************************************************
// Programmer: Guy Voncken
// Police Grand-Ducale
// Service de Police Judiciaire
// Section Nouvelles Technologies
// ****************************************************************************
// Module: Signal handler with backtrace
// ****************************************************************************
// Copyright 2008, 2009, 2010, 2011, 2012 Guy Voncken
//
// This file is part of libguytools.
//
// libguytools is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// libguytools is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with libguytools. If not, see .
#include
#include
#include
//#define __USE_GNU
#include
#include
//#define __USE_XOPEN
#include
#include
#include
#include "tooltypes.h"
#include "toolglobalid.h"
#include "toolsignal.h"
#include "toolerror.h"
// ------------------------------------
// Type definitions
// ------------------------------------
typedef struct
{
t_pToolSignalLogFn pLogFn;
t_pToolSignalHandler pSignalHandlerFn;
struct sigaction SignalActionDefault;
} t_ToolSignalLocal;
// ------------------------------------
// Module variables
// ------------------------------------
bool ToolSignalInitialised = false;
t_ToolSignalLocal ToolSignalLocal;
// ------------------------------------
// Log functions
// ------------------------------------
static int ToolSignalLogEntry (bool Error, const char *pFileName, const char *pFunctionName, int LineNr, const char *pFormat, ...)
{
va_list VaList;
va_start(VaList, pFormat);
if (ToolSignalLocal.pLogFn)
{
(*ToolSignalLocal.pLogFn)(Error, pthread_self(), pFileName, pFunctionName, LineNr, pFormat, VaList);
}
else
{
printf ("\n");
vprintf (pFormat, VaList);
}
va_end(VaList);
return NO_ERROR;
}
// ------------------------------------
// Main functions
// ------------------------------------
static void ToolSignalStandardSet (sigset_t *pSignalSet)
{
sigfillset (pSignalSet); // Add all known signals to set, except the ones listed below:
sigdelset (pSignalSet, SIGSEGV); // - handled by our backtrace function, see below
sigdelset (pSignalSet, SIGPIPE); // - which would cause problems in ceratin situations when our program deals with pipes
sigdelset (pSignalSet, SIGWINCH); // - emitted on window resize
sigdelset (pSignalSet, SIGCHLD); // - QProcess relies on receiving this one in order to know when a child process finishes
} // These settings will be valid for the current thread and all its children threads. That's the reason, why
// ToolSignalInit should be called in the application main thread before starting any other thread.
static void *ToolSignalThread (void *p)
{
sigset_t SignalSet;
int Signal;
bool Exit;
char *pSignalName;
p=p; // Dummy statement to avoid compiler warning about unused p
ToolSignalLogEntry (false, __FFL__, "Signal guard thread started with id %d", getpid());
Exit = false;
while (!Exit)
{
ToolSignalStandardSet (&SignalSet);
sigwait (&SignalSet, &Signal); // wait for any signal in given set
// when we get here, we've caught a signal
// ---------------------------------------
pSignalName = strsignal(Signal);
ToolSignalLogEntry (true, __FFL__, "Thread (%d-%d): Caught signal: %s", getpid(), pthread_self(), pSignalName);
if (ToolSignalLocal.pSignalHandlerFn)
(*ToolSignalLocal.pSignalHandlerFn) (Signal);
switch (Signal)
{
case SIGTERM:
case SIGINT : Exit = true; break;
default: break;
}
}
ToolSignalLogEntry (true, __FFL__, "Stopping signal guard thread.");
return NULL;
}
// ToolSignalBacktraceHandler is called by any
// thread in the program causing a segment violation.
static void ToolSignalBacktraceHandler (int Signal, siginfo_t *pSignalInfo, void *pSecret)
{
const int TraceArrLen = 50;
char **ppMessages;
void *TraceArr[TraceArrLen];
int TraceSize;
int i;
static int RecursiveCallDetection = 0;
/* Code below is no longer needed. According to tests on amd64 and i386 on Ubuntu 14.04, the address of the
place the where exception occured nowadays is correctly included in the array data returned by backtrace().
It thus seems to be no longer necessary to separately fetch and add the instruction pointer corresponding
to the segmentation fault.
This wasn't the case on older systems, see for example http://www.linuxjournal.com/article/6391?page=0,1 .
void *pIP = NULL;
#if defined(__sparc__)
struct sigcontext* pSigContext = (struct sigcontext*) pSecret;
#if __WORDSIZE == 64
pIP = (void*) pSigContext->sigc_regs.tpc ;
#else
pIP = (void*) pSigContext->si_regs.pc ;
#endif
#else
ucontext_t* pUContext = (ucontext_t*) pSecret;
#if defined(__i386__)
pIP = (void*) pUContext->uc_mcontext.gregs[REG_EIP];
#elif defined(__x86_64__)
pIP = (void*) pUContext->uc_mcontext.gregs[REG_RIP];
#elif defined(__hppa__)
pIP = (void*) pUContext->uc_mcontext.sc_iaoq[0] & ~0x3UL;
#elif (defined (__ppc__)) || (defined (__powerpc__))
pIP = (void*) pUContext->uc_mcontext.regs->nip;
#elif defined(__arm__)
pIP = (void*) pUContext->uc_mcontext.arm_pc;
#elif defined(__aarch64__)
pIP = (void*) pUContext->uc_mcontext.pc;
#endif
#endif
*/
RecursiveCallDetection++;
switch (RecursiveCallDetection)
{
case 1:
ppMessages = NULL;
ToolSignalLogEntry (true, __FFL__, "----------------------------------------------------------------------");
if (Signal == SIGSEGV)
{
ToolSignalLogEntry (true, __FFL__, "Thread (%d-%d): Got signal '%s' (%d), faulty address is %p" /*, "from %p" */, // See remarks above
getpid(), pthread_self(), strsignal(Signal), Signal,
pSignalInfo->si_addr /*, pIP*/);
}
else
{
ToolSignalLogEntry (true, __FFL__, "Thread (%d-%d): Got signal '%s' (%d) -- strange, function should only be called on SIGSEGV.",
getpid(), pthread_self(), strsignal(Signal), Signal);
}
TraceSize = backtrace (TraceArr, TraceArrLen);
/* TraceArr[1] = pIP; */ // See remarks above
ppMessages = backtrace_symbols (TraceArr, TraceSize);
ToolSignalLogEntry (true, __FFL__, "Backtrace execution path");
ToolSignalLogEntry (true, __FFL__, "The first two entries are normally related to the signal handler.");
ToolSignalLogEntry (true, __FFL__, "The faulty code generally is referenced by the 3rd line in the listing below.");
for (i=0; i