/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/*   (c) Copyright Systems Integration Specialists Company, Inc.,       */
/*	           1994 - 2008 All Rights Reserved			*/
/*									*/
/* MODULE NAME : SX_AXS4D.C  						*/
/* PRODUCT(S)  : 							*/
/*									*/
/* MODULE DESCRIPTION :                                                 */
/*	Functions to convert local data to text and vice versa.		*/
/*									*/
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE :                            */
/*			sxaLocalToText					*/
/*			sxaTextToLocal					*/
/*                                                                      */
/* MODIFICATION LOG :                                                   */
/*  Date    Who  Rev    Comments                                    	*/
/* -------- --- ------  ----------------------------------------------- */
/* 01/30/08 EJV    21   sprintf,sscanf: use S_FMT_* macros for ST_INT64	*/
/* 10/24/06 JRB    20   sxaTextToLocal: do not alloc and copy text	*/
/*			 buffer (caused memory leak).			*/
/*			sxaLocalToText: do not alloc text buf (caused	*/
/*			 memory leak). Go back to using global buffer.	*/
/*			Add thread-safe sxaLocalToText2.		*/
/*			Del unused sxaTextToLoc.			*/
/*			sxaAddString: DO NOT write past end of buffer.	*/
/*			sxaCheckOctetString: handle empty input string.	*/
/* 10/17/06 MDE    19    Added support for unsigned hex ints (32 bit)	*/
/* 04/04/06 CRM    18   Added SXD_CONTEXT to eliminate global variables */
/* 01/30/06 GLB    17   Integrated porting changes for VMS              */
/* 09/01/04 EJV    16   Added new include "sx_arb.h"			*/
/* 03/16/04 EJV    15   Added ST_(U)LONG typecast to sprintf,on some sys*/
/*			     ST_(U)INT32 can be (unsigned) long or int.	*/
/*			Use SISCO types in place of C types.		*/
/* 01/23/04 JRB    14   Add LYNX support.				*/
/* 01/08/04 EJV    13   Ported 64-bit funcs to sun.			*/
/* 10/17/03 JRB    12   Add SD_CONST.					*/
/* 10/13/03 EJV    11   Replaced defined(QNX) with defined(__QNX__).	*/
/* 07/09/03 JRB    10   Add module description.				*/
/* 06/11/03 EJV    09   __alpha: eliminated warning in sxaTextToLocInt16*/
/* 04/14/03 JRB    08   Add linux support. Use #error.			*/
/* 08/16/02 EJV    07   Ported 64-bit funcs to UNIX.			*/
/* 07/07/02 GLB    06   Remove unreferenced sxaLocToTextUtc             */
/*                      Remove unreferenced sxaTextToLocUtc             */
/* 04/24/02 EJV    05   Replaced ltoa with sprintf for !(_WIN32 || QNX).*/
/*			Replaced gcvt with sprintf for !(_WIN32	|| QNX).*/
/*			Added DEBUG_SISCO, SD_CONST for thisFileName.	*/
/*			sxaCheckOctetString: initialized nibble.	*/
/*			Added empty sxaLocToTextUtc and sxaTextToLocUtc	*/
/*			Corrected 2-nd param name (static fun protos)	*/
/* 04/18/02 EJV    04   Added NULL to sxaTextToLocTbl for UTC Time fun.	*/
/* 06/08/01 EJV    03   Changed 2nd param to time_t in sxaLocToTextGtime*/
/*			sxaTextToLocGtime.				*/
/* 05/21/01 MDE    02   Fixups for QNX					*/
/* 03/23/01 MDE    01   New, derived from axs4data.c			*/
/************************************************************************/

#include "glbtypes.h"
#include "sysincs.h"
#include "time.h" 
#include "time_str.h"
#include "sx_defs.h"
#include "sx_arb.h"
#include "sx_log.h"
#include "mem_chk.h"

/************************************************************************/
/* Define for SLOG debugging mechanism                                  */
/************************************************************************/
/************************************************************************/
/* Use a static pointer to avoid duplication of __FILE__ strings.	*/

#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif

/************************************************************************/
#define MAX_DDE_DATA_SIZE  30000
#define TEMP_DATA_BUF_SIZE 20000
/*#define DATA_SEPARATOR	   0x7c	 a pipe '|'	*/
#define DATA_SEPARATOR1	   0x0d		/* carraige return */
#define DATA_SEPARATOR2	   0x0a		/* line feed 	*/
/************************************************************************/

typedef struct 
  {
  ST_INT  nStrLen;       /* Current string array total length 	*/
  ST_INT  nDataIdx;      /* Current index in work buffer		*/
  ST_CHAR *sTmpData;     /* Temporary work buffer			*/
  ST_INT  nStringCount;  /* count strings added to buffer		*/
  ST_BOOLEAN textDataErrorDetected;
  ST_CHAR *sxaTextWorkBuf;
  ST_UINT workBufLen;	/* length of work buffer	*/
  } SXD_CONTEXT;

/************************************************************************/
/* Global variables							*/
/************************************************************************/
static ST_CHAR gTextBuf [MAX_DDE_DATA_SIZE];	/* sxaLocalToText encodes here*/

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

static ST_VOID sxaAddString (ST_VOID *usr, ST_CHAR *str);
static ST_INT sxaGetNextString (ST_VOID *usr);
static ST_VOID leftTrim (ST_CHAR *pString);

static ST_INT sxaCheckIntString (ST_CHAR*);
static ST_INT sxaCheckUintString (ST_CHAR*);
static ST_INT sxaCheckFloatString (ST_CHAR*);
static ST_VOID SkipWhiteSpace (ST_CHAR**);
static ST_INT sxaCheckOctetString (ST_CHAR*, ST_CHAR*, ST_INT*);
static ST_INT sxaCheckBitString (ST_CHAR*, ST_CHAR*, ST_INT*);


/************************************************************************/
/************************************************************************/
/* LOCAL TO TEXT DATA CONVERSION					*/
/************************************************************************/
/************************************************************************/
/* This table is used as input to the MMS-EASE arbitrary data handling	*/
/* function.  All functions return SUCCESS or FAILURE			*/

static ST_RET sxaLocToTextBool (ST_VOID *usr, ST_BOOLEAN *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextInt8 (ST_VOID *usr, ST_INT8 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextInt16 (ST_VOID *usr, ST_INT16 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextInt32 (ST_VOID *usr, ST_INT32 *pSrc, RUNTIME_TYPE *rt);
#if defined(INT64_SUPPORT)
static ST_RET sxaLocToTextInt64 (ST_VOID *usr, ST_INT64 *pSrc, RUNTIME_TYPE *rt);
#endif
static ST_RET sxaLocToTextUint8 (ST_VOID *usr, ST_UINT8 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextUint16 (ST_VOID *usr, ST_UINT16 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextUint32 (ST_VOID *usr, ST_UINT32 *pSrc, RUNTIME_TYPE *rt);
#if defined(INT64_SUPPORT)
static ST_RET sxaLocToTextUint64 (ST_VOID *usr, ST_UINT64 *pSrc, RUNTIME_TYPE *rt);
#endif
static ST_RET sxaLocToTextBcd1 (ST_VOID *usr, ST_INT8 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextBcd2 (ST_VOID *usr, ST_INT16 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextBcd4 (ST_VOID *usr, ST_INT32 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextFlt (ST_VOID *usr, ST_FLOAT *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextDbl (ST_VOID *usr, ST_DOUBLE *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextStr (ST_VOID *usr, ST_CHAR *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextOct (ST_VOID *usr, ST_UCHAR *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextBs  (ST_VOID *usr, ST_UCHAR *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextBtime4 (ST_VOID *usr, ST_INT32 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextBtime6 (ST_VOID *usr, ST_INT32 *pSrc, RUNTIME_TYPE *rt);
static ST_RET sxaLocToTextGtime (ST_VOID *usr, time_t *pSrc, RUNTIME_TYPE *rt);
#if 0
static ST_RET sxaLocToTextUtc   (ST_VOID *usr, MMS_UTC_TIME *pSrc, RUNTIME_TYPE *rt);
#endif
static SXD_ARB_DATA_CTRL sxaLocToTextTbl =
  {
  NULL,				/* arrStart 	*/
  NULL,				/* arrEnd    	*/
  NULL,				/* strStart  	*/
  NULL,				/* strEnd    	*/
  sxaLocToTextInt8,  		/* int8      	*/
  sxaLocToTextInt16,		/* int16     	*/
  sxaLocToTextInt32, 		/* int32     	*/
#if defined(INT64_SUPPORT)
  sxaLocToTextInt64,		/* int64	*/
#endif
  sxaLocToTextUint8, 		/* uint8     	*/
  sxaLocToTextUint16,		/* uint16    	*/
  sxaLocToTextUint32,		/* uint32    	*/
#if defined(INT64_SUPPORT)
  sxaLocToTextUint64,		/* uint64	*/
#endif
  sxaLocToTextFlt,   		/* flt       	*/
  sxaLocToTextDbl,   		/* dbl       	*/
  sxaLocToTextOct,		/* oct       	*/
  sxaLocToTextBool,		/* bool      	*/
  sxaLocToTextBcd1, 	    	/* bcd1      	*/
  sxaLocToTextBcd2, 	    	/* bcd2      	*/
  sxaLocToTextBcd4, 	    	/* bcd4      	*/
  sxaLocToTextBs,		/* bs	       	*/
  sxaLocToTextStr,		/* visible str	*/
  sxaLocToTextBtime4,		/* Bin Time    	*/
  sxaLocToTextBtime6,		/* Bin Time    	*/
  sxaLocToTextGtime,		/* Gen Time    	*/
  NULL 				/* UTC Time	*/
  };				

/************************************************************************/
/*			sxaLocalToText					*/
/* WARNING: this function is not thread-safe because it uses the global	*/
/*          buffer "gTextBuf". Better to call sxaLocalToText2 directly.	*/
/* NOTE: "ms_local_to_text" function produces better text for logging,	*/
/*       but this function produces text compatible with sxaTextToLocal.*/ 
/************************************************************************/
/* This is the main entry point for LOCAL->TEXT data conversion 	*/

ST_CHAR *sxaLocalToText (ST_VOID *dataPtr, SD_CONST RUNTIME_TYPE *rtHead, ST_INT numRt)
  {
  return (sxaLocalToText2 (dataPtr, rtHead, numRt,
	  gTextBuf,			/* Use global text buffer	*/
	  sizeof (gTextBuf)));		/* size of global text buffer 	*/
  }

/************************************************************************/
/*			sxaLocalToText2					*/
/* This function should be thread-safe as long as caller's "textBuf"	*/
/* is not accessed by other threads.					*/
/* NOTE: "ms_local_to_text" function produces better text for logging,	*/
/*       but this function produces text compatible with sxaTextToLocal.*/ 
/************************************************************************/
ST_CHAR *sxaLocalToText2 (ST_VOID *dataPtr, SD_CONST RUNTIME_TYPE *rtHead, ST_INT numRt,
	ST_CHAR *textBuf,	/* User buffer in which to write text	*/
	ST_UINT textBufSize)	/* size of user buffer			*/
  {
SXD_CONTEXT sxdContext;
ST_CHAR tempDataBuf[TEMP_DATA_BUF_SIZE];
ST_RET rtnVal;

/* Make a global temporary buffer available (easier than calloc..)	*/
  sxdContext.sTmpData = (ST_CHAR *) tempDataBuf;
  sxdContext.sxaTextWorkBuf = textBuf;	/* save user buffer pointer	*/
  sxdContext.workBufLen = textBufSize;	/* save user buffer size	*/

  sxdContext.nStrLen = 0;
  sxdContext.nDataIdx = 0;	     
  sxdContext.nStringCount = 0;

  sxdContext.textDataErrorDetected = SD_FALSE;

  rtnVal = sxd_process_arb_data ((ST_CHAR *) dataPtr, rtHead, numRt, &sxdContext, 
			         &sxaLocToTextTbl, NULL);

  if (rtnVal != SD_SUCCESS)
    {
    return (NULL);
    }

  if (sxdContext.textDataErrorDetected)
    {
    return (NULL);
    }

  /* Null terminate the string						*/
  sxdContext.sxaTextWorkBuf[sxdContext.nStrLen + 1] = 0;

  return (sxdContext.sxaTextWorkBuf);
  }

/************************************************************************/
/*			sxaLocToTextInt8 ()				*/
/************************************************************************/

static ST_RET sxaLocToTextInt8 (ST_VOID *usr, ST_INT8 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%d", (ST_INT) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return (SD_SUCCESS);
  }

/************************************************************************/
/*			sxaLocToTextInt16 ()				*/
/************************************************************************/

static ST_RET sxaLocToTextInt16 (ST_VOID *usr, ST_INT16 *pSrc, RUNTIME_TYPE *rt)		
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%d",(ST_INT) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return (SD_SUCCESS);
  }

/************************************************************************/
/*			sxaLocToTextInt32 ()				*/
/************************************************************************/

static ST_RET sxaLocToTextInt32 (ST_VOID *usr, ST_INT32 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%ld", (ST_LONG) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return (SD_SUCCESS);
  }

/************************************************************************/
/*			sxaLocToTextInt64 ()				*/
/************************************************************************/

#if defined(INT64_SUPPORT)
static ST_RET sxaLocToTextInt64 (ST_VOID *usr, ST_INT64 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData, S_FMT_INT64, *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }
#endif

/************************************************************************/
/*			sxaLocToTextUint8 ()				*/
/************************************************************************/

static ST_RET sxaLocToTextUint8 (ST_VOID *usr, ST_UINT8 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%u",(ST_UINT) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextUint16 ()				*/
/************************************************************************/

static ST_RET sxaLocToTextUint16 (ST_VOID *usr, ST_UINT16 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%u",(ST_UINT) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextUint32 ()				*/
/************************************************************************/

static ST_RET sxaLocToTextUint32 (ST_VOID *usr, ST_UINT32 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%lu", (ST_ULONG) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextUint64 ()				*/
/************************************************************************/

#if defined(INT64_SUPPORT)
static ST_RET sxaLocToTextUint64 (ST_VOID *usr, ST_UINT64 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData, S_FMT_UINT64, *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }
#endif

/************************************************************************/
/*			sxaLocToTextBcd1 ()			 	*/
/************************************************************************/

static ST_RET sxaLocToTextBcd1 (ST_VOID *usr, ST_INT8 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%d", (ST_INT) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextBcd2 ()				*/
/************************************************************************/

static ST_RET sxaLocToTextBcd2 (ST_VOID *usr, ST_INT16 *pSrc, RUNTIME_TYPE *rt)		
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%d",(ST_INT) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }	     

/************************************************************************/
/*			sxaLocToTextBcd4 ()				*/
/************************************************************************/

static ST_RET sxaLocToTextBcd4 (ST_VOID *usr, ST_INT32 *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%ld", (ST_LONG) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextBool ()		      		*/
/************************************************************************/

static ST_RET sxaLocToTextBool (ST_VOID *usr, ST_BOOLEAN *pSrc, RUNTIME_TYPE *rt)
  {     
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
  sprintf (sxdContext->sTmpData,"%u",(ST_UINT) *pSrc);
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextFlt ()				*/
/************************************************************************/

static ST_RET sxaLocToTextFlt (ST_VOID *usr, ST_FLOAT *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
#if defined(_WIN32) || defined(__QNX__)
  /* 7 significant digits */
  gcvt((ST_DOUBLE) *pSrc, 7, sxdContext->sTmpData);
#else
  sprintf (sxdContext->sTmpData, "%.7g", (ST_DOUBLE) (*pSrc));
#endif
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextDbl ()		     		*/
/************************************************************************/

static ST_RET sxaLocToTextDbl (ST_VOID *usr, ST_DOUBLE *pSrc, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;
#if defined(_WIN32) || defined(__QNX__)
  /* 16 significant digits */
  gcvt(*pSrc, 16, sxdContext->sTmpData);
#else
  sprintf (sxdContext->sTmpData, "%.16g", *pSrc);
#endif
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextStr ()		      		*/
/************************************************************************/

static ST_RET sxaLocToTextStr (ST_VOID *usr, ST_CHAR *pSrc, RUNTIME_TYPE *rt)
  {
  sxaAddString (usr, pSrc);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextOct				*/
/************************************************************************/

static ST_RET sxaLocToTextOct (ST_VOID *usr, ST_UCHAR *pSrc, RUNTIME_TYPE *rt)
  {
ST_INT i, k;
ST_INT numBytes;
ST_INT16 *sp;
ST_CHAR *destBuf;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

  sxdContext->sTmpData[0] = 0;
  numBytes = rt->u.p.el_len;

  if (numBytes < 0)		/* a variable length octet string	*/
    {
    sp = (ST_INT16 *) pSrc;
    numBytes = *sp;
    k=2;
    }
  else
    k=0;

  /* We take 3 bytes per octet, make sure it fits			*/
  if (numBytes > TEMP_DATA_BUF_SIZE/3)
    {
    SXLOG_NERR0 ("Octet String to encode too long");
    return SD_FAILURE;
    }

  destBuf = sxdContext->sTmpData;
  for (i = 0; i < numBytes; ++i, ++k)
    {
    sprintf (destBuf, "%02x ", (ST_UINT) pSrc[k]);
    destBuf += 3;
    }

  /* Eliminate the trailing space					*/
  *(destBuf - 1) = 0;
  sxaAddString (usr, sxdContext->sTmpData);
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaLocToTextBs					*/
/************************************************************************/

static ST_RET sxaLocToTextBs  (ST_VOID *usr, ST_UCHAR *pSrc, RUNTIME_TYPE *rt)
  {
ST_INT i;
ST_INT j;
ST_INT k;
ST_INT numBits;
ST_INT16 *sp;
ST_CHAR *destBuf;
ST_UCHAR mask;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

  sxdContext->sTmpData[0] = 0;
  numBits = rt->u.p.el_len;

/* We take 1 dest byte per bit, make sure it fits				*/
  if (numBits > TEMP_DATA_BUF_SIZE-1)
    {
    SXLOG_NERR0 ("Bit String to encode too long");
    return (SD_FAILURE);
    }

  if (numBits < 0)		/* a variable length bit string	*/
    {
    sp = (ST_INT16 *) pSrc;
    numBits = *sp;
    k=2;
    }
  else 
    k=0;

  destBuf = sxdContext->sTmpData;
  for (i = 0; i < numBits; ++k)	/* for each byte, while bits remain	*/
    {
    mask = 0x80;
    for (j = 0; j < 8 && i < numBits; ++i, ++j)
      {
      if (pSrc[k] & mask)
        destBuf[i] = '1';
      else
        destBuf[i] = '0';
      mask >>= 1;
      }
    }
  destBuf[i] = 0;
  sxaAddString (usr, sxdContext->sTmpData);
  return (SD_SUCCESS);
  }

/************************************************************************/
/*			sxaLocToTextBtime4				*/
/************************************************************************/

static ST_RET sxaLocToTextBtime4 (ST_VOID *usr, ST_INT32 *pSrc, RUNTIME_TYPE *rt)
  {
ST_CHAR timeString[MAX_TIME_STRING_LEN];
  
  if (Btime4ValsToString (timeString, *pSrc))
    {
    SXLOG_NERR0 ("Btime4 String conversion error.");
    return (SD_FAILURE);
    }

  sxaAddString (usr, timeString);
  return (SD_SUCCESS);
  }


/************************************************************************/
/*			sxaLocToTextBtime6				*/
/************************************************************************/

static ST_RET sxaLocToTextBtime6 (ST_VOID *usr, ST_INT32 *pSrc, RUNTIME_TYPE *rt)
  {
ST_INT32 *pDays, *pMsec;
ST_CHAR timeString[MAX_TIME_STRING_LEN];
  
  pMsec = pSrc;
  pDays = (pSrc+1);
  if (Btime6ValsToString (timeString, *pDays, *pMsec))
    {
    SXLOG_NERR0 ("Btime6 String conversion error.");
    return (SD_FAILURE);
    }

  sxaAddString (usr, timeString);
  return (SD_SUCCESS);
  }

/************************************************************************/
/*			sxaLocToTextGtime				*/
/************************************************************************/

static ST_RET sxaLocToTextGtime (ST_VOID *usr, time_t *pSrc, RUNTIME_TYPE *rt)
  {
ST_CHAR timeString[MAX_TIME_STRING_LEN];

  if (tstrTimeToString (*pSrc, timeString))
    {
    SXLOG_NERR0 ("Time to String conversion error");
    return (SD_FAILURE);
    }

  sxaAddString (usr, timeString);
  return (SD_SUCCESS);
  }
#if 0
/************************************************************************/
/*			sxaLocToTextUtc					*/
/************************************************************************/

static ST_RET sxaLocToTextUtc (ST_VOID *usr, MMS_UTC_TIME *pSrc, RUNTIME_TYPE *rt)
  {
    SXLOG_ERR0 ("sxaLocToTextUtc error: function not implemented");
    return (SD_FAILURE);
  }
#endif
/************************************************************************/
/*			sxaAddString					*/
/************************************************************************/
/* This function is used to add a string to the working string buffer	*/

static ST_VOID sxaAddString (ST_VOID *usr, ST_CHAR *str)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

  /* Watch out for overrun						*/
  if ((sxdContext->nStrLen + strlen (str) + 3) >= sxdContext->workBufLen)
    {
    SXLOG_NERR0 ("Local->Text buffer overrun");
    sxdContext->textDataErrorDetected = SD_TRUE;
    return;	/* STOP: DO NOT write any more data to buffer	*/
    }

  /* If not the first one, need to add seperators			*/
  if (sxdContext->nStringCount > 0)
    {
/*    sxaTextWorkBuf[nStrLen++] = DATA_SEPARATOR;			*/
    sxdContext->sxaTextWorkBuf[sxdContext->nStrLen++] = DATA_SEPARATOR1;
    sxdContext->sxaTextWorkBuf[sxdContext->nStrLen++] = DATA_SEPARATOR2;
    sxdContext->sxaTextWorkBuf[sxdContext->nStrLen] = 0x00;
    strcat (sxdContext->sxaTextWorkBuf,str);
    }
  else
    strcpy (sxdContext->sxaTextWorkBuf,str);

  sxdContext->nStringCount++;
  sxdContext->nStrLen += strlen (str);
  }

/************************************************************************/
/************************************************************************/
/* TEXT TO LOCAL DATA CONVERSION					*/
/************************************************************************/
/************************************************************************/
/* This table is used as input to the MMS-EASE arbitrary data handling	*/
/* function.  All functions return SUCCESS or FAILURE			*/

static ST_RET sxaTextToLocBool (ST_VOID *usr, ST_BOOLEAN *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocInt8 (ST_VOID *usr, ST_INT8 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocInt16 (ST_VOID *usr, ST_INT16 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocInt32 (ST_VOID *usr, ST_INT32 *pDest, RUNTIME_TYPE *rt);
#if defined(INT64_SUPPORT)
static ST_RET sxaTextToLocInt64 (ST_VOID *usr, ST_INT64 *pDest, RUNTIME_TYPE *rt);
#endif
static ST_RET sxaTextToLocUint8 (ST_VOID *usr, ST_UINT8 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocUint16 (ST_VOID *usr, ST_UINT16 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocUint32 (ST_VOID *usr, ST_UINT32 *pDest, RUNTIME_TYPE *rt);
#if defined(INT64_SUPPORT)
static ST_RET sxaTextToLocUint64 (ST_VOID *usr, ST_UINT64 *pDest, RUNTIME_TYPE *rt);
#endif
static ST_RET sxaTextToLocBcd1 (ST_VOID *usr, ST_INT8 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocBcd2 (ST_VOID *usr, ST_INT16 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocBcd4 (ST_VOID *usr, ST_INT32 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocFlt (ST_VOID *usr, ST_FLOAT *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocDbl (ST_VOID *usr, ST_DOUBLE *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocStr (ST_VOID *usr, ST_CHAR *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocOct (ST_VOID *usr, ST_UCHAR *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocBs  (ST_VOID *usr, ST_UCHAR *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocBtime4 (ST_VOID *usr, ST_INT32 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocBtime6 (ST_VOID *usr, ST_INT32 *pDest, RUNTIME_TYPE *rt);
static ST_RET sxaTextToLocGtime (ST_VOID *usr, time_t *pDest, RUNTIME_TYPE *rt);
#if 0
static ST_RET sxaTextToLocUtc   (ST_VOID *usr, MMS_UTC_TIME *pDest, RUNTIME_TYPE *rt);
#endif

static SXD_ARB_DATA_CTRL sxaTextToLocTbl =
  {
  NULL,				/* arrStart 	*/
  NULL,				/* arrEnd    	*/
  NULL,				/* strStart  	*/
  NULL,				/* strEnd    	*/
  sxaTextToLocInt8,  		/* int8      	*/
  sxaTextToLocInt16,		/* int16     	*/
  sxaTextToLocInt32, 		/* int32     	*/
#if defined(INT64_SUPPORT)
  sxaTextToLocInt64,		/* int64	*/
#endif
  sxaTextToLocUint8, 		/* uint8     	*/
  sxaTextToLocUint16,		/* uint16    	*/
  sxaTextToLocUint32,		/* uint32    	*/
#if defined(INT64_SUPPORT)
  sxaTextToLocUint64,		/* uint64	*/
#endif
  sxaTextToLocFlt,   		/* flt       	*/
  sxaTextToLocDbl,   		/* dbl       	*/
  sxaTextToLocOct,		/* oct       	*/
  sxaTextToLocBool,		/* bool      	*/
  sxaTextToLocBcd1, 	    	/* bcd1      	*/
  sxaTextToLocBcd2, 	    	/* bcd2      	*/
  sxaTextToLocBcd4, 	    	/* bcd4      	*/
  sxaTextToLocBs,		/* bs	       	*/
  sxaTextToLocStr,		/* visible str	*/
  sxaTextToLocBtime4,		/* Bin Time    	*/
  sxaTextToLocBtime6,		/* Bin Time    	*/
  sxaTextToLocGtime,		/* Gen Time    	*/
  NULL 				/* UTC Time	*/
  };				
		
/************************************************************************/
/*			sxaTextToLocal					*/
/************************************************************************/
/* This is the main entry point for TEXT->LOCAL data conversion 	*/

ST_RET sxaTextToLocal (ST_CHAR *pSource, ST_VOID *pDest, ST_INT numRt, SD_CONST RUNTIME_TYPE *rtHead)
  {
SXD_CONTEXT sxdContext;
ST_CHAR tempDataBuf[TEMP_DATA_BUF_SIZE];
ST_RET rtnVal;

/* Make a global temporary buffer available (easier than calloc..)	*/
  sxdContext.sTmpData = tempDataBuf;
  sxdContext.sxaTextWorkBuf = pSource;	/* point to input string	*/
  sxdContext.nStrLen = strlen (sxdContext.sxaTextWorkBuf);
  sxdContext.nDataIdx = 0;	     
  sxdContext.nStringCount = 0;

  sxdContext.textDataErrorDetected = SD_FALSE;

  rtnVal = sxd_process_arb_data ((ST_CHAR *) pDest, rtHead, numRt, &sxdContext, 
			         &sxaTextToLocTbl, NULL);
  if (sxdContext.textDataErrorDetected)
    rtnVal = SD_FAILURE;

  return (rtnVal);
  }

/************************************************************************/
/*			sxaTextToLocBool ()					*/
/************************************************************************/

static ST_RET sxaTextToLocBool (ST_VOID *usr, ST_BOOLEAN *pDest, RUNTIME_TYPE *rt)
  {
ST_INT nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string from the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckIntString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%d", &nDest) == 1) &&
      (nDest >= 0 && nDest <= 255))
    {
    *pDest = (ST_UCHAR) nDest;
    }
  else
    {	   
    SXLOG_NERR1 ("Text '%s' to Local error for type Boolean",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocInt8 ()			 	*/
/************************************************************************/

static ST_RET sxaTextToLocInt8 (ST_VOID *usr, ST_INT8 *pDest, RUNTIME_TYPE *rt)
  {
ST_INT nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckIntString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%d", &nDest) == 1) &&
      (nDest >= -128 && nDest <= 127))
    {
    *pDest = (ST_CHAR) nDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Integer8",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocInt16 ()		      		*/
/************************************************************************/

static ST_RET sxaTextToLocInt16 (ST_VOID *usr, ST_INT16 *pDest, RUNTIME_TYPE *rt)
  {
ST_INT32 nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckIntString (sxdContext->sTmpData) == SD_SUCCESS && 
#if (defined(__alpha) && !defined(__VMS)) 
      (sscanf (sxdContext->sTmpData, "%d", &nDest) == 1) &&
#else
      (sscanf (sxdContext->sTmpData, "%ld", &nDest) == 1) &&
#endif
      (nDest >= -32768 && nDest <= 32767))
    {
    *pDest = (ST_INT16) nDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Integer16",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  } 

/************************************************************************/
/*			sxaTextToLocInt32 ()				*/
/************************************************************************/

static ST_RET sxaTextToLocInt32 (ST_VOID *usr, ST_INT32 *pDest, RUNTIME_TYPE *rt)
  {
ST_LONG nDest;
ST_CHAR temp[35];
ST_CHAR *tempPtr;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckIntString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%ld", &nDest) == 1))
    {
#if defined(_WIN32) || defined(__QNX__)
    ltoa(nDest, temp, 10);
#else
    sprintf (temp, "%ld", nDest);
#endif

    /* look out for leading zero's					*/
    if (nDest != 0L)					
      {
      tempPtr = sxdContext->sTmpData;
      while (tempPtr[0] == '0')
        tempPtr++;
      sxdContext->sTmpData = tempPtr;
      }

    if (strcmp(sxdContext->sTmpData, temp))
      {
      SXLOG_NERR1 ("Text '%s' to Local error for type Integer32",
                      sxdContext->sTmpData);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      } 
    else  
      *pDest = nDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Integer32",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }

  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocInt64 ()				*/
/************************************************************************/

#if defined(INT64_SUPPORT)
static ST_RET sxaTextToLocInt64 (ST_VOID *usr, ST_INT64 *pDest, RUNTIME_TYPE *rt)
  {
ST_INT64 nDest;
ST_CHAR temp[35];
ST_CHAR *tempPtr;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckIntString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, S_FMT_INT64, &nDest) == 1))
    {
#ifdef _WIN32
    _i64toa(nDest, temp, 10);
#else
    sprintf (temp, S_FMT_INT64, nDest);
#endif

    /* look out for leading zero's					*/
    if (nDest != 0L)					
      {
      tempPtr = sxdContext->sTmpData;
      while (tempPtr[0] == '0')
        tempPtr++;
      sxdContext->sTmpData = tempPtr;
      }

    if (strcmp(sxdContext->sTmpData, temp))
      {
      SXLOG_NERR1 ("Text '%s' to Local error for type Integer64",
                      sxdContext->sTmpData);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      } 
    else  
      *pDest = nDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Integer64",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  } 
#endif

/************************************************************************/
/*			sxaTextToLocUint8 ()				*/
/************************************************************************/

static ST_RET sxaTextToLocUint8 (ST_VOID *usr, ST_UINT8 *pDest, RUNTIME_TYPE *rt)
  {
ST_UINT nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckUintString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%d", &nDest) == 1) &&
      (nDest <= 255))
    {
    *pDest = (ST_UCHAR) nDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Unsigned8",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocUint16 ()				*/
/************************************************************************/

static ST_RET sxaTextToLocUint16 (ST_VOID *usr, ST_UINT16 *pDest, RUNTIME_TYPE *rt)
  {
ST_ULONG nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckUintString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%lu", &nDest) == 1) &&
      (nDest <= 65535))
    {
    *pDest = (ST_UINT16) nDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Unsigned16",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  } 

/************************************************************************/
/*			sxaTextToLocUint32 ()				*/
/************************************************************************/

static ST_RET sxaTextToLocUint32 (ST_VOID *usr, ST_UINT32 *pDest, RUNTIME_TYPE *rt)
  {
ST_ULONG nDest;
ST_CHAR temp[35];
ST_CHAR *tempPtr;
SXD_CONTEXT *sxdContext;


  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* Check for hex format */
  if (sxdContext->sTmpData[0] == '0' && sxdContext->sTmpData[1] == 'x')
    {
    if (sscanf (sxdContext->sTmpData, "0x%lx", &nDest) == 1)
      {  
      *pDest = nDest;
      return SD_SUCCESS;
      }    
    }    

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckUintString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%lu", &nDest) == 1))
    {
#if defined(_WIN32) || defined(__QNX__)
    ultoa(nDest, temp, 10);
#else
    sprintf (temp, "%lu", nDest);
#endif

    /* look out for leading zero's					*/
    if (nDest != 0L)					
      {
      tempPtr = sxdContext->sTmpData;
      while (tempPtr[0] == '0')
        tempPtr++;
      sxdContext->sTmpData = tempPtr;
      }

    if (strcmp(sxdContext->sTmpData, temp))
      {
      SXLOG_NERR1 ("Text '%s' to Local error for type Unsigned32",
                      sxdContext->sTmpData);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      } 
    else 
      *pDest = nDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Unsigned32",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }


/************************************************************************/
/*			sxaTextToLocUint64 ()				*/
/************************************************************************/

#if defined(INT64_SUPPORT)
static ST_RET sxaTextToLocUint64 (ST_VOID *usr, ST_UINT64 *pDest, RUNTIME_TYPE *rt)
  {
ST_UINT64 nDest;
ST_CHAR temp[35];
ST_CHAR *tempPtr;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckUintString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, S_FMT_UINT64, &nDest) == 1))
    {
#ifdef _WIN32
    _ui64toa(nDest, temp, 10);
#else
    sprintf (temp,  S_FMT_UINT64, nDest);
#endif

    /* look out for leading zero's					*/
    if (nDest != 0L)					
      {
      tempPtr = sxdContext->sTmpData;
      while (tempPtr[0] == '0')
        tempPtr++;
      sxdContext->sTmpData = tempPtr;
      }

    if (strcmp(sxdContext->sTmpData, temp))
      {
      SXLOG_NERR1 ("Text '%s' to Local error for type Unsigned64",
                      sxdContext->sTmpData);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      } 
    else 
      *pDest = nDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Unsigned64",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }
#endif

/************************************************************************/
/*			sxaTextToLocBcd1 ()				*/
/************************************************************************/

static ST_RET sxaTextToLocBcd1 (ST_VOID *usr, ST_INT8 *pDest, RUNTIME_TYPE *rt)
  {
ST_INT nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckIntString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%d", &nDest) == 1))
    {
    if ( (rt->u.p.el_len == 1) && (nDest >= 0 && nDest <= 9) )
      *pDest = (ST_CHAR) nDest;
    else if ( (rt->u.p.el_len == 2) && (nDest >= 0 && nDest <= 99) )
      *pDest = (ST_CHAR) nDest;
    else
      {
      SXLOG_NERR2 ("Text '%s' to Local error for type BCD%d",
                      sxdContext->sTmpData, rt->u.p.el_len);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      }
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type BCD1",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocBcd2 ()					*/
/************************************************************************/

static ST_RET sxaTextToLocBcd2 (ST_VOID *usr, ST_INT16 *pDest, RUNTIME_TYPE *rt)
  {
ST_UINT nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckIntString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%u", &nDest) == 1))
    {
    if ( (rt->u.p.el_len == 3) && (nDest <= 999) )
      *pDest = (ST_INT16) nDest;
    else if ( (rt->u.p.el_len == 4) && (nDest <= 9999) )
      *pDest = (ST_INT16) nDest;
    else
      {
      SXLOG_NERR2 ("Text '%s' to Local error for type BCD%d",
                      sxdContext->sTmpData, rt->u.p.el_len);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      }
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type BCD2",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocBcd4 ()				*/
/************************************************************************/


static ST_RET sxaTextToLocBcd4 (ST_VOID *usr, ST_INT32 *pDest, RUNTIME_TYPE *rt)
  {
ST_LONG nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckIntString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%ld", &nDest) == 1))
    {
    if ( (rt->u.p.el_len == 5) && (nDest >= 0 && nDest <= 99999L) )
      *pDest = nDest;
    else if ( (rt->u.p.el_len == 6) && (nDest >= 0 && nDest <= 999999L) )
      *pDest = nDest;
    else if ( (rt->u.p.el_len == 7) && 
              (nDest >= 0 && (ST_ULONG) nDest <= 9999999L) )
      *pDest = nDest;
    else if ( (rt->u.p.el_len == 8) &&
              ((ST_ULONG) nDest <= 99999999L) )
      *pDest = nDest;
    else
      {
      SXLOG_NERR2 ("Text '%s' to Local error for type BCD%d",
                      sxdContext->sTmpData, rt->u.p.el_len);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      }
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type BCD4",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocFlt ()				*/
/************************************************************************/

static ST_RET sxaTextToLocFlt (ST_VOID *usr, ST_FLOAT *pDest, RUNTIME_TYPE *rt)
  {
ST_DOUBLE dDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;


/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/
  if (sxaCheckFloatString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%lf", &dDest) == 1))
    { 

    *pDest = (ST_FLOAT) dDest;
    
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Float",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocDbl ()					*/
/************************************************************************/
  
static ST_RET sxaTextToLocDbl (ST_VOID *usr, ST_DOUBLE *pDest, RUNTIME_TYPE *rt)
  {
ST_DOUBLE dDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* trim any leading blanks						*/
  leftTrim (sxdContext->sTmpData);

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckFloatString (sxdContext->sTmpData) == SD_SUCCESS && 
      (sscanf (sxdContext->sTmpData, "%lf", &dDest) == 1))
    {
    *pDest = dDest;
    }
  else
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Double",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocStr ()		       		*/
/************************************************************************/

static ST_RET sxaTextToLocStr (ST_VOID *usr, ST_CHAR *pDest, RUNTIME_TYPE *rt)
  {
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    {
    sxdContext->sTmpData[0] = 0x00;
    }
  

/* Verify that the string will fit into the destination			*/
  if (strlen (sxdContext->sTmpData) > (ST_UINT) (rt->el_size - 1))
    {
    sxdContext->textDataErrorDetected = SD_TRUE;
    SXLOG_NERR2 ("String too long (%d max) : '%s'", (ST_INT) (rt->el_size - 1),
    						       sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }

  strcpy (pDest, sxdContext->sTmpData);
  return SD_SUCCESS;
  }


/************************************************************************/
/*			sxaTextToLocOct					*/
/************************************************************************/

static ST_RET sxaTextToLocOct (ST_VOID *usr, ST_UCHAR *pDest, RUNTIME_TYPE *rt)
  {
ST_CHAR outData[TEMP_DATA_BUF_SIZE];
ST_INT outDataLen;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/

  if (sxaCheckOctetString (sxdContext->sTmpData, outData, &outDataLen) != SD_SUCCESS)
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Octet String",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }

  if (rt->u.p.el_len <0)
    {
    if (outDataLen > (ST_INT) abs(rt->u.p.el_len))
      {
      SXLOG_NERR2 ("Octet String too long (%d max) : '%s'", 
    		       abs (rt->u.p.el_len), sxdContext->sTmpData);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      }
    *((ST_INT16 *) pDest) = (ST_INT16) outDataLen;
    memcpy (pDest+2, outData, outDataLen);
    }
  else
    {
    if (outDataLen != (ST_INT) rt->u.p.el_len)
      {
      SXLOG_NERR2 ("Invalid Length Octet String (required length=%d octets) : '%s'",
       		      rt->u.p.el_len, sxdContext->sTmpData);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      }
    memcpy (pDest, outData, outDataLen);
    }

  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocBs					*/
/************************************************************************/

static ST_RET sxaTextToLocBs  (ST_VOID *usr, ST_UCHAR *pDest, RUNTIME_TYPE *rt)
  {
ST_CHAR outData[TEMP_DATA_BUF_SIZE];
ST_INT outDataLen, bstringLength;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

/* Verify the string contents are correct for the data type		*/
/* then convert to local format						*/
  
  if (sxaCheckBitString (sxdContext->sTmpData, outData, &outDataLen) != SD_SUCCESS)
    {
    SXLOG_NERR1 ("Text '%s' to Local error for type Bit String",
                      sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }

  bstringLength = strlen(sxdContext->sTmpData);
  if (rt->u.p.el_len <0)		/* variable length bit string 	*/
    {
    if (bstringLength > abs(rt->u.p.el_len))
      {
      SXLOG_NERR2 ("Variable Length Bit String too long (%d bits max) : '%s'",
        	      abs(rt->u.p.el_len), sxdContext->sTmpData);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      }
    *((ST_INT16 *) pDest) = (ST_INT16) bstringLength;
    memcpy (pDest+2, outData, outDataLen);
    }
  else
    {
    if (bstringLength != rt->u.p.el_len)
      {
      SXLOG_NERR2 ("Invlid Length Bit String  (required length=%d bits) : '%s'", 
                      rt->u.p.el_len, sxdContext->sTmpData);
      sxdContext->textDataErrorDetected = SD_TRUE;
      return SD_FAILURE;
      }
    memcpy (pDest, outData, outDataLen);
    }

  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocBtime4				*/
/************************************************************************/

static ST_RET sxaTextToLocBtime4 (ST_VOID *usr, ST_INT32 *pDest, RUNTIME_TYPE *rt)
  {
ST_INT32 nDest;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

  if (Btime4StringToVals (sxdContext->sTmpData, &nDest))
    {
    SXLOG_NERR1 ("Local Btime4 conversion error '%s'", sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }

  memcpy(pDest, &nDest, sizeof(ST_INT32));
  return SD_SUCCESS;
  }


/************************************************************************/
/*			sxaTextToLocBtime6				*/
/************************************************************************/

static ST_RET sxaTextToLocBtime6 (ST_VOID *usr, ST_INT32 *pDest, RUNTIME_TYPE *rt)
  {
ST_INT32 nDest[2];
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

  if (Btime6StringToVals (sxdContext->sTmpData, &nDest[1], &nDest[0]))
    {
    SXLOG_NERR1 ("Local Btime6 conversion error '%s'", sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }

  memcpy(pDest, nDest, 2*sizeof(ST_INT32));
  return SD_SUCCESS;
  }

/************************************************************************/
/*			sxaTextToLocGtime					*/
/************************************************************************/

static ST_RET sxaTextToLocGtime (ST_VOID *usr, time_t *pDest, RUNTIME_TYPE *rt)
  {
time_t t;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Get the next sub-string frm the source string into 'sTmpData'	*/
  if (sxaGetNextString (usr) != SD_SUCCESS)
    return SD_FAILURE;

  if (tstrStringToTime (sxdContext->sTmpData, &t))
    {
    SXLOG_NERR1 ("Local time conversion error '%s'", sxdContext->sTmpData);
    sxdContext->textDataErrorDetected = SD_TRUE;
    return SD_FAILURE;
    }

  *pDest = t;
  return SD_SUCCESS;
  }

#if 0
/************************************************************************/
/*			sxaTextToLocUtc					*/
/************************************************************************/

static ST_RET sxaTextToLocUtc (ST_VOID *usr, MMS_UTC_TIME *pDest, RUNTIME_TYPE *rt)
  {
    SXLOG_ERR0 ("sxaTextToLocUtc error: function not implemented");
    return (SD_FAILURE);
  }
#endif

/************************************************************************/
/************************************************************************/
/*			sxaGetNextString				*/
/************************************************************************/
/* Get the next sub-string frm the source string into 'sTmpData'	*/

static ST_INT sxaGetNextString (ST_VOID *usr)
  {
ST_INT  nCount;
ST_INT  nIdx;
ST_CHAR c;
SXD_CONTEXT *sxdContext;

  sxdContext = (SXD_CONTEXT *) usr;

/* Copy the data from data buffer to temporary data buffer.		*/
/* Start at the current position, strip off learing delimiters, 	*/
/* accept characters until the next delimiter				*/
/*									*/
/* CF_TEXT:  Each line ends with a carriage return/linefeed combination.*/
/*	     A null character signals the end of the data.		*/
  nCount = 0;
  nIdx = sxdContext->nDataIdx;
  while (sxdContext->nStrLen > 0)
    {
    sxdContext->nStrLen--;
    c = sxdContext->sxaTextWorkBuf[nIdx++];
    if (c == 0x00 || c == 0x0d)
      {
      break;	/* This is the end of this component of the string	*/
      }

    sxdContext->sTmpData[nCount++] = c;
    }

  while (sxdContext->nStrLen > 0)
    {
    c = sxdContext->sxaTextWorkBuf[nIdx];
    if (c != 0x00 && c != 0x0a )
      {
      break;	/* This is strips out the linefeed			*/
      }
    nIdx++;
    sxdContext->nStrLen--;
    }

  sxdContext->nDataIdx = nIdx;
  sxdContext->sTmpData[nCount] = 0x00;
  return (SD_SUCCESS);
  }

/************************************************************************/
/* leftTrim:  remove leading spaces from text string			*/
/************************************************************************/

static ST_VOID leftTrim (ST_CHAR *pString)
  {
ST_CHAR outData[TEMP_DATA_BUF_SIZE];
ST_INT len, startPos=0, i=0;

  len = (strlen (pString));
  if (!len)
    return;

  strcpy (outData, pString);
  while (i<len && outData[i] == ' ')
    {
    startPos++;
    i++;
    }

  strcpy (pString, &outData[startPos]);
  }

/************************************************************************/
/************************************************************************/
/*			sxaCheckIntString				*/
/************************************************************************/
/* Verify that this is valid integer data				*/

static ST_INT sxaCheckIntString (ST_CHAR *pC)
  {
ST_INT slen;
ST_INT i;

  slen = strlen (pC);

/* Make sure there are some characers to look at			*/
  if (!slen)
    return (SD_FAILURE);

/* Look at each character in the string and verify it is valid		*/
  for (i = 0; i < slen; ++i) 
    {
    if (isdigit(pC[i]))
      continue;
    if (i == 0  && (pC[i] == '-'))
      continue;

    return (SD_FAILURE);
    }
  return (SD_SUCCESS);
  }


/************************************************************************/
/*			sxaCheckUintString				*/
/************************************************************************/
/* Verify that this is valid unsigned integer data			*/

static ST_INT sxaCheckUintString (ST_CHAR *pC)
  {
ST_INT slen;
ST_INT i;

  slen = strlen (pC);

/* Make sure there are some characters to look at			*/
  if (!slen)
    return (SD_FAILURE);

/* Look at each character in the string and verify it is valid		*/
  for (i = 0; i < slen; ++i) 
    {
    if (isdigit(pC[i]))
      continue;

    return (SD_FAILURE);
    }
  return (SD_SUCCESS);
  }


/************************************************************************/
/*			sxaCheckFloatString				*/
/************************************************************************/
/* Verify that this is valid floating point data			*/

static ST_INT sxaCheckFloatString (ST_CHAR *pC)
  {
ST_INT slen;
ST_INT i;

  slen = strlen (pC);

/* Make sure there are some characers to look at			*/
  if (!slen)
    return (SD_FAILURE);

/* Look at each character in the string and verify it is valid		*/
  for (i = 0; i < slen; ++i) 
    {
    if (isdigit(pC[i]))
      continue;

    if (pC[i] == 'e' ||
        pC[i] == 'E' ||
        pC[i] == '+' ||
        pC[i] == '-' ||
        pC[i] == '.')
      {
      continue;
      }
    return (SD_FAILURE);
    }
  return (SD_SUCCESS);
  }


/************************************************************************/
/*			sxaCheckOctetString				*/
/************************************************************************/
/* Verify that this is valid octet string data				*/

static ST_VOID SkipWhiteSpace (ST_CHAR **p)
  {
ST_CHAR *r;

  r = *p;

  while (isspace (*r) && *r != '\0')
    r++;

  *p = r;
  }


static ST_INT sxaCheckOctetString (ST_CHAR *pC, ST_CHAR *pOutData, ST_INT *pOutLen)
  {
ST_CHAR *p = pC;
ST_BOOLEAN done = SD_FALSE;
ST_INT i = 0;
ST_INT nibble = 1;		/* init to error case				*/
ST_INT digit;

  SkipWhiteSpace (&p);	/* skip white space after delimiter		*/

  if (*p == '\0')
    {	/* input string is empty. Return len = 0.	*/
    *pOutLen = 0;
    return (SD_SUCCESS);
    }

  while (!done)
    {
    if (*p == '\0')
      done = SD_TRUE;
    else
      {
      if (!isxdigit (*p))		/* bad number			*/
        return (SD_FAILURE);

      i = 0;
      nibble = 0;
      while (isxdigit (*p))		/* while hex digits		*/
	{
	if (i > 2000)
	  return (SD_FAILURE);		/* length too long		*/
	digit = *p++;			/* separate nibbles		*/
	digit = isdigit (digit) ? digit - '0' : 10 + (toupper (digit) - 'A'); 
	if (nibble)
	  {
	  nibble = 0;
					/* set low byte			*/
	  pOutData[i] = (pOutData[i] | (ST_CHAR) digit);
	  i++;
          SkipWhiteSpace (&p);
	  }
	else
	  {
	  nibble = 1;
	  pOutData[i] = (ST_CHAR) digit << 4;	/* set high byte*/
	  }
	}
      }
    }

  /* set data length */
  if (nibble == 0)
    *pOutLen = i;
  else
    return (SD_FAILURE);

  return (SD_SUCCESS);
  }


/************************************************************************/
/*			sxaCheckBitString				*/
/************************************************************************/
/* Verify that this is valid bitstring data				*/

static ST_INT sxaCheckBitString (ST_CHAR *pC, ST_CHAR *pOutData, ST_INT *pOutLen)
  {
ST_CHAR *p = pC;
ST_INT i, j;
ST_UCHAR mask;

  i = 0;
  j = 0;
  mask = 0x80;
  while (*p != '\0')
    {

    switch (*p)
      {
      case '0':
        pOutData[i] &= ~mask;
      break;

      case '1':
        pOutData[i] |= mask;
      break;

      default:
        return (SD_FAILURE);
      break;
      }

    j++;		/* check next bit				*/
    mask >>= 1;

    if (j == 8)
      {
      i++;		/* do next byte					*/
      j = 0;
      mask = 0x80;
      }

    p++;
    }

  if (j > 0) 
    i++;
  *pOutLen = i;

  return (SD_SUCCESS);
  }

