blob: 50d5f7f7056f2d64617e7656036c427389c678cf [file] [log] [blame] [edit]
//===========================================================================//
// Purpose : Function definitions for miscellaneous helpful string functions.
//
// Functions include:
// - TC_CompareStrings
// - TC_FormatStringCentered
// - TC_FormatStringFilled
// - TC_FormatStringDateTimeStamp
// - TC_FormatStringFileNameLineNum
// - TC_FormatStringNameIndex
// - TC_ParseStringNameIndex
// - TC_ParseStringNameIndices
// - TC_ExtractStringSideMode
// - TC_ExtractStringTypeMode
// - TC_AddStringPrefix
// - TC_AddStringPostfix
// - TC_stricmp
// - TC_strnicmp
// - TC_strdup
//
//===========================================================================//
//---------------------------------------------------------------------------//
// Copyright (C) 2012-2013 Jeff Rudolph, Texas Instruments (jrudolph@ti.com) //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"),//
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included //
// in all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS //
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF //
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN //
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, //
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR //
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE //
// USE OR OTHER DEALINGS IN THE SOFTWARE. //
//---------------------------------------------------------------------------//
#include <cstdio>
#include <climits>
#include <ctime>
#include <cstring>
#include <string>
using namespace std;
#include "TCT_Generic.h"
#include "TIO_Typedefs.h"
#include "TC_StringUtils.h"
//===========================================================================//
// Function : TC_CompareStrings
// Purpose : Compare two strings, returning a negative value if the
// 1st string is less than the 2nd string, returning a
// positive value if the 1st string is greater than the
// 2nd string, and returning a 0 if both strings are the
// same. This function correctly handles alphanumeric
// strings in the form "xxx[nnn]" or "xxx(nnn)". For
// example, the sort order ( "A[1]", "A[11]", "A[2]" )
// results from a generic string compare function, while
// the sort order ( "A[1]", "A[2]", "A[11]" ) results from
// this compare function.
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
int TC_CompareStrings(
const char* pszStringA,
const char* pszStringB )
{
// Compare given two strings, but only after testing for a quick
// rejection based on 1st character from each given string
int i = 0;
// Loop until all characters in alphanumeric strings have been compared
while( pszStringA && pszStringB )
{
if( *pszStringA <= '9' && *pszStringA >= '1' &&
*pszStringB <= '9' && *pszStringB >= '1' )
{
// Handle special case when comparing digits from alphanumeric strings
// (by design, 'atol( )' reads until 1st non-digit character is found)
long lA = atol( pszStringA );
long lB = atol( pszStringB );
if(( lA != LONG_MAX ) && ( lB != LONG_MAX ))
{
long l = lA - lB;
if( l == 0 )
{
// Skip past digits when digits within alphanumeric strings match
while( *pszStringA <= '9' && *pszStringA >= '0' )
{
++pszStringA;
}
while( *pszStringB <= '9' && *pszStringB >= '0' )
{
++pszStringB;
}
}
else
{
// Detected mis-compare between given alphanumeric strings
i = ( l > 0 ? 1 : -1 );
break;
}
}
else
{
i = *pszStringA - *pszStringB;
if( i == 0 )
{
// Skip past digits when digits within alphanumeric strings match
++pszStringA;
++pszStringB;
continue;
}
else
{
// Detected mis-compare between given alphanumeric strings
break;
}
}
}
else
{
// Handle case when comparing non-digits from alphanumeric strings
i = *pszStringA - *pszStringB;
if( i == 0 )
{
// Continue iterating characters in given alphanumeric strings
if( *pszStringA && *pszStringB )
{
++pszStringA;
++pszStringB;
}
else if( *pszStringA )
{
++pszStringA;
}
else if( *pszStringB )
{
++pszStringB;
}
else
{
break;
}
}
else
{
// Detected mis-compare between given alphanumeric strings
break;
}
}
}
return( i );
}
//===========================================================================//
int TC_CompareStrings(
const string& srStringA,
const string& srStringB )
{
const char* pszStringA = srStringA.data( );
const char* pszStringB = srStringB.data( );
return( TC_CompareStrings( pszStringA, pszStringB ));
}
//===========================================================================//
int TC_CompareStrings(
const void* pvoidA,
const void* pvoidB )
{
const char* pszStringA = static_cast< const char* >( pvoidA );
const char* pszStringB = static_cast< const char* >( pvoidB );
return( TC_CompareStrings( pszStringA, pszStringB ));
}
//===========================================================================//
// Function : TC_FormatStringCentered
// Purpose : Format and return a centered string based on the given
// centered string reference length.
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
bool TC_FormatStringCentered(
const char* pszString,
size_t lenRefer,
char* pszCentered,
size_t lenCentered )
{
if( pszString && pszCentered )
{
memset( pszCentered, 0, lenCentered );
size_t lenString = strlen( pszString );
size_t lenBeginSpc = ( lenRefer - lenString ) > 0 ?
( lenRefer - lenString ) / 2 : 0;
size_t lenEndSpc = ( lenRefer - lenString + 1 ) > 0 ?
( lenRefer - lenString + 1 ) / 2 : 0;
if( lenCentered >= lenString + lenBeginSpc + lenEndSpc + 1 )
{
sprintf( pszCentered, "%*s%s%*s",
static_cast< int >( lenBeginSpc ), lenBeginSpc > 0 ? " " : "",
pszString,
static_cast< int >( lenEndSpc ), lenEndSpc > 0 ? " " : "" );
}
}
return( pszCentered && *pszCentered ? true : false );
}
//===========================================================================//
// Function : TC_FormatStringFilled
// Purpose : Format and return a filled string based on the given fill
// character.
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
bool TC_FormatStringFilled(
char cFill,
char* pszFilled,
size_t lenFilled )
{
if( pszFilled )
{
memset( pszFilled, 0, lenFilled + 1 );
memset( pszFilled, cFill, lenFilled );
}
return( pszFilled && *pszFilled ? true : false );
}
//===========================================================================//
// Function : TC_FormatStringDateTimeStamp
// Purpose : Format and return a date/time stamp string with optional
// prefix/postfix strings.
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
bool TC_FormatStringDateTimeStamp(
char* pszDateTimeStamp,
size_t lenDateTimeStamp,
const char* pszPrefix,
const char* pszPostfix )
{
if( pszDateTimeStamp )
{
memset( pszDateTimeStamp, 0, lenDateTimeStamp );
time_t gmtTime;
time( &gmtTime );
struct tm* localTime = localtime( &gmtTime );
size_t lenPrefix = pszPrefix ? strlen( pszPrefix ) : 0;
size_t lenPostfix = pszPostfix ? strlen( pszPostfix ) : 0;
if( lenDateTimeStamp >= 17 + lenPrefix + lenPostfix + 1 )
{
sprintf( pszDateTimeStamp, "%s%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d%s",
TIO_PSZ_STR( pszPrefix ),
localTime->tm_mon + 1,
localTime->tm_mday,
localTime->tm_year % 100,
localTime->tm_hour,
localTime->tm_min,
localTime->tm_sec,
TIO_PSZ_STR( pszPostfix ));
}
}
return( pszDateTimeStamp && *pszDateTimeStamp ? true : false );
}
//===========================================================================//
// Function : TC_FormatStringFileNameLineNum
// Purpose : Format and return a file name/line number string with
// optional prefix/postfix strings.
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 06/18/13 jeffr : Original
//===========================================================================//
bool TC_FormatStringFileNameLineNum(
char* pszFileNameLineNum,
size_t lenFileNameLineNum,
const char* pszFileName,
unsigned int lineNum,
const char* pszPrefix,
const char* pszPostfix )
{
if( pszFileNameLineNum )
{
memset( pszFileNameLineNum, 0, lenFileNameLineNum );
size_t lenPrefix = strlen( pszPrefix );
size_t lenPostfix = strlen( pszPostfix );
size_t lenFileName = lenFileNameLineNum - lenPrefix - lenPostfix - 4;
size_t lenLineNum = 5;
if( lenFileNameLineNum >= lenPrefix + lenFileName + lenLineNum + lenPostfix )
{
sprintf( pszFileNameLineNum, "%s%.*s:%d%s",
TIO_PSZ_STR( pszPrefix ),
static_cast<int>( lenFileName ),
TIO_PSZ_STR( pszFileName ),
lineNum,
TIO_PSZ_STR( pszPostfix ));
}
}
return( pszFileNameLineNum && *pszFileNameLineNum ? true : false );
}
//===========================================================================//
// Function : TC_FormatStringNameIndex
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 02/21/12 jeffr : Original
//===========================================================================//
void TC_FormatStringNameIndex(
const char* pszName,
size_t index,
string* psrNameIndex )
{
if( psrNameIndex )
{
*psrNameIndex = "";
if( pszName )
{
*psrNameIndex += pszName;
}
if( index != SIZE_MAX )
{
char szIndex[TIO_FORMAT_STRING_LEN_VALUE];
sprintf( szIndex, "%lu", static_cast< unsigned long >( index ));
*psrNameIndex += "[";
*psrNameIndex += szIndex;
*psrNameIndex += "]";
}
}
}
//===========================================================================//
void TC_FormatStringNameIndex(
const string& srName,
size_t index,
string* psrNameIndex )
{
const char* pszName = ( srName.length( ) ? srName.data( ) : 0 );
TC_FormatStringNameIndex( pszName, index, psrNameIndex );
}
//===========================================================================//
// Function : TC_ParseStringNameIndex
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 02/21/12 jeffr : Original
//===========================================================================//
bool TC_ParseStringNameIndex(
const char* pszNameIndex,
string* psrName,
size_t* pindex )
{
string srName( "" );
size_t index = SIZE_MAX;
if( pszNameIndex )
{
srName = pszNameIndex;
size_t left = srName.find( '[' );
size_t right = srName.find( ']' );
if(( left != string::npos ) && ( right != string::npos ))
{
if( left < right )
{
string srIndex( srName.substr( left + 1, right - left - 1 ));
index = atoi( srIndex.data( ));
srName = srName.substr( 0, left );
}
}
}
if( psrName )
{
*psrName = srName;
}
if( pindex )
{
*pindex = index;
}
return( index != SIZE_MAX ? true : false );
}
//===========================================================================//
bool TC_ParseStringNameIndex(
const string& srNameIndex,
string* psrName,
size_t* pindex )
{
const char* pszNameIndex = ( srNameIndex.length( ) ? srNameIndex.data( ) : 0 );
return( TC_ParseStringNameIndex( pszNameIndex, psrName, pindex ));
}
//===========================================================================//
// Function : TC_ParseStringNameIndices
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 02/21/12 jeffr : Original
//===========================================================================//
bool TC_ParseStringNameIndices(
const char* pszNameIndices,
string* psrName,
size_t* pindex_i,
size_t* pindex_j )
{
string srName( "" );
size_t index_i = SIZE_MAX;
size_t index_j = SIZE_MAX;
if( pszNameIndices )
{
srName = pszNameIndices;
size_t left = srName.find( '[' );
size_t right = srName.find( ']' );
size_t colon = srName.find( ':' );
if(( left != string::npos ) && ( right != string::npos ) && ( colon != string::npos))
{
if(( left < colon ) && (colon < right ))
{
string srIndex_i( srName.substr( left + 1, colon - left - 1 ));
index_i = atoi( srIndex_i.data( ));
string srIndex_j( srName.substr( colon + 1, right - colon - 1 ));
index_j = atoi( srIndex_j.data( ));
srName = srName.substr( 0, left );
}
}
else if(( left != string::npos ) && ( right != string::npos ))
{
if( left < right )
{
string srIndex( srName.substr( left + 1, right - left - 1 ));
index_i = index_j = atoi( srIndex.data( ));
srName = srName.substr( 0, left );
}
}
}
if( psrName )
{
*psrName = srName;
}
if( pindex_i )
{
*pindex_i = index_i;
}
if( pindex_j )
{
*pindex_j = index_j;
}
return(( index_i != SIZE_MAX ) && ( index_j != SIZE_MAX ) ? true : false );
}
//===========================================================================//
bool TC_ParseStringNameIndices(
const string& srNameIndices,
string* psrName,
size_t* pindex_i,
size_t* pindex_j )
{
const char* pszNameIndices = ( srNameIndices.length( ) ? srNameIndices.data( ) : 0 );
return( TC_ParseStringNameIndices( pszNameIndices, psrName, pindex_i, pindex_j ));
}
//===========================================================================//
// Function : TC_ExtractStringSideMode
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
void TC_ExtractStringSideMode(
TC_SideMode_t sideMode,
string* psrSideMode )
{
if( psrSideMode )
{
*psrSideMode = "";
switch( sideMode )
{
case TC_SIDE_LEFT: *psrSideMode = "left"; break;
case TC_SIDE_RIGHT: *psrSideMode = "right"; break;
case TC_SIDE_LOWER: *psrSideMode = "lower"; break;
case TC_SIDE_UPPER: *psrSideMode = "upper"; break;
case TC_SIDE_BOTTOM: *psrSideMode = "bottom"; break;
case TC_SIDE_TOP: *psrSideMode = "top"; break;
case TC_SIDE_PREV: *psrSideMode = "prev"; break;
case TC_SIDE_NEXT: *psrSideMode = "next"; break;
default: *psrSideMode = "?"; break;
}
}
}
//===========================================================================//
// Function : TC_ExtractStringTypeMode
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
void TC_ExtractStringTypeMode(
TC_TypeMode_t typeMode,
string* psrTypeMode )
{
if( psrTypeMode )
{
*psrTypeMode = "";
switch( typeMode )
{
case TC_TYPE_INPUT: *psrTypeMode = "input"; break;
case TC_TYPE_OUTPUT: *psrTypeMode = "output"; break;
case TC_TYPE_SIGNAL: *psrTypeMode = "signal"; break;
case TC_TYPE_CLOCK: *psrTypeMode = "clock"; break;
case TC_TYPE_POWER: *psrTypeMode = "power"; break;
case TC_TYPE_GLOBAL: *psrTypeMode = "global"; break;
default: *psrTypeMode = "?"; break;
}
}
}
//===========================================================================//
// Function : TC_AddStringPrefix
// Purpose : Add the given prefix to the given string.
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
bool TC_AddStringPrefix(
char* pszString,
const char* pszPrefix )
{
if( pszString && pszPrefix )
{
size_t lenString = strlen( pszString );
size_t lenPrefix = strlen( pszPrefix );
size_t lenCopy = TCT_Min( lenString, lenPrefix );
memcpy( pszString, pszPrefix, lenCopy );
}
return( pszPrefix && *pszPrefix ? true : false );
}
//===========================================================================//
// Function : TC_AddStringPostfix
// Purpose : Add the given postfix to the given string.
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
bool TC_AddStringPostfix(
char* pszString,
const char* pszPostfix )
{
if( pszString && pszPostfix )
{
size_t lenString = strlen( pszString );
size_t lenPostfix = strlen( pszPostfix );
size_t lenCopy = TCT_Min( lenString, lenPostfix );
memcpy( pszString + lenString - lenCopy, pszPostfix, lenCopy );
}
return( pszPostfix && *pszPostfix ? true : false );
}
//===========================================================================//
// Function : TC_stricmp
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
int TC_stricmp(
const char* pszStringA,
const char* pszStringB )
{
while(( pszStringA && *pszStringA ) &&
( pszStringB && *pszStringB ) &&
( toupper( *pszStringA ) == toupper( *pszStringB )))
{
++pszStringA;
++pszStringB;
}
return(( !pszStringA && !pszStringB ) ? 0 : ( *pszStringA - *pszStringB ));
}
//===========================================================================//
int TC_strnicmp(
const string& srStringA,
const string& srStringB )
{
const char* pszStringA = srStringA.data( );
const char* pszStringB = srStringB.data( );
return( TC_stricmp( pszStringA, pszStringB ));
}
//===========================================================================//
// Function : TC_strnicmp
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 05/01/12 jeffr : Original
//===========================================================================//
int TC_strnicmp(
const char* pszStringA,
const char* pszStringB,
int i )
{
while(( pszStringA && *pszStringA ) &&
( pszStringB && *pszStringB ) &&
( toupper( *pszStringA ) == toupper( *pszStringB )) &&
( i ))
{
++pszStringA;
++pszStringB;
--i;
}
pszStringA = ( i > 0 ? pszStringA : 0 );
pszStringB = ( i > 0 ? pszStringB : 0 );
return(( !pszStringA && !pszStringB ) ? 0 : ( *pszStringA - *pszStringB ));
}
//===========================================================================//
int TC_strnicmp(
const string& srStringA,
const string& srStringB,
int i )
{
const char* pszStringA = srStringA.data( );
const char* pszStringB = srStringB.data( );
return( TC_strnicmp( pszStringA, pszStringB, i ));
}
//===========================================================================//
// Function : TC_strdup
// Author : Jeff Rudolph
//---------------------------------------------------------------------------//
// Version history
// 07/10/12 jeffr : Original
//===========================================================================//
char* TC_strdup(
const char* pszString )
{
char* pszDupString = 0;
if( pszString )
{
size_t lenString = strlen( pszString );
pszDupString = static_cast< char* >( malloc( lenString + 1 ));
if( pszDupString )
{
memcpy( pszDupString, pszString, lenString + 1 );
}
}
return( pszDupString );
}
//===========================================================================//
char* TC_strdup(
const string& srString )
{
const char* pszString = srString.data( );
return( TC_strdup( pszString ));
}