habeebi
unknown
plain_text
a year ago
20 kB
7
Indexable
#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 = "<"; break;
case '>': AppendMe = ">"; break;
case '&': AppendMe = "&"; break;
case '"': AppendMe = """; 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;
}
Editor is loading...
Leave a Comment