diff options
Diffstat (limited to 'src/SString.c')
-rw-r--r-- | src/SString.c | 196 |
1 files changed, 178 insertions, 18 deletions
diff --git a/src/SString.c b/src/SString.c index 63aa8c5..b0b1477 100644 --- a/src/SString.c +++ b/src/SString.c @@ -24,10 +24,13 @@ typedef enum { MAKE_NULL_ALLOC, NEW_NULL_ALLOC, BUFFER_NULL_ALLOC } SSTRING_ERROR; static void String_HandleSeriousError( SSTRING_ERROR ); +#define LINE_END_BUFSIZE 3 + typedef struct String_tag { size_t length; SSCHAR *chars; + SSCHAR line_end[LINE_END_BUFSIZE]; } String_placeholder; static SSCHAR kLineEndChar = '\n'; @@ -45,6 +48,14 @@ StringGetBuffer( const String * s ) { return s->chars; } + +void +StringCopyBuffer( const String * s, SSCHAR * buf, size_t bufSize ) +{ + strncpy( buf, s->chars, bufSize ); + buf[bufSize-1] = '\0'; +} + /* * Returns 0 if index is not in the string */ @@ -83,6 +94,7 @@ String_Make( const SSCHAR * c_string ) } else BufferForThisManyChars( s, 0 ); + s->line_end[0] = kLineEndChar; } else String_HandleSeriousError( MAKE_NULL_ALLOC ); @@ -95,7 +107,11 @@ String_Make( const SSCHAR * c_string ) String * String_Copy( const String * other ) { - return StringSetToCString( String_New(), StringGetBuffer( other ) ); + String *s = StringSetToCString( String_New(), + StringGetBuffer( other ) ); + memcpy( s->line_end, other->line_end, LINE_END_BUFSIZE + * sizeof( SSCHAR ) ); + return s; } void @@ -118,6 +134,23 @@ StringTruncate( String * s, size_t n ) } String * +StringTrimLeading( String * s, size_t n ) +{ + const size_t orig_len = StringLength( s ); + + if( orig_len > 0 && n > 0 ) + { + const size_t position = MIN( orig_len, n ) - 1; + const size_t new_len = orig_len - position; + + memmove( 0, s->chars + position, new_len ); + s->chars[new_len] = '\0'; + s->length = new_len; + } + return s; +} + +String * StringSetNthChar( String * s, size_t n, SSCHAR c ) { if( n < s->length ) @@ -168,6 +201,31 @@ StringSetToCString( String * s, const SSCHAR *c_string ) return StringSetToBuffer( s, c_string, strlen( c_string ) ); } +size_t +StringSetNextToken( const String *s, String *token, + const SSCHAR *delim, size_t start ) +{ + if( start < s->length ) + { + const size_t ndelims = strlen( delim ); + size_t next = s->length; + size_t d; + + for( d = 0; d < ndelims; d++ ) + { + size_t nextDelim = start; + if( StringFindCharFrom( s, delim[d], &nextDelim ) ) + next = MIN( nextDelim, next ); + } + + StringSetRange( token, s, start, next - start ); + + return next < s->length ? next + 1 : next; + } + else + return 0; +} + String * StringConcatCString( String * s, const SSCHAR *c_string ) { @@ -183,13 +241,11 @@ String * StringSetToBuffer( String * s, const SSCHAR *buf, size_t len ) { if( s != NULL && buf != NULL ) - { if( BufferForThisManyChars( s, len ) ) { strncpy( s->chars, buf, len ); s->chars[ len ] = '\0'; } - } return s; } @@ -198,17 +254,31 @@ StringSet( String * s, const String * other ) { return StringSetToCString( s, StringGetBuffer( other ) ); } - +/* + * Take care! What if this String's buffer is the same as the other's? + * For now, this can happen only if the other String is the same as this + * String. + * + * This needs thought for every String that takes a String argument, + * and for the ones that take C strings as well. + */ String * -StringSetSubString( String * s, const String * other, - size_t first, size_t last ) +StringSetRange( String * s, const String * other, + size_t first, size_t length ) { const size_t other_length = other->length; - const size_t veryFirst = MIN( MIN( first, last ), other_length ), - veryLast = MIN( MAX( first, last ), other_length ), - length = ( veryLast + 1 ) - veryFirst; + const size_t veryFirst = MIN( first + 1, other_length ) - 1, + minLength = MIN( first + length, other_length ), + newLength = minLength - veryFirst; - return StringSetToBuffer( s, other->chars + veryFirst, length ); + return StringSetToBuffer( s, other->chars + veryFirst, newLength ); +} + +String * +StringSetToPartAfter( String * s, const String * other, size_t position ) +{ + return StringSetRange( s, other, + position + 1, StringLength( other ) - position ); } /* @@ -217,7 +287,7 @@ StringSetSubString( String * s, const String * other, * On output, is position where char was found. */ SSBOOL -StringFindChar( const String *s, SSCHAR theChar, size_t * position ) +StringFindCharFrom( const String *s, SSCHAR theChar, size_t * position ) { SSCHAR * charPtr; @@ -234,7 +304,7 @@ StringFindChar( const String *s, SSCHAR theChar, size_t * position ) } SSBOOL -StringFindSubString( const String * s, const String * other, +StringFindStringFrom( const String * s, const String * other, size_t * position ) { SSCHAR * charPtr; @@ -362,9 +432,10 @@ StringConcat( String * s, const String * other ) * On unix the default \n works; on the Mac, you might want \r */ void -String_SetLineEndCharacter( SSCHAR c ) +String_SetLineEndCharacter( String * s, const SSCHAR *end ) { - kLineEndChar = c; + strncpy( s->line_end, end, LINE_END_BUFSIZE ); + s->line_end[LINE_END_BUFSIZE - 1] = '\0'; } String * @@ -425,12 +496,101 @@ StringConcatDouble( String * s, double d ) snprintf( buf, sizeof( buf ), "%f", d ); return StringConcatCString( s, buf ); } +/*a + * + * 0) It's inappropritate to handle string and character convesions. + * And there are some very specific-use conversions, such as 't' + * + * 1) I'm not sure I completely understand all the conversions. + * specifically, I don't get G and g. + * + * 2) There are several standards, including C99 and SUSv2 + * + * 3) I haven't done long long or long double + * + * 4) Mixed up notions of unsigned with hex and octal...wrong? + * + * + * + */ +static void +addNumericMods( char * format, SSFORMAT f ) +{ + strcat( format, "%" ); + if( f & SFMT_LEFT_ALIGN ) + strcat( format, "-" ); + if( f & SFMT_PRINT_SIGN ) + strcat( format, "+" ); + if( f & SFMT_ADD_SIGN_SPACE ) + strcat( format, " " ); + if( f & SFMT_PAD_ZERO ) + strcat( format, "0" ); + if( f & SFMT_ALT ) + strcat( format, "#" ); +} +#define EMPTYSTRING { '\0' } +String * +StringConcatFormattedDecimal( String *s, long int d, + int width, int precision, SSINT_FORMAT f ) +{ + char buf[DECIMALBUFSIZE] = EMPTYSTRING; + char format[16] = EMPTYSTRING; + addNumericMods( format, f ); + strcat( format, "*.*ld" ); + snprintf( buf, sizeof( buf ), format, width, precision, d ); + return StringConcatCString( s, buf ); +} String * -StringConcatFormattedDouble( String * s, int ndigits, int ndec, double d ) -{ - char buf[DECIMALBUFSIZE] = { '\0' }; - snprintf( buf, sizeof( buf ), "%*.*f", ndigits, ndec, d ); +StringConcatFormattedUnsigned( String *s, unsigned long int n, + int width, int precision, SSINT_FORMAT f ) +{ + char buf[DECIMALBUFSIZE] = EMPTYSTRING; + char format[16] = EMPTYSTRING; + addNumericMods( format, f ); + strcat( format, "*.*l" ); + if( f & SFMT_HEX ) + { + if( f & SFMT_LOWERCASE ) + strcat( format, "x" ); + else + strcat( format, "X" ); + } + else if( f & SFMT_OCTAL ) + strcat( format, "o" ); + else + strcat( format, "u" ); + snprintf( buf, sizeof( buf ), format, width, precision, n ); + return StringConcatCString( s, buf ); +} + +String * +StringConcatFormattedDouble( String *s, double d, + int width, int precision, SSDOUBLE_FORMAT f ) +{ + char buf[DECIMALBUFSIZE] = EMPTYSTRING; + char format[16] = EMPTYSTRING; + addNumericMods( format, f ); + if( f & SFMT_ALWAYS_POINT ) + strcat( format, "#" ); + strcat( format, "*.*" ); + if( f & SFMT_EXPONENTIAL ) + { + if( f & SFMT_LOWERCASE ) + strcat( format, "e" ); + else + strcat( format, "E" ); + } + if( f & SFMT_DISCRETIONARY_EXP ) + { + if( f & SFMT_LOWERCASE ) + strcat( format, "g" ); + else + strcat( format, "G" ); + } + else + strcat( format, "f" ); + snprintf( buf, sizeof( buf ), format, width, precision, d ); return StringConcatCString( s, buf ); } |