Skip to content

Commit

Permalink
Fix escaping Strings in ViewString
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisJefferson committed Oct 14, 2019
1 parent 2c596b3 commit f96cb02
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 9 deletions.
2 changes: 1 addition & 1 deletion lib/list.gi
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ local str,ls, i;
fi;

if IsString( list ) then
return Concatenation("\"", list, "\"");
return Concatenation(CHUNK_ESCAPE_STRING(list));
fi;

# make strings for objects in l
Expand Down
60 changes: 53 additions & 7 deletions src/stringobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "error.h"
#include "gaputils.h"
#include "io.h"
#include "listfunc.h"
#include "lists.h"
#include "modules.h"
#include "opers.h"
Expand Down Expand Up @@ -529,8 +530,11 @@ static Obj CopyString(Obj list, Int mut)
/****************************************************************************
**
*F PrintString(<list>) . . . . . . . . . . . . . . . . . . . print a string
*F FuncCHUNK_ESCAPE_STRING(<list>) . . . . . . . escape a string as a string
**
** 'PrintString' prints the string with the handle <list>.
** 'CHUNK_ESCAPE_STRING' returns a list of strings which, when concatenated,
** produce a String containing what PrintString outputs.
**
** No linebreaks are allowed, if one must be inserted anyhow, it must
** be escaped by a backslash '\', which is done in 'Pr'.
Expand All @@ -542,14 +546,36 @@ static Obj CopyString(Obj list, Int mut)
** characters. The function can be used to print *any* string in a way
** which can be read in by GAP afterwards.
*/
void PrintString(Obj list)

// Type of function given to OutputStringGeneric
typedef void StringOutputterType(void * data, char * strbuf, UInt len);

// Output using Pr
void ToPrOutputter(void * data, char * strbuf, UInt len)
{
strbuf[len++] = '\0';
Pr("%s", (Int)strbuf, 0L);
}

// Output to a list of Strings
void ToStringOutputter(void * data, char * strbuf, UInt len)
{
Obj list = (Obj)data;

strbuf[len++] = '\0';
AddPlist(list, MakeImmString(strbuf));
CHANGED_BAG(list);
}

void OutputStringGeneric(Obj list, StringOutputterType func, void * data)
{
char PrStrBuf[10007]; /* 7 for a \c\123 at the end */
UInt scanout, n;
UInt scanout = 0, n;
UInt1 c;
UInt len = GET_LEN_STRING(list);
UInt off = 0;
Pr("\"", 0L, 0L);
PrStrBuf[scanout++] = '\"';
func(data, PrStrBuf, scanout);
while (off < len) {
scanout = 0;
do {
Expand Down Expand Up @@ -606,12 +632,32 @@ void PrintString(Obj list)
PrStrBuf[scanout++] = c;
}
} while (off < len && scanout < 10000);
PrStrBuf[scanout++] = '\0';
Pr("%s", (Int)PrStrBuf, 0L);
func(data, PrStrBuf, scanout);
}
Pr("\"", 0L, 0L);
scanout = 0;
PrStrBuf[scanout++] = '\"';
func(data, PrStrBuf, scanout);
}

void PrintString(Obj list)
{
OutputStringGeneric(list, ToPrOutputter, (void *)0);
}

Obj FuncCHUNK_ESCAPE_STRING(Obj self, Obj string)
{
if (!IS_STRING(string)) {
RequireArgument("ConvString", string, "must be a string");
}

if (!IS_STRING_REP(string)) {
string = CopyToStringRep(string);
}

Obj list = NEW_PLIST(T_PLIST, 1);
OutputStringGeneric(string, ToStringOutputter, list);
return list;
}

/****************************************************************************
**
Expand Down Expand Up @@ -1905,7 +1951,7 @@ static StructGVarFilt GVarFilts [] = {
*V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
*/
static StructGVarFunc GVarFuncs [] = {

GVAR_FUNC_1ARGS(CHUNK_ESCAPE_STRING, string),
GVAR_FUNC_1ARGS(IS_STRING_CONV, string),
GVAR_FUNC_1ARGS(CONV_STRING, string),
GVAR_FUNC_1ARGS(COPY_TO_STRING_REP, string),
Expand Down
27 changes: 26 additions & 1 deletion tst/testinstall/strings.tst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
##
## This file tests output methods (mainly for strings)
##
#@local x
#@local x, str
gap> START_TEST("strings.tst");

# FFE
Expand Down Expand Up @@ -42,10 +42,28 @@ gap> String(x);
"abc"
gap> x:="\0xFF";
"\377"
gap> PrintString(x);
"\377"
gap> ViewString(x);
"\"\\377\""
gap> x:="\0x42\0x23\0x10\0x10\0x10";
"B#\020\020\020"
gap> PrintString(x);
"B#\020\020\020"
gap> ViewString(x);
"\"B#\\020\\020\\020\""
gap> x:="A string with \0xFF Hex stuff \0x42 in it";
"A string with \377 Hex stuff B in it"
gap> PrintString(x);
"A string with \377 Hex stuff B in it"
gap> ViewString(x);
"\"A string with \\377 Hex stuff B in it\""
gap> x := "\n\t\c\\\"'";
"\n\t\c\\\"'"
gap> PrintString(x);
"\n\t\c\\\"'"
gap> ViewString(x);
"\"\\n\\t\\c\\\\\\\"'\""
gap> "\0yab";
Syntax error: Expecting hexadecimal escape, or two more octal digits in stream\
:1
Expand Down Expand Up @@ -174,5 +192,12 @@ gap> x:='\0xFF';
gap> x:='\0xab';
'\253'

# Huge strings
gap> for len in [10,100,1000,10000,100000] do
> str := List([1..len], x -> 'a');
> Assert(0, Concatenation("\"",str,"\"") = ViewString(str));
> Assert(0, Concatenation(str,"\n") = DisplayString(str));
> od;;

#
gap> STOP_TEST( "strings.tst", 1);

0 comments on commit f96cb02

Please sign in to comment.