diff --git a/src/stringobj.c b/src/stringobj.c index c59e3e1879..d12aaae495 100644 --- a/src/stringobj.c +++ b/src/stringobj.c @@ -198,17 +198,17 @@ void LoadChar( Obj c ) /**************************************************************************** ** -*F FuncEmptyString( , ) . . . . . . . empty string with space -* -* Returns an empty string, but with space for len characters preallocated. -* +*F FuncEmptyString( , ) . . . . . . . . empty string with space +** +** Returns an empty string, but with space for len characters preallocated. +** */ Obj FuncEmptyString( Obj self, Obj len ) { Obj new; - while ( ! IS_INTOBJ(len) ) { + while ( ! IS_NONNEG_INTOBJ(len) ) { len = ErrorReturnObj( - " must be an integer (not a %s)", + " must be an non-negative integer (not a %s)", (Int)TNAM_OBJ(len), 0L, "you can replace via 'return ;'" ); } @@ -220,11 +220,11 @@ Obj FuncEmptyString( Obj self, Obj len ) /**************************************************************************** ** -*F FuncShrinkAllocationString( , ) . . give back unneeded memory -* -* Shrinks the bag of to minimal possible size (possibly converts to -* compact representation). -* +*F FuncShrinkAllocationString( , ) . . give back unneeded memory +** +** Shrinks the bag of to minimal possible size (possibly converts to +** compact representation). +** */ Obj FuncShrinkAllocationString( Obj self, Obj str ) { @@ -406,19 +406,22 @@ Obj FuncSTRING_SINTLIST ( * integers ? */ /* general code */ - if (! IS_RANGE(val) ) { - if (! IS_PLIST(val)) { + while (!IS_RANGE(val) && !IS_PLIST(val)) { +again: val = ErrorReturnObj( - " must be a plain list or range, not a %s)", + " must be a plain list of small integers or a range, not a %s", (Int)TNAM_OBJ(val), 0L, "you can replace via 'return ;'" ); - } - + } + if (! IS_RANGE(val) ) { l=LEN_PLIST(val); n=NEW_STRING(l); p=CHARS_STRING(n); for (i=1;i<=l;i++) { - *p++=CHAR_SINT(INT_INTOBJ(ELM_PLIST(val,i))); + Obj x = ELM_PLIST(val,i); + if (!IS_INTOBJ(x)) + goto again; + *p++=CHAR_SINT(INT_INTOBJ(x)); } } else { @@ -434,7 +437,6 @@ Obj FuncSTRING_SINTLIST ( } - CHANGED_BAG(n); return n; } @@ -464,12 +466,10 @@ Obj FuncREVNEG_STRING ( q=CHARS_STRING(n); j=l-1; for (i=1;i<=l;i++) { - /* *q++=CHAR_SINT(-SINT_CHAR(p[j])); */ *q++=-p[j]; j--; } - CHANGED_BAG(n); return n; } @@ -672,7 +672,7 @@ void CleanStringCopy ( void PrintString ( Obj list ) { - char PrStrBuf[10007]; /* 7 for a \c\123 at the end */ + char PrStrBuf[10007]; /* 7 for a \c\123 at the end */ UInt scanout, n; UInt1 c; UInt len = GET_LEN_STRING(list); @@ -682,10 +682,10 @@ void PrintString ( { scanout = 0; do - { - c = CHARS_STRING(list)[off++]; - switch (c) - { + { + c = CHARS_STRING(list)[off++]; + switch (c) + { case '\\': PrStrBuf[scanout++] = '\\'; PrStrBuf[scanout++] = '\\'; @@ -694,35 +694,35 @@ void PrintString ( PrStrBuf[scanout++] = '\\'; PrStrBuf[scanout++] = '\"'; break; - case '\n': - PrStrBuf[scanout++] = '\\'; - PrStrBuf[scanout++] = 'n'; - break; - case '\t': - PrStrBuf[scanout++] = '\\'; - PrStrBuf[scanout++] = 't'; - break; - case '\r': - PrStrBuf[scanout++] = '\\'; - PrStrBuf[scanout++] = 'r'; - break; - case '\b': - PrStrBuf[scanout++] = '\\'; - PrStrBuf[scanout++] = 'b'; - break; - case '\01': - PrStrBuf[scanout++] = '\\'; - PrStrBuf[scanout++] = '>'; - break; - case '\02': - PrStrBuf[scanout++] = '\\'; - PrStrBuf[scanout++] = '<'; - break; - case '\03': - PrStrBuf[scanout++] = '\\'; - PrStrBuf[scanout++] = 'c'; - break; - default: + case '\n': + PrStrBuf[scanout++] = '\\'; + PrStrBuf[scanout++] = 'n'; + break; + case '\t': + PrStrBuf[scanout++] = '\\'; + PrStrBuf[scanout++] = 't'; + break; + case '\r': + PrStrBuf[scanout++] = '\\'; + PrStrBuf[scanout++] = 'r'; + break; + case '\b': + PrStrBuf[scanout++] = '\\'; + PrStrBuf[scanout++] = 'b'; + break; + case '\01': + PrStrBuf[scanout++] = '\\'; + PrStrBuf[scanout++] = '>'; + break; + case '\02': + PrStrBuf[scanout++] = '\\'; + PrStrBuf[scanout++] = '<'; + break; + case '\03': + PrStrBuf[scanout++] = '\\'; + PrStrBuf[scanout++] = 'c'; + break; + default: if (c < 32 || c>126) { PrStrBuf[scanout++] = '\\'; n = c / 64; @@ -735,8 +735,8 @@ void PrintString ( } else PrStrBuf[scanout++] = c; - } - } + } + } while (off < len && scanout < 10000); PrStrBuf[scanout++] = '\0'; Pr( "%s", (Int)PrStrBuf, 0L ); @@ -1084,8 +1084,6 @@ void AssString ( /* now perform the assignment and return the assigned value */ SET_ELM_STRING( list, pos, val ); - /* CHARS_STRING(list)[pos-1] = CHAR_VALUE(val); */ - CHANGED_BAG( list ); } } @@ -1377,7 +1375,6 @@ void ConvString ( ResizeBag( string, SIZEBAG_STRINGLEN(lenString) ); /* copy data area from tmp */ memcpy(ADDR_OBJ(string), CONST_ADDR_OBJ(tmp), SIZE_OBJ(tmp)); - CHANGED_BAG(string); } @@ -1431,17 +1428,6 @@ Obj MakeString2(const Char *cstr1, const Char *cstr2) return result; } -Obj MakeString3(const Char *cstr1, const Char *cstr2, const Char *cstr3) -{ - Obj result; - size_t len1 = strlen(cstr1), len2 = strlen(cstr2), len3 = strlen(cstr3); - result = NEW_STRING(len1 + len2 + len3); - memcpy(CSTR_STRING(result), cstr1, len1); - memcpy(CSTR_STRING(result)+len1, cstr2, len2); - memcpy(CSTR_STRING(result)+len1+len2, cstr3, len3); - return result; -} - Obj MakeImmString2(const Char *cstr1, const Char *cstr2) { Obj result = MakeString2(cstr1, cstr2); @@ -1449,13 +1435,6 @@ Obj MakeImmString2(const Char *cstr1, const Char *cstr2) return result; } -Obj MakeImmString3(const Char *cstr1, const Char *cstr2, const Char *cstr3) -{ - Obj result = MakeString3(cstr1, cstr2, cstr3); - MakeImmutableString(result); - return result; -} - Obj ConvImmString(Obj str) { Obj result; @@ -1511,12 +1490,11 @@ Obj FuncCONV_STRING ( Obj string ) { /* check whether is a string */ - if ( ! IS_STRING( string ) ) { + while ( ! IS_STRING( string ) ) { string = ErrorReturnObj( "ConvString: must be a string (not a %s)", (Int)TNAM_OBJ(string), 0L, "you can replace via 'return ;'" ); - return FuncCONV_STRING( self, string ); } /* convert to the string representation */ @@ -1549,12 +1527,11 @@ Obj FuncCOPY_TO_STRING_REP ( Obj obj ) { /* check whether is a string */ - if (!IS_STRING(obj)) { + while (!IS_STRING(obj)) { obj = ErrorReturnObj( - "ConvString: must be a string (not a %s)", + "CopyToStringRep: must be a string (not a %s)", (Int)TNAM_OBJ(obj), 0L, "you can replace via 'return ;'" ); - return FuncCOPY_TO_STRING_REP( self, obj ); } return CopyToStringRep(obj); } @@ -1645,12 +1622,11 @@ Obj FuncNormalizeWhitespace ( Int i, j, len, white; /* check whether is a string */ - if ( ! IsStringConv( string ) ) { + while ( ! IsStringConv( string ) ) { string = ErrorReturnObj( "NormalizeWhitespace: must be a string (not a %s)", (Int)TNAM_OBJ(string), 0L, "you can replace via 'return ;'" ); - return FuncNormalizeWhitespace( self, string ); } len = GET_LEN_STRING(string); @@ -1701,21 +1677,19 @@ Obj FuncREMOVE_CHARACTERS ( UInt1 REMCHARLIST[256] = {0}; /* check whether is a string */ - if ( ! IsStringConv( string ) ) { + while ( ! IsStringConv( string ) ) { string = ErrorReturnObj( "RemoveCharacters: first argument must be a string (not a %s)", (Int)TNAM_OBJ(string), 0L, "you can replace via 'return ;'" ); - return FuncREMOVE_CHARACTERS( self, string, rem ); } /* check whether is a string */ - if ( ! IsStringConv( rem ) ) { + while ( ! IsStringConv( rem ) ) { rem = ErrorReturnObj( "RemoveCharacters: second argument must be a string (not a %s)", (Int)TNAM_OBJ(rem), 0L, "you can replace via 'return ;'" ); - return FuncREMOVE_CHARACTERS( self, string, rem ); } /* set REMCHARLIST by setting positions of characters in rem to 1 */ @@ -1757,32 +1731,30 @@ Obj FuncTranslateString ( Int j, len; /* check whether is a string */ - if ( ! IsStringConv( string ) ) { + while ( ! IsStringConv( string ) ) { string = ErrorReturnObj( - "RemoveCharacters: first argument must be a string (not a %s)", + "TranslateString: first argument must be a string (not a %s)", (Int)TNAM_OBJ(string), 0L, "you can replace via 'return ;'" ); - return FuncTranslateString( self, string, trans ); } - /* check whether is a string */ - if ( ! IsStringConv( trans ) ) { - trans = ErrorReturnObj( - "RemoveCharacters: second argument must be a string (not a %s)", - (Int)TNAM_OBJ(trans), 0L, - "you can replace via 'return ;'" ); - return FuncTranslateString( self, string, trans ); - } - - /* check if string has length at least 256 */ - if ( GET_LEN_STRING( trans ) < 256 ) { - trans = ErrorReturnObj( - "RemoveCharacters: second argument must have length >= 256", - 0L, 0L, - "you can replace via 'return ;'" ); - return FuncTranslateString( self, string, trans ); + // check whether is a string of length at least 256 + while ( ! IsStringConv( trans ) || GET_LEN_STRING( trans ) < 256 ) { + if ( ! IsStringConv( trans ) ) { + trans = ErrorReturnObj( + "TranslateString: second argument must be a string (not a %s)", + (Int)TNAM_OBJ(trans), 0L, + "you can replace via 'return ;'" ); + } + + if ( GET_LEN_STRING( trans ) < 256 ) { + trans = ErrorReturnObj( + "TranslateString: second argument must have length >= 256", + 0L, 0L, + "you can replace via 'return ;'" ); + } } - + /* now change string in place */ len = GET_LEN_STRING(string); s = CHARS_STRING(string); @@ -1816,30 +1788,27 @@ Obj FuncSplitStringInternal ( UInt1 SPLITSTRINGWSPACE[256] = { 0 }; /* check whether is a string */ - if ( ! IsStringConv( string ) ) { + while ( ! IsStringConv( string ) ) { string = ErrorReturnObj( "SplitString: first argument must be a string (not a %s)", (Int)TNAM_OBJ(string), 0L, "you can replace via 'return ;'" ); - return FuncSplitStringInternal( self, string, seps, wspace ); } /* check whether is a string */ - if ( ! IsStringConv( seps ) ) { + while ( ! IsStringConv( seps ) ) { seps = ErrorReturnObj( "SplitString: second argument must be a string (not a %s)", (Int)TNAM_OBJ(seps), 0L, "you can replace via 'return ;'" ); - return FuncSplitStringInternal( self, string, seps, wspace ); } /* check whether is a string */ - if ( ! IsStringConv( wspace ) ) { + while ( ! IsStringConv( wspace ) ) { wspace = ErrorReturnObj( "SplitString: third argument must be a string (not a %s)", (Int)TNAM_OBJ(wspace), 0L, "you can replace via 'return ;'" ); - return FuncSplitStringInternal( self, string, seps, wspace ); } /* set SPLITSTRINGSEPS by setting positions of characters in rem to 1 */ diff --git a/src/stringobj.h b/src/stringobj.h index b511226fc4..4a04ee8462 100644 --- a/src/stringobj.h +++ b/src/stringobj.h @@ -367,10 +367,8 @@ static inline Obj MakeImmString(const Char * cstr) Obj MakeString2(const Char *cstr1, const Char *cstr2); -Obj MakeString3(const Char *cstr1, const Char *cstr2, const Char *cstr3); Obj MakeImmString2(const Char *cstr1, const Char *cstr2); -Obj MakeImmString3(const Char *cstr1, const Char *cstr2, const Char *cstr3); Obj ConvImmString(Obj str); diff --git a/tst/testinstall/kernel/stringobj.tst b/tst/testinstall/kernel/stringobj.tst new file mode 100644 index 0000000000..54f315d91e --- /dev/null +++ b/tst/testinstall/kernel/stringobj.tst @@ -0,0 +1,126 @@ +# +# Tests for functions defined in src/strinobj.c +# +gap> START_TEST("kernel/strinobj.tst"); + +# +gap> s := EmptyString(2); +"" +gap> EmptyString(-1); +Error, must be an non-negative integer (not a integer) + +# +gap> ShrinkAllocationString(s); +gap> ShrinkAllocationString(1); +Error, must be a string, not a integer) + +# +gap> CHAR_INT(fail); +Error, must be an integer (not a boolean or fail) +gap> CHAR_INT(-1); +Error, must be an integer between 0 and 255 +gap> CHAR_INT(65); +'A' + +# +gap> INT_CHAR(1); +Error, must be a character (not a integer) +gap> INT_CHAR('A'); +65 + +# +gap> CHAR_SINT(fail); +Error, must be an integer (not a boolean or fail) +gap> CHAR_SINT(255); +Error, must be an integer between -128 and 127 +gap> CHAR_SINT(65); +'A' + +# +gap> SINT_CHAR(1); +Error, must be a character (not a integer) +gap> SINT_CHAR('A'); +65 + +# +gap> INTLIST_STRING("ABC", 1); +[ 65, 66, 67 ] +gap> INTLIST_STRING("ABC", -1); +[ 65, 66, 67 ] +gap> INTLIST_STRING(1, -1); +Error, must be a string, not a integer) + +# +gap> SINTLIST_STRING("ABC"); +[ 65, 66, 67 ] +gap> SINTLIST_STRING(1); +Error, must be a string, not a integer) + +# +gap> STRING_SINTLIST([ 65, 66, 67 ]); +"ABC" +gap> STRING_SINTLIST([ 65 .. 67 ]); +"ABC" +gap> STRING_SINTLIST(1); +Error, must be a plain list of small integers or a range, not a integer +gap> STRING_SINTLIST([ 'B' ]); +Error, must be a plain list of small integers or a range, not a list (pl\ +ain,hom) + +# +gap> REVNEG_STRING(1); +Error, must be a string, not a integer) + +# +gap> CONV_STRING(1); +Error, ConvString: must be a string (not a integer) + +# +gap> COPY_TO_STRING_REP(1); +Error, CopyToStringRep: must be a string (not a integer) + +# +gap> POSITION_SUBSTRING("abc","b",0); +2 +gap> POSITION_SUBSTRING("abc","b",3); +fail +gap> POSITION_SUBSTRING("abc","x",3); +fail +gap> POSITION_SUBSTRING(1,2,3); +Error, POSITION_SUBSTRING: must be a string (not a integer) +gap> POSITION_SUBSTRING("abc",2,3); +Error, POSITION_SUBSTRING: must be a string (not a integer) +gap> POSITION_SUBSTRING("abc","b",-1); +Error, POSITION_SUBSTRING: must be a non-negative integer (not a integer\ +) + +# +gap> s:=" abc\n xyz\n";; NormalizeWhitespace(s); s; +"abc xyz" +gap> NormalizeWhitespace(1); +Error, NormalizeWhitespace: must be a string (not a integer) + +# +gap> s:="abcdabcd";; REMOVE_CHARACTERS(s, "db"); s; +"acac" +gap> REMOVE_CHARACTERS(1,1); +Error, RemoveCharacters: first argument must be a string (not a integ\ +er) +gap> REMOVE_CHARACTERS(s,1); +Error, RemoveCharacters: second argument must be a string (not a integer\ +) + +# +gap> s:="abc";; TranslateString(s,UPPERCASETRANSTABLE); s; +"ABC" +gap> TranslateString(1,1); +Error, TranslateString: first argument must be a string (not a intege\ +r) +gap> TranslateString("abc",1); +Error, TranslateString: second argument must be a string (not a intege\ +r) +gap> TranslateString("abc","def"); +Error, TranslateString: second argument must have length >= 256 + +# +gap> STOP_TEST("kernel/strinobj.tst", 1);