1005 lines
34 KiB
C
1005 lines
34 KiB
C
/************************************************************************/
|
|
/* SISCO SOFTWARE MODULE HEADER *****************************************/
|
|
/************************************************************************/
|
|
/* (c) Copyright Systems Integration Specialists Company, Inc., */
|
|
/* 1993-2008, All Rights Reserved */
|
|
/* */
|
|
/* MODULE NAME : slog.c */
|
|
/* PRODUCT(S) : SLOG */
|
|
/* */
|
|
/* MODULE DESCRIPTION : */
|
|
/* */
|
|
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
|
|
/* */
|
|
/* MODIFICATION LOG : */
|
|
/* Date Who Rev Comments */
|
|
/* -------- --- ------ ------------------------------------------- */
|
|
/* 03/27/08 EJV 61 Use S_MAX_PATH instead of MAX_PATH. */
|
|
/* slog_get_index_file_name: added destLen param*/
|
|
/* and changed to return result. */
|
|
/* 02/06/08 EJV 60 Moved MAX_PATH define to sysincs.h */
|
|
/* _slogSetTimeTextElapsed _WIN32 only. */
|
|
/* 12/14/07 DSF 59 Added sNonStandardLogMode to support .NET */
|
|
/* Logger class */
|
|
/* 11/16/07 MDE 58 Fixed LINUX compile problems */
|
|
/* 10/23/07 MDE 57 Added ElapsedTime option for Windows */
|
|
/* 01/15/07 EJV 56 Chg S_LOCK_RESOURCES to S_LOCK_UTIL_RESOURCES*/
|
|
/* 01/08/07 EJV 55 slogIpcStop: added lc param. */
|
|
/* 09/13/06 DSF 54 No calls to ExceptionReport */
|
|
/* 08/18/06 JRB 53 Chk _slog_remote_fun along with other ptrs. */
|
|
/* 08/02/06 EJV 52 Corr: chg logMissed to ST_INT to avoid */
|
|
/* repeated logging when IPC_LOG_EN is set. */
|
|
/* 06/20/06 RLH 51 Added parameter checks and other robustness */
|
|
/* features to _slogXML */
|
|
/* 03/14/06 CRM 50 Added _slogXML to log XML strings */
|
|
/* 02/13/06 DSF 49 Migrate to VS.NET 2005 */
|
|
/* 01/23/06 EJV 48 doSlog: clarified buf overrun log for WIN32. */
|
|
/* 11/01/05 EJV 47 slog_end: added S_LOCK_RESOURCES. */
|
|
/* 10/31/05 MDE 46 Tweaked slog_end to stop IPC, disable */
|
|
/* 10/31/05 MDE 45 Default logging now disabled, log missed */
|
|
/* 10/21/05 MDE 44 Fixed slog_end path size */
|
|
/* 08/10/05 MDE 43 Added slog_start, slog_end */
|
|
/* 08/02/05 MDE 42 Fixed compile warning */
|
|
/* 05/23/05 EJV 40 doSlog corr: replaced LOG_IPC_EN with */
|
|
/* LOG_IPC_LISTEN_EN || LOG_IPC_CALL_EN */
|
|
/* Moved sock_debug_sel to gensock2.c */
|
|
/* Moved gs_debug_sel to glbsem.c */
|
|
/* 04/21/05 EJV 39 doSlog: use vsnprintf on Linux; */
|
|
/* Reworked the code assembling log in msg_buf.*/
|
|
/* 02/23/05 JRB 38 slogSetTimeText: fix for VXWORKS. */
|
|
/* 01/26/05 JRB 37 Move clnp_debug_sel to lean_var.c */
|
|
/* 01/24/05 MDE 36 Fixed tweak */
|
|
/* 01/20/05 MDE 35 Minor tweak for fileName & logtype checks */
|
|
/* 11/22/04 JRB 34 Add & use slog_max_msg_size_set funct. */
|
|
/* Ignore sl_max_msg_size if chged after first log.*/
|
|
/* Del static slog_buf, use new lc->msg_buf. */
|
|
/* slogDelBuf: add (LOG_CTRL *) arg. */
|
|
/* 08/04/04 EJV 33 Del slogTime, slogMs global variables. */
|
|
/* 07/09/04 EJV 32 All systems: one time/date format in slog hdr*/
|
|
/* 06/24/04 DSF 31 For Windows, log milliseconds */
|
|
/* 05/18/04 MDE 30 Removed LOG_IPC_SUPPORT #ifdef's */
|
|
/* 05/13/04 EJV 29 Added slogSetHdr, slogHdr. */
|
|
/* 03/11/04 GLB 28 Remove "thisFileName" */
|
|
/* 02/10/04 KCR 27 Added slogDelBuf() */
|
|
/* 01/12/04 EJV 26 Moved sock_debug_sel from gensock2.c */
|
|
/* 10/24/03 JRB 25 Move gs_debug_sel from glbsem.c to here. */
|
|
/* Move clnp_debug_sel to here. */
|
|
/* 10/13/03 EJV 24 Del MSOS2 (old), _WINDOWS. */
|
|
/* 05/07/03 DSF 23 Added support for sErrLogCtrl */
|
|
/* 03/28/02 EJV 22 vnsprintf: use it on Tru64 UNIX v5.0 and up */
|
|
/* 02/11/02 DSF 21 Call ExpRaiseDebugException () to log the */
|
|
/* call stack */
|
|
/* 10/18/01 JRB 20 Fix sprintf calls. */
|
|
/* 09/28/01 EJV 19 Added vnsprintf for systems that support it. */
|
|
/* 05/18/00 JRB 18 More Lint cleanup. */
|
|
/* 04/19/00 JRB 17 Lint cleanup. */
|
|
/* 09/24/99 JRB 16 added: #include "sysincs.h" */
|
|
/* 09/13/99 MDE 15 Added SD_CONST modifiers */
|
|
/* 07/15/99 RKR 14 16-bit version needs stdarg.h */
|
|
/* 04/14/99 MDE 13 Removed unnecessary include files */
|
|
/* 11/11/98 DSF 12 Minor changes to _slog_dyn_log_fun */
|
|
/* 10/08/98 MDE 11 Migrated to updated SLOG interface */
|
|
/* 08/25/98 IKE 10 Prevent buffer overrun by vsprintf for some */
|
|
/* platforms */
|
|
/* 08/13/98 MDE 09 Now log buffer overruns */
|
|
/* 06/15/98 MDE 08 Changes to allow compile under C++ */
|
|
/* 06/02/98 DSF 07 LOG_TIME_EN on by default */
|
|
/* 01/09/98 EJV 06 SUN Solaris 2.5 uses now ANSI vsprintf */
|
|
/* 11/05/97 DSF 05 Added SYSTIME_EN */
|
|
/* 10/06/97 DSF 04 Added thisFileName */
|
|
/* 09/12/97 DSF 03 Expose slogSetTimeText () */
|
|
/* 08/19/97 DSF 02 Initialize sLogCtrlDefault to default */
|
|
/* settings */
|
|
/* 05/27/97 DSF 01 Added IPC logging capability */
|
|
/* 04/02/97 DTL 7.00 MMSEASE 7.0 release. See MODL70.DOC for */
|
|
/* history. */
|
|
/************************************************************************/
|
|
|
|
#if defined(__OS2__)
|
|
#pragma data_seg(alldata)
|
|
#define INCL_BASE
|
|
#define INCL_DOS
|
|
#define INCL_DOSMISC
|
|
#define INCL_ERRORS
|
|
#define INCL_DOSPROCESS
|
|
#define INCL_DOSQUEUES
|
|
#define INCL_DOSSEMAPHORES
|
|
#define INCL_DOSMEMMGR
|
|
#define INCL_DOSFILEMGR
|
|
#define INCL_DOSDATETIME
|
|
#define INCL_DOSDEVICES
|
|
#include <os2.h>
|
|
#include <stddef.h>
|
|
#endif
|
|
|
|
#include "glbtypes.h"
|
|
#include "sysincs.h"
|
|
#include "glbsem.h"
|
|
#include "slog.h"
|
|
#include "stime.h"
|
|
#include "str_util.h"
|
|
#include "sx_defs.h"
|
|
|
|
#if defined (_WIN32)
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#define XML_NO_TAG 0
|
|
#define XML_DOCUMENT 1
|
|
#define XML_COMMENT 2
|
|
#define XML_START 3
|
|
#define XML_END 4
|
|
#define XML_EMPTY 5
|
|
|
|
ST_CHAR *_slogXMLLogTypeStr = "SLOGXML";
|
|
|
|
/************************************************************************/
|
|
/* Other prototypes. */
|
|
/************************************************************************/
|
|
|
|
static ST_VOID doSlog (LOG_CTRL *lc,
|
|
SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST logTypeStr,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_CHAR *SD_CONST format, va_list ap);
|
|
ST_VOID slogSetTimeText (LOG_CTRL *lc);
|
|
#if defined (_WIN32)
|
|
static ST_VOID _slogSetTimeTextElapsed (LOG_CTRL *lc);
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* Global variables used by the SLOG library. */
|
|
/************************************************************************/
|
|
|
|
|
|
LOG_CTRL *sErrLogCtrl = NULL;
|
|
|
|
LOG_CTRL sLogCtrlDefault = {LOG_TIME_EN,
|
|
{1000000, "mms.log",
|
|
FIL_CTRL_WIPE_EN |
|
|
FIL_CTRL_WRAP_EN |
|
|
FIL_CTRL_MSG_HDR_EN,
|
|
0, 0, NULL}};
|
|
|
|
LOG_CTRL *sLogCtrl = &sLogCtrlDefault;
|
|
ST_CHAR slogTimeText[TIME_BUF_LEN];
|
|
ST_INT sl_max_msg_size = MAX_LOG_SIZE;
|
|
ST_UINT32 slogRemoteFlags;
|
|
ST_BOOLEAN sNonStandardLogMode = SD_FALSE;
|
|
|
|
ST_VOID (*slog_service_fun) (ST_VOID);
|
|
|
|
ST_CHAR *_slogAlwaysLogTypeStr = "SLOGALWAYS";
|
|
|
|
/* dynamic logging function */
|
|
ST_VOID (*slog_dyn_log_fun) (LOG_CTRL *lc,
|
|
SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_INT bufLen,
|
|
SD_CONST ST_CHAR *buf);
|
|
ST_VOID (*_slog_dyn_log_fun) (LOG_CTRL *lc,
|
|
SD_CONST ST_CHAR *timeStr,
|
|
SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST logTypeStr,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_INT bufLen,
|
|
SD_CONST ST_CHAR *buf);
|
|
|
|
/* remote logging function */
|
|
/* Assign to this fun pointer a function which handles the logging to */
|
|
/* remote log file. For the slog_remote_flags parameter reference the */
|
|
/* description for slog_remote_fun function. */
|
|
|
|
ST_VOID (*slog_remote_fun) (ST_UINT32 slog_remote_flags,
|
|
LOG_CTRL *lc,
|
|
SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_INT bufLen,
|
|
SD_CONST ST_CHAR *buf);
|
|
|
|
ST_VOID (*_slog_remote_fun) (ST_UINT32 slog_remote_flags,
|
|
LOG_CTRL *lc,
|
|
SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST logTypeStr,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_INT bufLen,
|
|
SD_CONST ST_CHAR *buf);
|
|
|
|
/************************************************************************/
|
|
/* _slog */
|
|
/* Main general message logging function, typically called via macro */
|
|
/* Just print the message to be logged, pass to memory & file logging */
|
|
/* functions if enabled */
|
|
/************************************************************************/
|
|
|
|
ST_VOID _slogc (LOG_CTRL *lc, SD_CONST ST_CHAR *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start (ap, format);
|
|
doSlog (lc, SLOG_CONT, NULL, NULL, 0, format, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
ST_VOID _slog (LOG_CTRL *lc,
|
|
SD_CONST ST_CHAR *SD_CONST logTypeStr,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_CHAR *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start (ap, format);
|
|
doSlog (lc, SLOG_NORMAL, logTypeStr, sourceFile, lineNum, format, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* slog */
|
|
/************************************************************************/
|
|
|
|
ST_VOID slog (LOG_CTRL *lc,
|
|
SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_CHAR *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start (ap, format);
|
|
doSlog (lc, logType, NULL, sourceFile, lineNum, format, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* slogx */
|
|
/* Extended message logging function. */
|
|
/* Same as slog, except one more argument to determine if this type of */
|
|
/* logging is enabled. This function allows one macro to be used */
|
|
/* for any number of arguments. */
|
|
/* This function is designed so that the first 5 arguments are passed */
|
|
/* to this function via macro. For example: */
|
|
/* #define SLOG_ACSE_IND s_debug_sel & ACSE_IND_PRINT, s_sLogCtrl,\ */
|
|
/* ACSE_IND_PRINT_TYPE,THISFILE,__LINE__ */
|
|
/* slogx (SLOG_ACSE_IND, "Indication PDU ptr=" S_FMT_PTR ", len=%d", ptr, len); */
|
|
/************************************************************************/
|
|
|
|
ST_VOID slogx (ST_UINT32 doit, LOG_CTRL *lc,
|
|
SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_CHAR *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
/* Make sure "doit" flag is set. */
|
|
if (!doit)
|
|
return;
|
|
|
|
va_start (ap, format);
|
|
doSlog (lc, logType, NULL, sourceFile, lineNum, format, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* doSlog */
|
|
/* Main logging function, called from slog or slogx. */
|
|
/* Just print the message to be logged, pass to memory & file logging */
|
|
/* functions if enabled */
|
|
/************************************************************************/
|
|
|
|
#define SLOG_MISSED_LOG_MSG "Warning: SLOG Log messages missed"
|
|
|
|
static ST_VOID doSlog (LOG_CTRL *lc,
|
|
SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST logTypeStr,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
SD_CONST ST_CHAR *SD_CONST format, va_list ap)
|
|
{
|
|
ST_INT count;
|
|
ST_CHAR tmpBuf[128];
|
|
static ST_INT logMissed = 0;
|
|
static ST_CHAR *missedSourceFile;
|
|
static ST_INT missedLineNum;
|
|
|
|
S_GS_INIT ();
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
|
|
/* Make sure the LOG_CTRL pointer is not NULL */
|
|
if (!lc)
|
|
{
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return;
|
|
}
|
|
|
|
/* Check to see if any logging is enabled AND dynamic user logging */
|
|
/* function pointer not set */
|
|
|
|
if (!(lc->logCtrl & (LOG_FILE_EN | LOG_MEM_EN | LOG_IPC_EN)) &&
|
|
!slog_dyn_log_fun && !_slog_dyn_log_fun &&
|
|
!slog_remote_fun && !_slog_remote_fun)
|
|
{
|
|
if (logMissed == 0)
|
|
{
|
|
logMissed = 1;
|
|
missedSourceFile = sourceFile;
|
|
missedLineNum = lineNum;
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return;
|
|
}
|
|
|
|
/* Allocate a slog_buffer the first time this function is called. This */
|
|
/* allows us to make the size of the slog message buffer larger than */
|
|
/* the default. */
|
|
|
|
if (lc->msg_buf == NULL)
|
|
{
|
|
/* NOTE: this code only for backward compatibility with apps that */
|
|
/* control buffer size by setting the global var "sl_max_msg_size". */
|
|
/* New apps should call "slog_max_msg_size_set" directly. */
|
|
/* Use value of sl_max_msg_size NOW. Don't care if user changes it later.*/
|
|
if (slog_max_msg_size_set (lc, sl_max_msg_size) != SD_SUCCESS)
|
|
{
|
|
fprintf(stderr, "\nslog: error setting max msg size");
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* It is OK to pass in a NULL format string when using the dynamic */
|
|
/* logging functions - no vsprintf if so */
|
|
|
|
if (format == NULL)
|
|
{
|
|
/* make buf a zero length string just in case */
|
|
count = 0;
|
|
lc->msg_buf[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
#if defined(_WIN32)
|
|
count = _vsnprintf(lc->msg_buf,lc->max_msg_size,format,ap);
|
|
#elif defined(__QNX__) && defined(__WATCOMC__)
|
|
count = _vbprintf(lc->msg_buf,lc->max_msg_size,format,ap);
|
|
#elif defined(_AIX) || defined(sun) || defined(_hpux) || defined(__alpha) || defined(linux)
|
|
count = vsnprintf(lc->msg_buf,lc->max_msg_size,format,ap);
|
|
#else /* other systems: VXWORKS, ... */
|
|
count = vsprintf (lc->msg_buf, format, ap);
|
|
#endif
|
|
lc->msg_buf[lc->max_msg_size-1] = 0; /* terminate the buffer, Win and UNIX */
|
|
/* functions don't behave the same */
|
|
/* NOTE: On _WIN32 count could be negative because of error or too small buffer. */
|
|
/* On other systems count is negative because of error, too small buffer is */
|
|
/* indicated by return of count larger than buf_size supplied to the function.*/
|
|
#if defined(_WIN32)
|
|
if (count < 0)
|
|
{
|
|
sprintf (tmpBuf,"*** LOG ERROR: LOG BUFFER OVERRUN (lc->max_msg_size=%d bytes) or _vsnprintf function error",
|
|
lc->max_msg_size);
|
|
strncpy_safe (lc->msg_buf, tmpBuf, lc->max_msg_size-1);
|
|
count = strlen (lc->msg_buf); /* count = len of this log message */
|
|
}
|
|
#else /* !defined(_WIN32) */
|
|
if (count < 0)
|
|
{
|
|
sprintf (tmpBuf,"*** LOG ERROR: _vbprintf(QNX), vsnprintf(UNIX,LINUX), or vsprintf(other sys) function failed");
|
|
strncpy_safe (lc->msg_buf, tmpBuf, lc->max_msg_size-1);
|
|
count = strlen (lc->msg_buf); /* count = len of this log message */
|
|
}
|
|
else if (count >= lc->max_msg_size)
|
|
{
|
|
sprintf (tmpBuf,"*** LOG ERROR: LOG BUFFER OVERRUN: message len=%d bytes (lc->max_msg_size=%d bytes)",
|
|
count, lc->max_msg_size);
|
|
strncpy_safe (lc->msg_buf, tmpBuf, lc->max_msg_size-1);
|
|
count = strlen (lc->msg_buf); /* set count to len of this log message */
|
|
}
|
|
#endif /* !defined(_WIN32) */
|
|
|
|
count++; /* allow for null terminator */
|
|
}
|
|
|
|
/* If time stamping is desired, get the time string from the user */
|
|
if (lc->logCtrl & LOG_TIME_EN)
|
|
slogSetTimeText (lc);
|
|
else
|
|
slogTimeText[0] = 0; /* Init to empty time/date string. */
|
|
|
|
/* Check for type for special logging ('continuation' or dynamic */
|
|
/* logging format commands) - */
|
|
/* All standard log types are >= 0 */
|
|
/* Continuation logging is SLOG_CONT (-1) */
|
|
/* Dynamic logging format commands are other negative numbers, */
|
|
/* reserved are - */
|
|
/* SLOG_DYN_PAUSE = -10 */
|
|
/* SLOG_DYN_LF = -11 */
|
|
/* SLOG_DYN_CLRSCR = -12 */
|
|
|
|
if (logType >=0 || logType == SLOG_CONT)
|
|
{
|
|
if (lc->logCtrl & LOG_FILE_EN) /* File Logging enabled */
|
|
{
|
|
if (logMissed == 1)
|
|
{
|
|
logMissed = 2; /* to prevent logging this msg again */
|
|
/* when slogIpc turns off all masks */
|
|
slogFile (lc, 0, "INTERNAL_SLOG", missedSourceFile, missedLineNum, strlen (SLOG_MISSED_LOG_MSG), SLOG_MISSED_LOG_MSG);
|
|
}
|
|
slogFile (lc, logType, logTypeStr, sourceFile, lineNum, count, lc->msg_buf);
|
|
}
|
|
if (lc->logCtrl & LOG_MEM_EN) /* File Logging enabled */
|
|
slogMem (lc, logType, logTypeStr, sourceFile, lineNum, count, lc->msg_buf);
|
|
}
|
|
if ((lc->logCtrl & LOG_IPC_LISTEN_EN) || (lc->logCtrl & LOG_IPC_CALL_EN))
|
|
/* IPC Logging enabled (listen, calling, or both modes) */
|
|
slogIpc (lc, logType, logTypeStr, sourceFile, lineNum, count, lc->msg_buf);
|
|
|
|
/* If the user has set up a dynamic log display function, call it */
|
|
if (slog_dyn_log_fun)
|
|
(*slog_dyn_log_fun)(lc, logType, sourceFile, lineNum, count, lc->msg_buf);
|
|
if (_slog_dyn_log_fun)
|
|
(*_slog_dyn_log_fun)(lc, slogTimeText, logType, logTypeStr, sourceFile,
|
|
lineNum, count, lc->msg_buf);
|
|
|
|
/* If the user has set up a remote logging function, call it */
|
|
if (slog_remote_fun)
|
|
{
|
|
(*slog_remote_fun)(slogRemoteFlags, lc, logType, sourceFile, lineNum,
|
|
count, lc->msg_buf);
|
|
}
|
|
if (_slog_remote_fun)
|
|
{
|
|
(*_slog_remote_fun)(slogRemoteFlags, lc, logType, logTypeStr,
|
|
sourceFile, lineNum, count, lc->msg_buf);
|
|
}
|
|
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* slogSetTimeText */
|
|
/* Set the time string per the lc control information */
|
|
/************************************************************************/
|
|
ST_VOID slogSetTimeText (LOG_CTRL *lc)
|
|
{
|
|
slogTimeText[0] = 0; /* Init to empty. */
|
|
|
|
if (lc->logCtrl & LOG_TIME_EN)
|
|
{
|
|
#if defined (_WIN32)
|
|
SYSTEMTIME systime;
|
|
|
|
if ((lc->logCtrl & LOG_ELAPSEDTIME_EN) == 0)
|
|
{
|
|
GetLocalTime (&systime);
|
|
sprintf (slogTimeText, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
|
|
systime.wYear, systime.wMonth, systime.wDay,
|
|
systime.wHour, systime.wMinute, systime.wSecond, systime.wMilliseconds);
|
|
}
|
|
else
|
|
_slogSetTimeTextElapsed (lc);
|
|
|
|
#elif defined (VXWORKS)
|
|
/* Does not support gettimeofday. */
|
|
time_t curTime;
|
|
struct tm *locTime;
|
|
|
|
curTime = time (NULL);
|
|
locTime = localtime (&curTime);
|
|
sprintf (slogTimeText, "%04d-%02d-%02d %02d:%02d:%02d",
|
|
locTime->tm_year+1900, locTime->tm_mon+1, locTime->tm_mday,
|
|
locTime->tm_hour, locTime->tm_min, locTime->tm_sec);
|
|
#else
|
|
/* UNIX, Linux, QNX,... */
|
|
struct timeval tp;
|
|
time_t curTime;
|
|
struct tm *locTime;
|
|
|
|
gettimeofday (&tp, NULL);
|
|
curTime = (time_t) tp.tv_sec;
|
|
locTime = localtime (&curTime);
|
|
sprintf (slogTimeText, "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
|
|
locTime->tm_year+1900, locTime->tm_mon+1, locTime->tm_mday,
|
|
locTime->tm_hour, locTime->tm_min, locTime->tm_sec, tp.tv_usec/1000);
|
|
#endif /* UNIX, Linux, QNX,... */
|
|
}
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
#if defined (_WIN32)
|
|
static ST_VOID _slogSetTimeTextElapsed (LOG_CTRL *lc)
|
|
{
|
|
static ST_BOOLEAN firstTime = SD_TRUE;
|
|
static LARGE_INTEGER ticksPerSec;
|
|
static LARGE_INTEGER startTicks;
|
|
static double dTicksPerSec;
|
|
LARGE_INTEGER ticks;
|
|
double dDeltaTicks;
|
|
double dSec;
|
|
|
|
if (firstTime == SD_TRUE)
|
|
{
|
|
/* See if supported, and if so how many ticks per second */
|
|
if (QueryPerformanceFrequency(&ticksPerSec))
|
|
{
|
|
/* Mark the start of time for us */
|
|
QueryPerformanceCounter (&startTicks);
|
|
|
|
/* We want to work with double precision floating point */
|
|
dTicksPerSec = (double) ticksPerSec.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
strncpy_safe (slogTimeText, "Elapsed Time Not Available", sizeof (slogTimeText) - 1);
|
|
return;
|
|
}
|
|
firstTime = SD_FALSE;
|
|
}
|
|
|
|
|
|
/* Get the current tick count */
|
|
QueryPerformanceCounter (&ticks);
|
|
|
|
/* Get delta from start of logging */
|
|
dDeltaTicks = (double) (ticks.QuadPart - startTicks.QuadPart);
|
|
|
|
/* Calculate the elapsed time */
|
|
dSec = dDeltaTicks/dTicksPerSec;
|
|
|
|
sprintf (slogTimeText, "%.6f", dSec);
|
|
}
|
|
#endif /* defined (_WIN32) */
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* slogTrimFileName */
|
|
/************************************************************************/
|
|
|
|
ST_VOID slogTrimFileName (ST_CHAR *dest, SD_CONST ST_CHAR *fullName)
|
|
{
|
|
ST_INT i,s;
|
|
ST_CHAR c;
|
|
|
|
s = 0;
|
|
i = 0;
|
|
while ((c = fullName[i]))
|
|
{
|
|
if (c == '\\' || c == '/' || c == ':' || c == ']' )
|
|
s = i+1; /* remember the last path seperator character position */
|
|
i++;
|
|
}
|
|
strncpy (dest,&fullName[s], SLOG_MAX_FNAME);
|
|
dest[SLOG_MAX_FNAME] = 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* slogSetHdr */
|
|
/* Set the header string per the lc control information. */
|
|
/* The slogHdr needs to be SLOG_MAX_HDR+1 bytes long (in worst case). */
|
|
/************************************************************************/
|
|
|
|
ST_VOID slogSetHdr (LOG_CTRL *lc, SD_CONST ST_INT logType,
|
|
SD_CONST ST_CHAR *SD_CONST logTypeStr,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
ST_CHAR *slogHdr, ST_CHAR *lineBreak)
|
|
{
|
|
ST_CHAR fname[SLOG_MAX_FNAME+1];
|
|
ST_CHAR tmp[SLOG_MAX_FNAME+14+1]; /* 14 for line nubmer & () */
|
|
|
|
sprintf (slogHdr, lineBreak);
|
|
|
|
if ((lc->fc.ctrl & FIL_CTRL_MSG_HDR_EN) && (logType != SLOG_CONT))
|
|
{
|
|
if (!(lc->logCtrl & LOG_NO_HEADER_CR))
|
|
strcat (slogHdr, lineBreak);
|
|
|
|
if (lc->logCtrl & LOG_TIME_EN) /* user wants time stamp */
|
|
{
|
|
strcat (slogHdr, slogTimeText);
|
|
strcat (slogHdr, " ");
|
|
}
|
|
|
|
if (!(lc->logCtrl & LOG_LOGTYPE_SUPPRESS))
|
|
{
|
|
if (logTypeStr != NULL && logTypeStr[0] != 0)
|
|
{
|
|
strncat (slogHdr, logTypeStr, min (strlen(logTypeStr), SLOG_MAX_LOGTYPESTR));
|
|
strcat (slogHdr, " ");
|
|
}
|
|
else
|
|
{
|
|
sprintf (tmp, "LogType:% 2d ", logType);
|
|
strcat (slogHdr, tmp);
|
|
}
|
|
}
|
|
|
|
if ((sourceFile != NULL && sourceFile[0] != 0) && !(lc->logCtrl & LOG_FILENAME_SUPPRESS))
|
|
{
|
|
slogTrimFileName (fname, sourceFile);
|
|
sprintf (tmp, "(%s %d) ", fname, lineNum);
|
|
strcat (slogHdr, tmp);
|
|
}
|
|
if (!(lc->logCtrl & LOG_NO_HEADER_CR))
|
|
{
|
|
strcat (slogHdr, lineBreak);
|
|
strcat (slogHdr," ");
|
|
}
|
|
}
|
|
if (logType == SLOG_CONT)
|
|
strcat (slogHdr," ");
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* dumpCallingStack */
|
|
/************************************************************************/
|
|
|
|
#if defined(MSDOS) && !defined(_WINDOWS)
|
|
ST_VOID main (ST_VOID);
|
|
#endif
|
|
|
|
ST_VOID slogCallStack (LOG_CTRL *lc, SD_CONST ST_CHAR *txt)
|
|
{
|
|
#if !defined(CODAN)
|
|
#if defined(MSDOS) && !defined(TC)
|
|
static ST_UINT32 ptr_to_abs (ST_VOID *ptr);
|
|
ST_UINT16 os,sg;
|
|
ST_UINT16 os2,sg2;
|
|
ST_UINT16 os3,sg3;
|
|
ST_UINT16 os4,sg4;
|
|
ST_UINT16 os5,sg5;
|
|
#endif
|
|
|
|
/* For DOS we can save the caller's return address */
|
|
#if defined(MSDOS) && !defined(TC)
|
|
_asm {
|
|
push si ; save SI
|
|
|
|
mov si, bp ; first BP frame
|
|
mov ax, ss:[si+2] ; get return address "offset" from stack
|
|
mov os, ax ; store in "offset" variable
|
|
mov ax, ss:[si+4] ; get return address "segment" from stack
|
|
mov sg, ax ; store in "segment" variable
|
|
|
|
mov si, ss:[si] ; second BP frame
|
|
mov ax, ss:[si+2] ; get return address "offset" from stack
|
|
mov os2, ax ; store in "offset" variable
|
|
mov ax, ss:[si+4] ; get return address "segment" from stack
|
|
mov sg2, ax ; store in "segment" variable
|
|
|
|
mov si, ss:[si] ; third BP frame
|
|
mov ax, ss:[si+2] ; get return address "offset" from stack
|
|
mov os3, ax ; store in "offset" variable
|
|
mov ax, ss:[si+4] ; get return address "segment" from stack
|
|
mov sg3, ax ; store in "segment" variable
|
|
|
|
mov si, ss:[si] ; fourth BP frame
|
|
mov ax, ss:[si+2] ; get return address "offset" from stack
|
|
mov os4, ax ; store in "offset" variable
|
|
mov ax, ss:[si+4] ; get return address "segment" from stack
|
|
mov sg4, ax ; store in "segment" variable
|
|
|
|
mov si, ss:[si] ; fifth BP frame
|
|
mov ax, ss:[si+2] ; get return address "offset" from stack
|
|
mov os5, ax ; store in "offset" variable
|
|
mov ax, ss:[si+4] ; get return address "segment" from stack
|
|
mov sg5, ax ; store in "segment" variable
|
|
|
|
pop si ; restore SI
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
if (txt != NULL)
|
|
slog(lc, 0, NULL, 0, "%s", txt);
|
|
|
|
#if defined(MSDOS) && !defined(TC)
|
|
slog(lc,SLOG_CONT,NULL,0,"Calling Address (1st frame): 0x%04X:%04X (0x%lX)",
|
|
sg,os,((ST_UINT32)sg << 4) + (ST_UINT32)os);
|
|
slog(lc,SLOG_CONT,NULL,0,"Calling Address (2nd frame): 0x%04X:%04X (0x%lX)",
|
|
sg2,os2,((ST_UINT32)sg2 << 4) + (ST_UINT32)os2);
|
|
slog(lc,SLOG_CONT,NULL,0,"Calling Address (3rd frame): 0x%04X:%04X (0x%lX)",
|
|
sg3,os3,((ST_UINT32)sg3 << 4) + (ST_UINT32)os3);
|
|
slog(lc,SLOG_CONT,NULL,0,"Calling Address (4th frame): 0x%04X:%04X (0x%lX)",
|
|
sg4,os4,((ST_UINT32)sg4 << 4) + (ST_UINT32)os4);
|
|
slog(lc,SLOG_CONT,NULL,0,"Calling Address (5th frame): 0x%04X:%04X (0x%lX)",
|
|
sg5,os5,((ST_UINT32)sg5 << 4) + (ST_UINT32)os5);
|
|
slog(lc,SLOG_CONT,NULL,0,"Main Address : %08lx (0x%lX)",
|
|
main,ptr_to_abs ((ST_VOID *)main));
|
|
|
|
#endif
|
|
|
|
#if !defined(CODAN)
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ptr_to_abs (ptr) */
|
|
/* Convert buffer address to long real address */
|
|
/************************************************************************/
|
|
|
|
#if defined(MSDOS) && !defined(TC)
|
|
static ST_UINT32 ptr_to_abs (ST_VOID *ptr)
|
|
{
|
|
ST_UINT32 temp1;
|
|
ST_UINT32 temp2;
|
|
|
|
temp1 = (ST_UINT32) ptr;
|
|
temp2 = temp1 >> 12; /* Microsoft/Xenix use seg/off */
|
|
temp1 &= 0xFFFF;
|
|
temp2 &= 0xFFFF0;
|
|
return (temp1 + temp2); /* find real address */
|
|
}
|
|
#endif
|
|
|
|
|
|
/************************************************************************/
|
|
/* slog */
|
|
/************************************************************************/
|
|
|
|
ST_VOID slogDelBuf (LOG_CTRL *lc)
|
|
{
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
if (lc->msg_buf)
|
|
free (lc->msg_buf);
|
|
lc->msg_buf = NULL;
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* slog_max_msg_size_set */
|
|
/* Set the maximum message size and allocate a buffer of this size. */
|
|
/* This function sets "max_msg_size" and "msg_buf" in LOG_CTRL. */
|
|
/************************************************************************/
|
|
ST_RET slog_max_msg_size_set (LOG_CTRL *lc, ST_INT max_msg_size)
|
|
{
|
|
ST_RET retcode = SD_SUCCESS;
|
|
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
lc->max_msg_size = max_msg_size; /* save size in LOG_CTRL */
|
|
|
|
if (lc->msg_buf != NULL)
|
|
free (lc->msg_buf); /* buf already allocated by previous call, so free it first*/
|
|
|
|
/* Alloc "lc->msg_buf". chk_malloc calls slog so use malloc here! */
|
|
/* This is the only place "lc->msg_buf" is allocated. */
|
|
lc->msg_buf = (ST_CHAR *) malloc (lc->max_msg_size + 1);
|
|
if (lc->msg_buf == NULL)
|
|
{ /* this should almost never happen */
|
|
lc->max_msg_size = 0; /* no buffer so can't log anything */
|
|
retcode = SD_FAILURE;
|
|
}
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return (retcode);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* slog_start */
|
|
/************************************************************************/
|
|
|
|
ST_RET slog_start (LOG_CTRL *lc, ST_INT max_msg_size)
|
|
{
|
|
ST_RET rc;
|
|
|
|
rc = slog_max_msg_size_set (lc, max_msg_size);
|
|
rc = slogIpcInit (lc);
|
|
return (rc);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* slog_end */
|
|
/************************************************************************/
|
|
|
|
ST_RET slog_end (LOG_CTRL *lc)
|
|
{
|
|
ST_CHAR idxFileName[S_MAX_PATH];
|
|
FILE *fh;
|
|
ST_RET rc;
|
|
|
|
slogIpcStop (lc);
|
|
rc = slog_get_index_file_name (lc, idxFileName, sizeof(idxFileName));
|
|
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
if (rc == SD_SUCCESS)
|
|
{
|
|
fh = fopen (idxFileName,"w+");
|
|
if (fh)
|
|
{
|
|
fprintf (fh,"%ld", lc->fc.wipeFilePos);
|
|
fclose (fh);
|
|
rc = SD_SUCCESS;
|
|
}
|
|
else
|
|
rc = SD_FAILURE;
|
|
}
|
|
|
|
/* No more file or IPC logging after end ... */
|
|
lc->logCtrl &= ~(LOG_FILE_EN | LOG_IPC_EN);
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* _slogXML */
|
|
/* Formats XML strings and logs them if file logging is enabled. */
|
|
/************************************************************************/
|
|
ST_VOID _slogXML (LOG_CTRL *lc,
|
|
SD_CONST ST_CHAR *SD_CONST logTypeStr,
|
|
SD_CONST ST_CHAR *SD_CONST sourceFile,
|
|
SD_CONST ST_INT lineNum,
|
|
ST_UINT numBytes,
|
|
SD_CONST ST_CHAR *textData)
|
|
{
|
|
ST_UINT filCtrlSave;
|
|
ST_UINT tabLevel = 0;
|
|
ST_UINT index, i, j;
|
|
ST_CHAR xmlBuffer[SX_MAX_ELEM_LEN+1];
|
|
ST_INT eleLength[SX_MAX_XML_NEST];
|
|
ST_INT prevTag;
|
|
ST_INT tag = XML_NO_TAG;
|
|
|
|
|
|
|
|
S_GS_INIT ();
|
|
S_LOCK_UTIL_RESOURCES ();
|
|
|
|
/* Make sure the LOG_CTRL and textData pointers are not NULL */
|
|
if ((!lc) || (!textData))
|
|
{
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return;
|
|
}
|
|
|
|
/* Check to see if any logging is enabled AND dynamic user logging */
|
|
/* function pointer not set */
|
|
if (!(lc->logCtrl & LOG_FILE_EN) &&
|
|
!slog_dyn_log_fun && !_slog_dyn_log_fun &&
|
|
!slog_remote_fun && !_slog_remote_fun)
|
|
{
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
return;
|
|
}
|
|
|
|
/* Remember the state of the wipe/wrap/header enable flags */
|
|
/* so that we can restore them later */
|
|
filCtrlSave = lc->fc.ctrl & (FIL_CTRL_WIPE_EN |
|
|
FIL_CTRL_WRAP_EN |
|
|
FIL_CTRL_MSG_HDR_EN);
|
|
|
|
if (!numBytes)
|
|
{
|
|
lc->fc.ctrl |= (filCtrlSave & FIL_CTRL_WIPE_EN);
|
|
}
|
|
|
|
if (lc->logCtrl & LOG_FILE_EN) /* File Logging enabled */
|
|
{
|
|
for (i=0; i<SX_MAX_XML_NEST; i++)
|
|
eleLength[i] = 0;
|
|
|
|
xmlBuffer[0] = '\0';
|
|
|
|
index=0;
|
|
|
|
/* process at most numBytes of data, or until end of textData string */
|
|
|
|
for (i=0; (i < numBytes) && (textData[i] != 0); i++)
|
|
{
|
|
if (tabLevel >= SX_MAX_XML_NEST) /* Log error if maximum nesting level is exceeded */
|
|
{
|
|
slogFile (lc, SLOG_NORMAL, logTypeStr, sourceFile, lineNum, 0, "XML nesting exceeds maximum level");
|
|
break;
|
|
}
|
|
|
|
if (eleLength[tabLevel] >= SX_MAX_ELEM_LEN) /* Log error if maximum element length is exceeded */
|
|
{
|
|
slogFile (lc, SLOG_NORMAL, logTypeStr, sourceFile, lineNum, 0, "XML element exceeds maximum length");
|
|
break;
|
|
}
|
|
|
|
eleLength[tabLevel]++;
|
|
|
|
/* Skip control characters */
|
|
/* cast the chars as ST_UCHAR so data > 0x7F will not look negative */
|
|
|
|
if (iscntrl((ST_UCHAR) textData[i]) || (textData[i] == ' ' && index == 0))
|
|
{
|
|
index = 0;
|
|
continue;
|
|
}
|
|
|
|
/* Determine tag value */
|
|
if (textData[i] == '/' && textData[i+1] == '>')
|
|
tag = XML_EMPTY;
|
|
|
|
if (textData[i] == '<')
|
|
{
|
|
prevTag = tag;
|
|
|
|
if (textData[i] == '<' && textData[i+1] == '?')
|
|
tag = XML_DOCUMENT;
|
|
else if (textData[i] == '<' && textData[i+1] == '!')
|
|
tag = XML_COMMENT;
|
|
else if (textData[i] == '<' && textData[i+1] == '/')
|
|
tag = XML_END;
|
|
else if(textData[i] == '<')
|
|
tag = XML_START;
|
|
|
|
/* Increment/decrement tabLevel */
|
|
if (prevTag == XML_START && (tag == XML_START || tag == XML_COMMENT))
|
|
tabLevel++;
|
|
else if (tag == XML_END && (prevTag == XML_END || prevTag == XML_EMPTY))
|
|
tabLevel--;
|
|
|
|
/* Format tab level */
|
|
if (index == 0)
|
|
{
|
|
xmlBuffer[0] = '\0';
|
|
|
|
if (tabLevel)
|
|
{
|
|
for (j=0; j<tabLevel; j++, index+=2)
|
|
strcat (xmlBuffer, " ");
|
|
}
|
|
}
|
|
}
|
|
|
|
xmlBuffer[index++] = textData[i];
|
|
xmlBuffer[index] = '\0';
|
|
|
|
/* Log XML buffer */
|
|
if (textData[i] == '>' && (
|
|
textData[i+1] == '<' ||
|
|
textData[i+1] == ' ' ||
|
|
iscntrl ((ST_UCHAR) textData[i+1]) ||
|
|
i == numBytes-1 ||
|
|
tag != XML_START))
|
|
{
|
|
slogFile (lc, SLOG_CONT, logTypeStr, sourceFile, lineNum, strlen(xmlBuffer), xmlBuffer);
|
|
index = 0;
|
|
|
|
/* If the user has set up a dynamic log display function, call it */
|
|
if (slog_dyn_log_fun)
|
|
{
|
|
(*slog_dyn_log_fun)(lc, SLOG_CONT, NULL, 0, strlen(xmlBuffer), xmlBuffer);
|
|
}
|
|
if (_slog_dyn_log_fun)
|
|
{
|
|
(*_slog_dyn_log_fun)(lc, slogTimeText, SLOG_CONT, NULL, NULL, 0, strlen(xmlBuffer), xmlBuffer);
|
|
}
|
|
|
|
/* If the user has set up a remote logging function, call it */
|
|
if (slog_remote_fun)
|
|
{
|
|
(*slog_remote_fun)(slogRemoteFlags, lc, SLOG_CONT, NULL, 0, strlen(xmlBuffer), xmlBuffer);
|
|
}
|
|
if (_slog_remote_fun)
|
|
{
|
|
(*_slog_remote_fun)(slogRemoteFlags, lc, SLOG_CONT, NULL, NULL, 0, strlen(xmlBuffer), xmlBuffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* All done, restore the flag state bits */
|
|
lc->fc.ctrl |= filCtrlSave;
|
|
|
|
S_UNLOCK_UTIL_RESOURCES ();
|
|
}
|
|
|
|
|