habeebi

mail@pastecode.io avatar
unknown
plain_text
24 days ago
20 kB
1
Indexable
Never
#define GSCVSID "$Header: /home/cvs/ficc/liberty/src/kool_ade/src/string.c,v 1.45 2014/07/20 09:33:23 sharps Exp $"
/****************************************************************
**
**	STRING.C	- Lots of little string functions
**
**	Copyright 1994 - Goldman, Sachs & Co. - New York
**
**	$Log: string.c,v $
**	Revision 1.45  2014/07/20 09:33:23  sharps
**	IS:6012-539693 Use GS_PRI.SIZE macros
**
**	Revision 1.44  2013/01/28 10:05:44  guptans
**	IS:6012-367102 Added rStrIStr
**	
**	Revision 1.43  2012/11/16 14:56:27  chex
**	IS:6012-345049 remove unused backout
**	
**	Revision 1.42  2012/09/13 15:47:21  chex
**	IS:6012-345049 remove string.h since it builds just fine without it
**	
**	Revision 1.41  2012/09/12 19:59:23  chex
**	IS:6012-345049 string.c is included in autofunc's build. Use getenv when building autofunc and backout when building others
**	
**	Revision 1.40  2012/09/11 19:56:23  chex
**	IS:6012-345049 use strcasestr to do case-insensitive string search on Linux
**	
**	Revision 1.39  2010/10/07 14:27:02  uschoj
**	IS:6012-132636 Make it build on linux64_g4
**	
**	Revision 1.38  2010/06/01 11:47:45  keatlj
**	IS:6012-93680 show kool_ade on the heap
**	
**	Revision 1.37  2009/02/24 16:23:09  uschoj
**	IS:6012-18954 gcc4 fixes
**	
**	Revision 1.36  2007/10/30 16:41:12  burchk
**	IS:822506 Remove StrToUpper and StrToLower, since we already have StrLower
**	and StrUpper
**	
****************************************************************/

// Need this test so it can build in autofunc (grrrr)
#ifndef BUILDING_KOOL_ADE
#define BUILDING_KOOL_ADE
#endif

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#define INCL_ALLOCA
#define INCL_FILEIO
#include <portable.h>
#include <portable/gsinttypes.h>

#include <cctype>
#include <cstdarg>
#include <cstdlib>
#include <strings.h>

#include <err.h>
#include <kool_ade.h>

#include <vccrtdbg.h>

/****************************************************************
**	Routine: StrIStr
**	Returns: Pointer to first occurrence of String2 in String1
**	Summary: Case insensitive strstr function
**	Action : Case insensitive strstr function
****************************************************************/

char *StrIStr(
	register char	*String1,
	const char		*String2
)
{
#if CC_OS == CC_OS_UNIX && CC_UNIX_REV == CC_UNIX_LINUX
		return !*String2 ? 0 : strcasestr( String1, String2 );
#endif

	register char	
			Lower = (char)tolower(*String2),
			Upper = (char)toupper(*String2);

	size_t	Len   = strlen(String2);

	if( !Len )
		return NULL;
	
	for( ; *String1; String1++)
		if( *String1 == Lower || *String1 == Upper )
			if( strncasecmp( String1+1, String2+1, Len-1 ) == 0 )
				return String1;

	return NULL;
}



/****************************************************************
**	Routine: rStrIStr
**	Returns: pointer to last occurrence of String2 in String1 < Pos
**	Action : case insensitive rstrstr function
****************************************************************/

char *rStrIStr(
	char		*String1,
	int			 Limit,
	char const	*String2
)
{
	char	*Prev = NULL,
			*Curr,
			*CutOff = String1 + Limit - strlen( String2 ) + 1;

	while( TRUE )
	{
		Curr = StrIStr( String1, String2 );
		if( !Curr || Curr > CutOff )
			break;
		Prev = Curr;
		String1 = Curr + 1;
	}
	return( Prev );
}

/****************************************************************
**	Routine: StrPaste
**	Returns: Allocated string
**	Summary: Paste a bunch of strings together
**	Action : StrPaste pastes a list of strings together into one
**			 allocated string.  StrPaste( "a", "b", "c", NULL )
**			 returns "abc".
**			 NOTE: Final argument MUST be NULL
**			 NOTE: The returned string must be free()d later.
****************************************************************/

char *StrPaste(
	const char	*First,
	...
)
{
	va_list	Marker;

	size_t	Len;

	char	*Output,
			*Pos;

	const char
			*Arg;


	Len = 0;
	va_start( Marker, First );
	for( Arg = First; Arg; Arg = va_arg( Marker, const char *))
		Len += strlen( Arg );
	va_end( Marker );

	Output = Pos = (char *)malloc( Len+1 );
	va_start( Marker, First );
	for( Arg = First; Arg; Arg = va_arg( Marker, const char *))
	{
		strcpy( Pos, Arg );
		Pos += strlen( Pos );
	}
	va_end( Marker );
	
	return Output;
}



/****************************************************************
**	Routine: StrReplace
**	Returns: Allocated, substituted string
**	Summary: Simple substring replacement
**	Action : StrReplace is a simple substring replace function
**			 which replaces SubStr within Input with Replace.
**			 Flags is a combination of the following values:
**				REPL_GLOBAL		- Global replace within Input
**				REPL_FREE		- Free Input argument
**				REPL_CASE		- Case sensitive search
**								  (Default is to ignore case)
**			 The REPL_FREE flag allow multiple calls to StrReplace
**			 to be easily chained.
**				Str = StrReplace( Str, "Foo", "Bar", REPL_FREE );
**				Str = StrReplace( Str, "Cow", "Pig", REPL_FREE );
****************************************************************/

char *StrReplace(
	char		*Input,
	const char	*SubStr,
	const char	*Replace,
	int			Flags
)
{
	size_t	SubLen = strlen( SubStr ),
			RepLen = strlen( Replace );

	char	*InPos,
			*Tmp,
			*Found,
			*Output;

	size_t	OutLen = 0,
			NewLen,
			InLen;


	InPos = Input;
	Output = strdup( "" );
	while( 1 )
	{
		if( Flags & REPL_CASE )
			Found = strstr( InPos, SubStr );
		else
			Found = StrIStr( InPos, SubStr );
		if( !Found )
		{
			OutLen += strlen( InPos );
			Output = (char *)realloc( Output, OutLen + 1 );
			strcat( Output, InPos );
			break;
		}
		InLen	= static_cast<size_t>( Found - InPos );
		NewLen	= OutLen + InLen + RepLen;
		Output	= (char *)realloc( Output, NewLen + 1 );
		Tmp = Output + OutLen;
		strncpy( Tmp, InPos, InLen );
		strcpy( Tmp+InLen, Replace );

		InPos   = Found + SubLen;
		OutLen  = NewLen;

		if( !(Flags & REPL_GLOBAL) )
		{
			OutLen += strlen( InPos );
			Output = (char *)realloc( Output, OutLen + 1 );
			strcat( Output, InPos );
			break;
		}
	}

	if( Flags & REPL_FREE )
		free( Input );
	return Output;
}



/****************************************************************
**	Routine: StrWildMatch
**	Returns: TRUE  - String matches Pattern
**			 FALSE - no match
**	Action : Perform wildcard match using '*' and '?'
****************************************************************/

int StrWildMatch(
	const char	*Pattern,
	const char	*String
)
{
	int		Pat,
			Str;


	while( 0 != (Pat = *Pattern ))
	{
		if( Pat == '*' )
		{
			Pattern++;
			if( !*Pattern )
				return TRUE;

			for( ; *String; String++ )
				if( StrWildMatch( Pattern, String ))
					return TRUE;
			return FALSE;
		}
		if( Pat == '?' )
		{
			Pattern++;
			String++;
			continue;
		}
		if( !(Str = *String ))
			return FALSE;

		if( toupper( Pat ) != toupper( Str ) )
			return FALSE;

		Pattern++;
		String++;
	}
	return *Pattern == *String;
}



/****************************************************************
**	Routine: StrRTrim
**	Returns: String pointer passed in
**	Summary: Trim trailing spaces in place
**	Action : StrRTrim trims spaces from the right end of a
**			 string.  The string is modified in place.
**	Example: // Modify a copy of a string
**			 Copy = StrRTrim( strdup( "a string   " ));
**
**			 // Modify a string in place
**			 InPlace = StrRTrim( "another string   " );
****************************************************************/

char *StrRTrim(
	char	*Str
)
{
	ssize_t	Pos;
    	
	for( Pos = static_cast<ssize_t>( strlen( Str ) ); --Pos >= 0 && isspace( Str[ Pos ] ); );

	if( isspace( Str[ Pos + 1 ] ) )
		Str[ Pos + 1 ] = '\0';

	return Str;
}



/****************************************************************
**	Routine: StrLTrim
**	Returns: String passed in
**	Summary: Trim leading spaces in place
**	Action : StrLTrim trims spaces from the left end of a
**			 string.  The string is modified in place.
**	Example: // Modify a copy of a string
**			 Copy = StrLTrim( strdup( "   a string" ));
**
**			 // Modify a string in place
**			 InPlace = StrLTrim( "   another string" );
****************************************************************/

char *StrLTrim(
	char	*Str
)
{
	char	*FirstNonSpace;
	
	
	for( FirstNonSpace = Str; isspace( *FirstNonSpace ); FirstNonSpace++ );

	if( FirstNonSpace != Str )
		memmove( Str, FirstNonSpace, strlen( FirstNonSpace ) + 1 );

	return Str;
}



/****************************************************************
**	Routine: StrBegins
**	Returns: TRUE or FALSE
**	Summary: Does Str begin with BegStr?
**	Action : Compare the beginning of Str with EndStr and return
**			 TRUE if they match.
**	Example: // These are TRUE
**			 StrBegins( "Long String",	"Long" );
**			 StrBegins( "Long String",	"Long String" );
**
**			 // These are FALSE
**			 StrBegins( "Long String",	"long" );
**			 StrBegins( "Long",			"Long String" );
**	SeeAlso: StrEnds, StrIBegins, StrIEnds
****************************************************************/

int StrBegins(
	const char	*Str,
	const char	*BegStr
)
{
	size_t	Len1 = strlen( Str ),
			Len2 = strlen( BegStr );


	if( Len1 < Len2 )
		return FALSE;
	return 0 == strncmp( Str, BegStr, Len2 );
}



/****************************************************************
**	Routine: StrEnds
**	Returns: TRUE or FALSE
**	Summary: Does Str end with EndStr?
**	Action : Compare the end of Str with EndStr and return TRUE
**			 if they match.
**	Example: // These are TRUE
**			 StrEnds( "Long String",	"ing" );
**			 StrEnds( "Long String",	"Long String" );
**
**			 // These are FALSE
**			 StrEnds( "Long String",	"string" );
**			 StrEnds( "ing",			"Long String" );
**	SeeAlso: StrBegins, StrIBegins, StrIEnds
****************************************************************/

int StrEnds(
	const char	*Str,
	const char	*EndStr
)
{
	size_t	Len1 = strlen( Str ),
			Len2 = strlen( EndStr );


	if( Len1 < Len2 )
		return FALSE;
	return 0 == strcmp( Str + Len1 - Len2, EndStr );
}



/****************************************************************
**	Routine: StrIBegins
**	Returns: TRUE or FALSE
**	Summary: Does Str begin with BegStr?
**	Action : Compare the beginning of Str with EndStr and return
**			 TRUE if they match.
**	Example: // These are TRUE
**			 StrIBegins( "Long String",	"Long" );
**			 StrIBegins( "Long String",	"Long String" );
**			 StrIBegins( "Long String",	"long" );
**
**			 // These are FALSE
**			 StrIBegins( "Long",		"Long String" );
**	SeeAlso: StrBegins, StrIEnds, StrIEnds
****************************************************************/

int StrIBegins(
	const char	*Str,
	const char	*BegStr
)
{
	size_t	Len1 = strlen( Str ),
			Len2 = strlen( BegStr );


	if( Len1 < Len2 )
		return FALSE;
	return 0 == strncasecmp( Str, BegStr, Len2 );
}



/****************************************************************
**	Routine: StrIEnds
**	Returns: TRUE or FALSE
**	Summary: Does Str end with EndStr?
**	Action : Compare the end of Str with EndStr and return TRUE
**			 if they match.
**	Example: // These are TRUE
**			 StrIEnds( "Long String",	"ing" );
**			 StrIEnds( "Long String",	"Long String" );
**			 StrIEnds( "Long String",	"string" );
**
**			 // These are FALSE
**			 StrIEnds( "ing",			"Long String" );
**	SeeAlso: StrBegins, StrEnds, StrIBegins
****************************************************************/

int StrIEnds(
	const char	*Str,
	const char	*EndStr
)
{
	size_t	Len1 = strlen( Str ),
			Len2 = strlen( EndStr );


	if( Len1 < Len2 )
		return FALSE;
	return 0 == strcasecmp( Str + Len1 - Len2, EndStr );
}



/****************************************************************
**	Routine: StrChrCount
**	Returns: Count occurrences of characters
**	Action : Returns the number of occurrences of characters
**			 from CharSet in String
**
**			 You can set End == -1 to mean end of string
****************************************************************/

size_t StrChrCount(
	const char	*String,
	const char	*CharSet,
	ssize_t		Start,
	ssize_t		End
)
{
	size_t Len = strlen( String );
	size_t Count = 0;

	const char *StrEnd;

	if( End < 0 || static_cast<size_t>( End ) > Len )
		End = static_cast<ssize_t>( Len );
	if( Start < 0 )
		Start = 0;
	if( static_cast<size_t>( Start ) >= Len )
		return 0;

	StrEnd = String + End;
	for( String += Start; ( String += strcspn( String, CharSet ) ) < StrEnd && *String; ++String )
		++Count;

	return Count;	
}



/****************************************************************
**	Routine: StrTokenize
**	Returns: Count of tokens found, -1 on error
**	Action : Parse a space/quote delimited line, ala slang.dat.
**			 Modifies String and fills in Tokens with pointers
**			 to each token in String.
**
**			 Handles spaces, tabs, and quoted strings.  Ignores
**			 comments starting with //.  A blank line or a line
**			 with only a comment returns a token count of zero.
**			 
**	Example: char	*Tokens[ 9 ],
**					Example[] = "Example\t\"quoted text\"  foo";
**			 StrTokenize( Example, 8, Tokens );
****************************************************************/

int StrTokenize(
	char	*String,	// Input string (will be modified)
	int		MaxTokens,
	char	**Tokens	// [ MaxTokens+1 ]  NULL terminated on return
)
{
	int		TokenCount = 0;


	while( *String  )
	{
		// Skip spaces and tabs
		while( *String && ISSPACE( *String ))
			String++;

		// Check for blank field or comment
		if( *String == '\0' || ( *String == '/' && String[1] == '/' ))
			break;

		// Check for too many tokens
		if( TokenCount >= MaxTokens )
		{
			Err( ERR_INVALID_STRING , "StrTokenize: @, too many tokens [max: %d]", MaxTokens );
			return -1;
		}

		// Parse quoted or non-quoted field
		if( *String == '"' )
		{
			String++;
			Tokens[ TokenCount++ ] = String;
			while( *String && *String != '"' )
				String++;
			if( *String != '"' )
			{
				Err( ERR_INVALID_STRING , "StrTokenize: @, missing closing double quote" );
				return -1;
			}
			*String++ = '\0';
		}
		else
		{
			Tokens[ TokenCount++ ] = String;
			while( *String && !ISSPACE( *String ))
				String++;
			if( *String )
				*String++ = '\0';
		}
	}
	Tokens[ TokenCount ] = NULL;
	return TokenCount;
}



/****************************************************************
**	Routine: StrQuoteUrl
**	Returns: allocated string quoted for URL display
**	Action : Quote URL special characters
****************************************************************/

char *StrQuoteUrl(
	const char	*Str
)
{
	char    *NewStr,
			*NewStrBuf,
			c;


	NewStr = NewStrBuf = (char *) malloc( strlen( Str ) * 3 + 1 );

	while( (c = *Str++) )
		switch( c )
		{
			case ' ':
				*NewStr++ = '+';
				break;

			case '/':
			case '%':
			case '+':
			case '#':
			case '?':
			case ',':
			case ':':
			case '&':
			case '"':
			case '\'':
				NewStr += sprintf( NewStr, "%%%02x", c );
				break;

			default:
				*NewStr++ = c;
				break;
		};

	*NewStr++ = '\0';

	return NewStrBuf;
}



/****************************************************************
**	Routine: StrQuoteHtml
**	Returns: allocated string quoted for HTML display
**	Action : Quote HTML special characters
****************************************************************/

char *StrQuoteHtml(
	const char	*HtmlStr
)
{
	const char *Str;

	char *NewStr;
	char *NewStrBuf;

	size_t NewLen = 1;

	for( Str = HtmlStr; *Str != '\0'; ++Str )
	{
		switch( *Str )
		{
			case '<':
			case '>':
			case '&':
			case '"':
				NewLen += 6;		// Largest of the replacement strings
				break;
			default:
				NewLen++;
				break;
		}
	}
	NewStr = (char *) alloca( NewLen+1 );
	NewStrBuf = NewStr;
	for( Str = HtmlStr; *Str != '\0'; ++Str )
	{
		char const* AppendMe = NULL;

		switch( *Str )
		{
			case '<':	AppendMe = "&lt;";	break;
			case '>':	AppendMe = "&gt;";  break;
			case '&':	AppendMe = "&amp;";  break;
			case '"':	AppendMe = "&quot;";  break;
			default:
				*NewStr++ = *Str;
				break;
		}
		if( AppendMe )
		{
			strcpy( NewStr, AppendMe );
			NewStr += strlen( NewStr );
		}
	}
	*NewStr = '\0';

	return strdup( NewStrBuf );
}


static int hexToInt( char hex )
{
	if( hex >= '0' && hex <= '9' )
		return( hex - '0' );
	if( hex >= 'A' && hex <= 'F' )
		return( hex - 'A' + 10 );
	if( hex >= 'a' && hex <= 'f' )
		return( hex - 'a' + 10 );
	return -1;
}


/****************************************************************
**	Routine: StrFromUrl
**	Returns: allocated string
**	Action : Convert a URL-quoted string to a plain string
****************************************************************/

char *StrFromUrl(
	const char *Str		// URL-quoted string (w/ + & %20
)
{
	char	*NewStr,
			*NewStrBuf,
			c;

	NewStr = NewStrBuf = (char *) malloc( strlen( Str ) + 1 );

	while( (c = *Str++) )
		switch( c )
		{
			case '%':
				if( *Str && *(Str + 1) && isxdigit( *Str ) && isxdigit( *(Str + 1) ) )
				{
					*NewStr++ = (char) (0x10 * hexToInt( *Str ) + hexToInt( *(Str + 1) ) );
					Str += 2;
				}
				else
					*NewStr++ = '%';
				break;

			case '+':
				*NewStr++ = ' ';
				break;

			default:
				*NewStr++ = c;
				break;
		};

	*NewStr++ = '\0';

	return NewStrBuf;
}


/****************************************************************
**	Routine: StrBaseName
**	Returns: Pointer to file part of Path
**	Action : Returns string following final file separator.  If
**           finds none, return Path
**  Params : Path - Path passed as String
****************************************************************/
const char *StrBaseName( 
    const char *Path
)
{
    const char 
            *p, 
            *d;

    if( !Path )
        return( NULL );

    for( p = Path + strlen( Path ); p >= Path; p-- )
        for( d = FILENAME_SEPARATORS; *d; d++ )
            if( *p == *d )
                return( p+1 );

    return( Path );
}



/****************************************************************
**	Routine: StringToUniqueId
**	Returns: uint32 from input string, or 0 on error
**	Action : Convert numeric string to unique id. 0 is not a valid unique id
**			 so return that on error.
**			 NOTE: This is not intended as a general purpose conversion routine:
**			 it's specific to secdb unique IDs.
****************************************************************/

uint32_t StringToUniqueId(
	const char *Str
)
{
	size_t Len = strlen( Str );

	// String must not be blank, or > 10 chars (max size of decimal representation of uint32_t)
	if( 0 == Len )
		return static_cast<uint32_t>( Err( ERR_INVALID_ARGUMENTS, "StringToUniqueId: Input string blank" ) );

	const size_t MaxLen = 10;

	if( Len > MaxLen )
		return static_cast<uint32_t>( Err( ERR_INVALID_ARGUMENTS, "StringToUniqueId: Input string ('%s') too long (%" GS_PRIuSIZE ">%" GS_PRIuSIZE "d)", Str, Len, MaxLen ) );

	// Must be digits only
	for( const char *p = Str; *p; ++p )
		if( !ISDIGIT( *p ) )
			return static_cast<uint32_t>( Err( ERR_INVALID_ARGUMENTS, "StringToUniqueId: Input string ('%s') contains non-digit %c", Str, *p ) );

	uint32_t Id;

	if( 1 != sscanf( Str, "%u", &Id ) )
		return static_cast<uint32_t>( Err( ERR_INVALID_ARGUMENTS, "StringToUniqueId: Failed to parse input string ('%s')", Str ) );

	// Now check that it matches the input (a bit paranoid)
	char Str1[ MaxLen + 1 ];
	sprintf( Str1, "%u", Id );

	if( strcmp( Str, Str1 ) )
		return static_cast<uint32_t>( Err( ERR_INVALID_ARGUMENTS, "StringToUniqueId: Consistency check failed (input='%s', id=%u, id as string='%s')", Str, Id, Str1 ) );

	return Id;
}
Leave a Comment