Files
libraries/ux/ux_str.c
Philip Smart af833c09ee Initial upload
2019-11-18 00:29:48 +00:00

767 lines
24 KiB
C
Executable File

/******************************************************************************
* Product: # # # # # ### ######
* # # # # # # # #
* # # # # # # # #
* # # # # # ######
* # # # # # # # #
* # # # # # # # #
* ##### # # ####### ####### ### ######
*
* File: ux_str.c
* Description: General purpose string processing funtions. Additions to
* those which exist within the C libraries.
*
* Version: %I%
* Dated: %D%
* Copyright: P.D. Smart, 1994-2019.
*
* History: 1.0 - Initial Release.
*
******************************************************************************
* This source file is free software: you can redistribute it and#or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This source file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* Bring in system header files.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/timeb.h>
#include <sys/stat.h>
#include <fcntl.h>
#if defined(SUNOS) || defined(SOLARIS) || defined(LINUX)
#include <sys/socket.h>
#include <sys/time.h>
#include <string.h>
#endif
#if defined(SOLARIS)
#include <sys/file.h>
#endif
#if defined(LINUX)
#include <term.h>
#endif
#if defined(_WIN32)
#include <winsock.h>
#include <time.h>
#endif
#if defined(SUNOS) || defined(SOLARIS)
#include <netinet/in.h>
#include <sys/wait.h>
#endif
/* Indicate that we are a C module for any header specifics.
*/
#define UX_STRINGPROCESSING_C
/* Bring in specific header files.
*/
#include "ux.h"
/******************************************************************************
* Function: PutCharFromLong
* Description: Place a long type variable into a character buffer in a known
* byte order. IE. A long is 32 bit, and is placed into the
* char buffer as MSB (3), 2, 1, LSB (0). Where MSB fits into the
* first byte of the buffer.
* Returns: R_OK - Cannot fail ... will I be eating my words...?
******************************************************************************/
int PutCharFromLong( UCHAR *pDestBuf, /* O: Destination buffer */
ULNG lVar ) /* I: Variable of type long */
{
/* Local variables.
*/
int nReturn = R_OK;
ULNG lVal = lVar;
/* Cant assume any byte ordering, so use arithmetic to break it down
* into fundamental components. Assume a long is 32bit.
*/
pDestBuf[0] = (UCHAR)(lVal/16777216L);
lVal -= (ULNG)pDestBuf[0] * 16777216L;
pDestBuf[1] = (UCHAR)(lVal/65536L);
lVal -= (ULNG)pDestBuf[1] * 65536L;
pDestBuf[2] = (UCHAR)(lVal/256L);
lVal -= (ULNG)pDestBuf[2] * 256L;
pDestBuf[3] = (UCHAR)lVal;
/* Finished, get out!!
*/
return( nReturn );
}
/******************************************************************************
* Function: PutCharFromInt
* Description: Place an int type variable into a character buffer in a known
* byte order. IE. An int is 16 bit, and is placed into the
* char buffer as MSB (1), LSB (0). Where MSB fits into the
* first byte of the buffer.
* Returns: R_OK - Cannot fail ... see comment above.
******************************************************************************/
int PutCharFromInt( UCHAR *pDestBuf, /* O: Destination buffer */
UINT lVar ) /* I: Variable of type int */
{
/* Local variables.
*/
int nReturn = R_OK;
ULNG lVal = (ULNG)lVar;
/* Cant assume any byte ordering, so use arithmetic to break it down
* into fundamental components. Assume 16 bit Int.
*/
if(lVal > 65536L)
{
/* > 16 bit, so remove upper component.
*/
lVal -= (lVal/16777216L)*65536L;
}
pDestBuf[0] = (UCHAR)(lVal/256L);
lVal -= (ULNG)pDestBuf[0] * 256L;
pDestBuf[1] = (UCHAR)lVal;
/* Finished, get out!!
*/
return( nReturn );
}
/******************************************************************************
* Function: GetLongFromChar
* Description: Get a long type variable from a character buffer. The byte
* ordering in the buffer is assumed to be 32bit, MSB(3), 2, 1,
* LSB (0), where the MSB fits into the first byte of the
* buffer.
* Returns: R_OK - Cannot fail ... will I be eating my words...?
******************************************************************************/
ULNG GetLongFromChar( UCHAR *pDestBuf ) /* I: Source buffer to convert */
{
/* Local variables.
*/
ULNG lVal = 0;
/* Cant assume any byte ordering, so use arithmetic to break it down
* into fundamental components. Assume a long is 32bit.
*/
lVal = (UCHAR)pDestBuf[0] * 16777216L;
lVal += (UCHAR)pDestBuf[1] * 65536L;
lVal += (UCHAR)pDestBuf[2] * 256L;
lVal += (UCHAR)pDestBuf[3];
/* Finished, get out!!
*/
return( lVal );
}
/******************************************************************************
* Function: GetIntFromChar
* Description: Get a long type variable from a character buffer. The byte
* ordering in the buffer is assumed to be 16bit, MSB(1), LSB(0)
* where the MSB fits into the first byte of the buffer.
* Returns: R_OK - Cannot fail ... will I be eating my words...?
******************************************************************************/
UINT GetIntFromChar( UCHAR *pDestBuf ) /* I: Source buffer to convert */
{
/* Local variables.
*/
UINT lVal = 0;
/* Cant assume any byte ordering, so use arithmetic to break it down
* into fundamental components. Assume a long is 32bit.
*/
lVal += (UCHAR)pDestBuf[0] * 256;
lVal += (UCHAR)pDestBuf[1];
/* Finished, get out!!
*/
return( lVal );
}
/******************************************************************************
* Function: StrPut
* Description: Put a string INTO another string. Same as strcpy BUT it doesnt
* terminate the destination string.
* Returns: R_OK - Cannot fail ... will I be eating my words...?
******************************************************************************/
UINT StrPut( UCHAR *spDestBuf, /* I: Destination buffer to copy into */
UCHAR *spSrcBuf, /* I: Source buffer to copy from */
UINT nBytes ) /* I: Number of bytes to copy */
{
/* Local variables.
*/
UINT nNdx;
/* Simple copy.
*/
for(nNdx=0; nNdx < nBytes && spSrcBuf[nNdx] != '\0'; nNdx++)
{
spDestBuf[nNdx] = spSrcBuf[nNdx];
}
/* Finished, get out!!
*/
return( R_OK );
}
/******************************************************************************
* Function: FFwdOverWhiteSpace
* Description: Forward a pointer past whitespace in the input buffer.
* Returns: Non.
******************************************************************************/
void FFwdOverWhiteSpace( UCHAR *szInBuf, /* I: Input data buffer */
UINT *nPos ) /* IO: Start/End position in buf */
{
/* Local variables.
*/
/* Move the pointer past whitespace to the fisrt non-whitespace character
* or the end of file.
*/
while(szInBuf[*nPos] != '\0' && isspace(szInBuf[*nPos]))
{ (*nPos)++; }
return;
}
/******************************************************************************
* Function: ParseForToken
* Description: Parse the input buffer for the next token. A token can be a
* Alpha/Alphanum word, a numeric, a single character or a
* string.
* Returns: Type of Token located.
******************************************************************************/
UINT ParseForToken( UCHAR *szInBuf, /* I: Input buffer */
UINT *nPos, /* IO: Current pos in buffer */
UCHAR *szTokBuf ) /* O: Token output buffer */
{
/* Local variables.
*/
UINT nExit;
UINT nQuoteType;
UINT nToken;
UINT nTokNdx;
/* Initially, forward to the first non-whitespace.
*/
while(szInBuf[*nPos] != '\0' && isspace(szInBuf[*nPos]))
{
(*nPos)++;
}
/* End of buffer..?
*/
if(szInBuf[*nPos] == '\0')
{
/* Instruct caller that we are at the end.
*/
nToken = TOK_EOB;
} else
/* Do we have an alpha/alphanum in the buffer?
*/
if(isalpha(szInBuf[*nPos]))
{
/* Instruct caller, initially, that we located an ALPHA word.
*/
nToken = TOK_ALPHA;
/* Go through the buffer, copying out the word.
*/
for(nTokNdx=0; isalnum(szInBuf[*nPos]) || szInBuf[*nPos] == '-' ||
szInBuf[*nPos] == '_' || szInBuf[*nPos] == '/';
nTokNdx++, (*nPos)++)
{
/* Data copy.
*/
szTokBuf[nTokNdx] = szInBuf[*nPos];
}
/* Terminate Token Buffer.
*/
szTokBuf[nTokNdx] = '\0';
} else
/* Do we have a numeric in the buffer?
*/
if(isdigit(szInBuf[*nPos]) ||
(szInBuf[*nPos] == '-' && isdigit(szInBuf[(*nPos)+1])) ||
(szInBuf[*nPos] == '+' && isdigit(szInBuf[(*nPos)+1])))
{
/* Instruct caller that we located a numeric.
*/
nToken = TOK_NUMERIC;
/* Straight data copy.
*/
for(nTokNdx=0;
isdigit(szInBuf[*nPos]) || szInBuf[*nPos] == '.' ||
szInBuf[*nPos] == '-' || szInBuf[*nPos] == '+';
nTokNdx++, (*nPos)++)
{
szTokBuf[nTokNdx] = szInBuf[*nPos];
}
/* Terminate Token Buffer.
*/
szTokBuf[nTokNdx] = '\0';
} else
/* Do we have a string in the buffer?
*/
if(szInBuf[*nPos] == 0x27 || szInBuf[*nPos] == 0x22)
{
/* Instruct caller that we located a string.
*/
nToken = TOK_STRING;
/* What type of quote are we looking for?
*/
if(szInBuf[(*nPos)] == 0x27)
nQuoteType = 0;
else
nQuoteType = 1;
/* Go through the input buffer until we locate the matching quote
* or we hit the end of buffer.
*/
for(nTokNdx=0, nExit=FALSE; nExit == FALSE; nTokNdx++, (*nPos)++)
{
/* Copy over to the token buffer, all chars, including the final
* quote/eob.
*/
szTokBuf[nTokNdx] = szInBuf[*nPos];
/* If were looking for single quotes and we locate one which is
* not escaped, then we've reached the end of the string.
*/
if(szInBuf[*nPos] == 0x27 && nQuoteType == 0)
{
/* If where at the beginning of a string and we dont meet
* the criterion for a null string, the loop.
*/
if(nTokNdx == 0 &&
szInBuf[(*nPos)+1] != 0x27)
{
continue;
} else
/* A null string?
*/
if(nTokNdx == 0 &&
szInBuf[(*nPos)+1] == 0x27 &&
szInBuf[(*nPos)+2] != 0x27)
{
/* Copy final byte into token buffer.
*/
szTokBuf[++nTokNdx] = szInBuf[++(*nPos)];
nExit = TRUE;
} else
/* A lone quote?
*/
if(szInBuf[(*nPos)-1] != 0x5c &&
szInBuf[(*nPos)+1] != 0x27 &&
szInBuf[(*nPos)-1] != 0x27)
{
nExit = TRUE;
}
} else
/* If were looking for double quotes and we locate on which is
* not escaped, then we've reached the end of the string.
*/
if(szInBuf[*nPos] == 0x22 && nQuoteType == 1)
{
/* If where at the beginning of a string and we dont meet
* the criterion for a null string, then loop.
*/
if(nTokNdx == 0 &&
szInBuf[(*nPos)+1] != 0x22)
{
continue;
} else
/* A null string?
*/
if(szInBuf[(*nPos)+1] == 0x22 &&
szInBuf[(*nPos)+2] != 0x22 &&
nTokNdx == 0)
{
/* Copy final byte into token buffer.
*/
szTokBuf[++nTokNdx] = szInBuf[++(*nPos)];
nExit = TRUE;
} else
/* A lone quote?
*/
if(szInBuf[(*nPos)-1] != 0x5c &&
szInBuf[(*nPos)+1] != 0x22 &&
szInBuf[(*nPos)-1] != 0x22)
{
nExit = TRUE;
}
} else
/* Found the end of buffer... some idiot hasnt terminated the
* string correctly.
*/
if(szInBuf[*nPos] == '\0')
nExit = TRUE;
}
/* Terminate Token Buffer.
*/
szTokBuf[nTokNdx] = '\0';
} else
/* Is this a comment...?
*/
if(szInBuf[*nPos] == '/' && szInBuf[(*nPos)+1] == '*')
{
/* Instruct caller that we located a comment.
*/
nToken = TOK_COMMENT;
/* Loop through copying upto the end of the comment.
*/
for(nTokNdx=0, nExit=FALSE; nExit == FALSE; nTokNdx++, (*nPos)++)
{
/* Copy data into token buffer.
*/
szTokBuf[nTokNdx] = szInBuf[*nPos];
if(nTokNdx < 2) continue;
/* End of comment?
*/
if(szInBuf[*nPos] == '*' && szInBuf[(*nPos)+1] == '/')
{
nExit = TRUE;
}
/* Found the end of buffer... some idiot hasnt terminated the
* comment correctly.
*/
if(szInBuf[*nPos] == '\0')
nExit = TRUE;
}
/* Terminate Token Buffer.
*/
szTokBuf[nTokNdx] = '\0';
} else
{
/* Instruct caller that we located a character.
*/
nToken = TOK_CHAR;
/* Straight data copy and termination.
*/
szTokBuf[0] = szInBuf[(*nPos)++];
szTokBuf[1] = '\0';
}
/* Return type to caller.
*/
return(nToken);
}
/******************************************************************************
* Function: ParseForString
* Description: Get next valid string from input buffer.
* Returns: Non.
******************************************************************************/
int ParseForString( UCHAR *szInBuf, /* I: Input buffer */
UINT *nPos, /* I: Position in input buffer */
UCHAR *szOutBuf ) /* O: Target buffer for string */
{
/* Local variables.
*/
UINT nReturn = R_OK;
UINT nTokType;
/* Zero callers buffer.
*/
szOutBuf[0] = '\0';
/* Get next parameter.
*/
nTokType = ParseForToken(szInBuf, nPos, szOutBuf);
/* If its not a valid string, modify return code.
*/
if(nTokType == TOK_COMMENT || nTokType == TOK_CHAR ||
nTokType == TOK_EOB || strlen(szOutBuf) == 0)
{
nReturn = R_FAIL;
}
/* Return result to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: ParseForInteger
* Description: Get next valid integer from input buffer.
* Returns: Non.
******************************************************************************/
int ParseForInteger( UCHAR *szInBuf, /* I: Input buffer */
UINT *nPos, /* I: Position in input buffer */
UINT *nMin, /* I: Minimum allowable value */
UINT *nMax, /* I: Maximum allowable value */
int *pOutInt ) /* O: Target buffer for integer */
{
/* Local variables.
*/
UINT nInt;
UINT nReturn = R_OK;
UINT nTokType;
UCHAR szTmpBuf[MAX_TMPBUFLEN];
/* Get next parameter.
*/
nTokType = ParseForToken(szInBuf, nPos, szTmpBuf);
/* Convert into an integer.
*/
if(nTokType != TOK_NUMERIC || sscanf(szTmpBuf, "%d", &nInt) != 1 ||
(nMin != NULL && nInt < *nMin) || (nMax != NULL && nInt > *nMax))
{
nReturn = R_FAIL;
} else
{
*pOutInt = nInt;
}
/* Return result to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: ParseForLong
* Description: Get next valid Long from input buffer.
* Returns: Non.
******************************************************************************/
int ParseForLong( UCHAR *szInBuf, /* I: Input buffer */
UINT *nPos, /* I: Position in input buffer */
long *lMin, /* I: Minimum allowable value */
long *lMax, /* I: Maximum allowable value */
long *pOutLong ) /* O: Target buffer for Long */
{
/* Local variables.
*/
UINT nReturn = R_OK;
UINT nTokType;
long lLng;
UCHAR szTmpBuf[MAX_TMPBUFLEN];
/* Get next parameter.
*/
nTokType = ParseForToken(szInBuf, nPos, szTmpBuf);
/* Convert into an integer.
*/
if(nTokType != TOK_NUMERIC || sscanf(szTmpBuf, "%ld", &lLng) != 1 ||
(lMin != NULL && lLng < *lMin) || (lMax != NULL && lLng > *lMax))
{
nReturn = R_FAIL;
} else
{
*pOutLong = lLng;
}
/* Return result to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: StrRTrim
* Description: A function to trim off all trailing spaces for a given string.
* The function works by starting at the end of a null terminated
* string and looking for the first non-space character. It then
* places a null terminator at the new location.
* Returns: Pointer to new string.
******************************************************************************/
char *StrRTrim( char *szSrc ) /* IO: Base string to trim */
{
/* Local variables.
*/
char *pLocation = &szSrc[strlen(szSrc)-1];
/* Scan backwards until we find a non space or we meet the beginning
* of the string.
*/
while( pLocation != szSrc && isspace(*pLocation) )
{
pLocation--;
}
/* If we are not at the beginning of the string, then place a null
* terminator at t+1;
*/
if(pLocation != szSrc)
{
pLocation++;
*pLocation = '\0';
}
/* All done, exit.
*/
return(szSrc);
}
/******************************************************************************
* Function: StrCaseCmp
* Description: A function to perform string compares regardless of
* character case. Provided mainly for operating systems that
* dont possess such functionality.
* Returns: 0 - Strings compare.
* > 0
* < 0
******************************************************************************/
int StrCaseCmp( const char *szSrc, /* I: Base string to compare against */
const char *szCmp ) /* I: Comparator string */
{
/* Local variables.
*/
register signed char cResult;
/* Loop, progressing through the strings until we have a difference or
* we get to the end of the string and hence have a comparison match.
*/
while(1)
{
cResult = toupper(*szSrc) - toupper(*szCmp);
szCmp++;
szSrc++;
if(cResult != 0 || *szCmp == '\0' || *szSrc == '\0')
break;
}
/* Return result to caller.
*/
return(cResult);
}
/******************************************************************************
* Function: StrnCaseCmp
* Description: A function to perform string compares regardless of
* character case for a specified number of characters within
* both strings. Provided mainly for operating systems that
* dont possess such functionality.
* Returns: 0 - Strings compare.
* > 0
* < 0
******************************************************************************/
int StrnCaseCmp( const char *szSrc, /* I: Base string to compare against */
const char *szCmp, /* I: Comparator string */
size_t nCount ) /* I: Number of bytes to compare */
{
/* Local variables.
*/
register signed char cResult;
/* Loop, progressing through the strings until we have a difference or
* the given number of characters match in both strings.
*/
while(nCount)
{
cResult = toupper(*szSrc) - toupper(*szCmp);
szCmp++;
szSrc++;
if(cResult != 0 || *szCmp == '\0' || *szSrc == '\0')
break;
nCount--;
}
/* Return result to caller.
*/
return(cResult);
}
/******************************************************************************
* Function: SplitFQFN
* Description: A function to split a fully qualified filename into a
* directory and filename components.
* Returns: R_OK - Filename split.
* R_FAIL - Couldnt split due to errors, ie. memory.
******************************************************************************/
int SplitFQFN( char *szFQFN, /* I: Fully Qualified File Name */
char **szDir, /* O: Directory component */
char **szFN ) /* O: Filename component */
{
/* Local variables.
*/
UINT nNdx;
char *spTmpDir;
char *spTmpFN;
char *szFunc = "SplitFQFN";
/* Allocate a buffer to hold the directory component.
*/
if((spTmpDir=(UCHAR *)malloc(strlen(szFQFN)+1)) == NULL)
{
Lgr(LOG_DEBUG, szFunc, "Couldnt malloc (%d) bytes", strlen(szFQFN)+1);
Errno = E_NOMEM;
return(R_FAIL);
}
/* Allocate a buffer to hold the filename component.
*/
if((spTmpFN=(UCHAR *)malloc(strlen(szFQFN)+1)) == NULL)
{
Lgr(LOG_DEBUG, szFunc, "Couldnt malloc (%d) bytes", strlen(szFQFN)+1);
Errno = E_NOMEM;
return(R_FAIL);
}
/* Starting at the end of the string, work backwards until we find
* a directory element character or start of string.
*/
for(nNdx=strlen(szFQFN); nNdx >= 0 && szFQFN[nNdx] != '/'; nNdx--);
/* If nNdx == 0 && szFQFN[nNdx] not equal to the directory character
* then we have a filename with no directory. Just copy.
*/
if(nNdx == 0 && szFQFN[nNdx] != '/')
{
strcpy(spTmpDir, "");
strcpy(spTmpFN, szFQFN);
} else
if(nNdx == 0 && szFQFN[nNdx] == '/')
{
strcpy(spTmpDir, "/");
strcpy(spTmpFN, &szFQFN[1]);
} else
{
szFQFN[nNdx] = '\0';
strcpy(spTmpDir, szFQFN);
strcpy(spTmpFN, &szFQFN[nNdx+1]);
szFQFN[nNdx] = '/';
}
/* Setup callers pointers to point to new memory.
*/
*szDir = spTmpDir;
*szFN = spTmpFN;
/* Return result to caller.
*/
return(R_OK);
}