Skip to content

Commit

Permalink
Add OutputGzipFile
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisJefferson committed Nov 17, 2020
1 parent 2e5d82f commit a81f6c1
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 53 deletions.
5 changes: 4 additions & 1 deletion lib/streams.gd
Original file line number Diff line number Diff line change
Expand Up @@ -726,14 +726,16 @@ DeclareOperation( "OutputTextString", [ IsList, IsBool ] );
## <#GAPDoc Label="OutputTextFile">
## <ManSection>
## <Oper Name="OutputTextFile" Arg='filename, append'/>
## <Oper Name="OutputGzipFile" Arg='filename, append'/>
##
## <Description>
## <C>OutputTextFile( <A>filename</A>, <A>append</A> )</C> returns an output stream in the
## category <C>IsOutputTextFile</C> that writes received characters to the file
## <A>filename</A>. If <A>append</A> is <K>false</K>, then the file is emptied first,
## otherwise received characters are added at the end of the file.
## If <A>filename</A> ends in <C>.gz</C> then the file will be
## written with gzip compression.
## written with gzip compression. <C>OutputGzipFile</C> acts identically to
## <C>OutputTextFile</C>, except it compresses the output with gzip.
## <P/>
## <Example><![CDATA[
## gap> # use a temporary directory
Expand Down Expand Up @@ -766,6 +768,7 @@ DeclareOperation( "OutputTextString", [ IsList, IsBool ] );
## <#/GAPDoc>
##
DeclareOperation( "OutputTextFile", [ IsString, IsBool ] );
DeclareOperation( "OutputGzipFile", [ IsString, IsBool ] );


#############################################################################
Expand Down
31 changes: 29 additions & 2 deletions lib/streams.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1084,14 +1084,33 @@ fi;
#M OutputTextFile( <str>, <append> )
##
InstallMethod( OutputTextFile,
"output text stream from file",
"output text stream to file",
[ IsString,
IsBool ],
function( str, append )
local fid;
str := UserHomeExpand(str);

fid := OUTPUT_TEXT_FILE( str, append );
fid := OUTPUT_TEXT_FILE( str, append, false );
if fid = fail then
return fail;
else
atomic OutputTextFileStillOpen do
AddSet( OutputTextFileStillOpen, fid );
od;
return Objectify( OutputTextFileType, [fid, Immutable(str), true] );
fi;
end );

InstallMethod( OutputGzipFile,
"output gzipped text to file",
[ IsString,
IsBool ],
function( str, append )
local fid;
str := UserHomeExpand(str);

fid := OUTPUT_TEXT_FILE( str, append, true );
if fid = fail then
return fail;
else
Expand All @@ -1110,6 +1129,14 @@ InstallOtherMethod( OutputTextFile,
Error("Usage OutputTextFile( <fname>, <append> )");
end );

InstallOtherMethod( OutputGzipFile,
"error catching method, append not given",
[ IsString ],
-SUM_FLAGS, # as low as possible
function( str )
Error("Usage OutputGzipFile( <fname>, <append> )");
end );

#############################################################################
##
#M CloseStream( <output-text-file> )
Expand Down
10 changes: 5 additions & 5 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ UInt OpenInput(TypInputFile * input, const Char * filename)
#endif

/* try to open the input file */
file = SyFopen( filename, "r" );
file = SyFopen(filename, "r", TRUE);
if ( file == -1 )
return 0;

Expand Down Expand Up @@ -503,7 +503,7 @@ UInt OpenLog (
return 0;

/* try to open the file */
IO()->OutputLogFileOrStream.file = SyFopen(filename, "w");
IO()->OutputLogFileOrStream.file = SyFopen(filename, "w", TRUE);
IO()->OutputLogFileOrStream.isstream = FALSE;
if (IO()->OutputLogFileOrStream.file == -1)
return 0;
Expand Down Expand Up @@ -597,7 +597,7 @@ UInt OpenInputLog (
return 0;

/* try to open the file */
IO()->InputLogFileOrStream.file = SyFopen(filename, "w");
IO()->InputLogFileOrStream.file = SyFopen(filename, "w", TRUE);
IO()->InputLogFileOrStream.isstream = FALSE;
if (IO()->InputLogFileOrStream.file == -1)
return 0;
Expand Down Expand Up @@ -694,7 +694,7 @@ UInt OpenOutputLog (
/* try to open the file */
memset(&IO()->OutputLogFileOrStream, 0, sizeof(TypOutputFile));
IO()->OutputLogFileOrStream.isstream = FALSE;
IO()->OutputLogFileOrStream.file = SyFopen(filename, "w");
IO()->OutputLogFileOrStream.file = SyFopen(filename, "w", TRUE);
if (IO()->OutputLogFileOrStream.file == -1)
return 0;

Expand Down Expand Up @@ -817,7 +817,7 @@ UInt OpenOutput(TypOutputFile * output, const Char * filename, BOOL append)
#endif

/* try to open the file */
Int file = SyFopen(filename, append ? "a" : "w");
Int file = SyFopen(filename, append ? "a" : "w", TRUE);
if ( file == -1 )
return 0;

Expand Down
20 changes: 9 additions & 11 deletions src/saveload.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,11 @@ static Int OpenForSave( Obj fname )
Pr("Already saving\n", 0, 0);
return 1;
}
SaveFile = SyFopen(CONST_CSTR_STRING(fname), "wb");
if (SaveFile == -1)
{
Pr("Couldn't open file %s to save workspace\n",
(UInt)CONST_CSTR_STRING(fname), 0);
return 1;
SaveFile = SyFopen(CONST_CSTR_STRING(fname), "wb", TRUE);
if (SaveFile == -1) {
Pr("Couldn't open file %s to save workspace\n",
(UInt)CONST_CSTR_STRING(fname), 0);
return 1;
}
LBPointer = LoadBuffer;
LBEnd = LBPointer+sizeof(LoadBuffer);
Expand All @@ -89,11 +88,10 @@ static void OpenForLoad( const Char *fname )
{
Panic("Internal error -- this should never happen");
}
LoadFile = SyFopen(fname, "rb");
if (LoadFile == -1)
{
Pr("Couldn't open saved workspace %s\n",(Int)fname, 0);
SyExit(1);
LoadFile = SyFopen(fname, "rb", TRUE);
if (LoadFile == -1) {
Pr("Couldn't open saved workspace %s\n", (Int)fname, 0);
SyExit(1);
}
}

Expand Down
18 changes: 10 additions & 8 deletions src/streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -1264,8 +1264,8 @@ static Obj FuncINPUT_TEXT_FILE(Obj self, Obj filename)

/* call the system dependent function */
SyClearErrorNo();
fid = SyFopen( CONST_CSTR_STRING(filename), "r" );
if ( fid == - 1)
fid = SyFopen(CONST_CSTR_STRING(filename), "r", TRUE);
if (fid == -1)
SySetErrorNo();
return fid == -1 ? Fail : INTOBJ_INT(fid);
}
Expand All @@ -1286,24 +1286,26 @@ static Obj FuncIS_END_OF_FILE(Obj self, Obj fid)

/****************************************************************************
**
*F FuncOUTPUT_TEXT_FILE( <self>, <name>, <append> ) . . . . . open a stream
*F FuncOUTPUT_TEXT_FILE( <self>, <name>, <append>, <comp> ) . open a stream
*/
static Obj FuncOUTPUT_TEXT_FILE(Obj self, Obj filename, Obj append)
static Obj FuncOUTPUT_TEXT_FILE(Obj self, Obj filename, Obj append, Obj comp)
{
Int fid;

RequireStringRep(SELF_NAME, filename);
RequireTrueOrFalse(SELF_NAME, append);
RequireTrueOrFalse(SELF_NAME, comp);

Int compbool = (comp == True);
/* call the system dependent function */
SyClearErrorNo();
if ( append == True ) {
fid = SyFopen( CONST_CSTR_STRING(filename), "a" );
fid = SyFopen(CONST_CSTR_STRING(filename), "a", compbool);
}
else {
fid = SyFopen( CONST_CSTR_STRING(filename), "w" );
fid = SyFopen(CONST_CSTR_STRING(filename), "w", compbool);
}
if ( fid == - 1)
if (fid == -1)
SySetErrorNo();
return fid == -1 ? Fail : INTOBJ_INT(fid);
}
Expand Down Expand Up @@ -1773,7 +1775,7 @@ static StructGVarFunc GVarFuncs[] = {
GVAR_FUNC_1ARGS(LIST_DIR, dirname),
GVAR_FUNC_1ARGS(CLOSE_FILE, fid),
GVAR_FUNC_1ARGS(INPUT_TEXT_FILE, filename),
GVAR_FUNC_2ARGS(OUTPUT_TEXT_FILE, filename, append),
GVAR_FUNC_3ARGS(OUTPUT_TEXT_FILE, filename, append, compress),
GVAR_FUNC_1ARGS(IS_END_OF_FILE, fid),
GVAR_FUNC_1ARGS(POSITION_FILE, fid),
GVAR_FUNC_1ARGS(READ_BYTE_FILE, fid),
Expand Down
19 changes: 11 additions & 8 deletions src/sysfiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ Int4 SyGAPCRC( const Char * name )
Int seen_nl;

/* the CRC of a non existing file is 0 */
fid = SyFopen( name, "r" );
fid = SyFopen(name, "r", TRUE);
if ( fid == -1 ) {
return 0;
}
Expand Down Expand Up @@ -585,7 +585,7 @@ void SyBufSetEOF(Int fid)

/****************************************************************************
**
*F SyFopen( <name>, <mode> ) . . . . . . . . open the file with name <name>
*F SyFopen( <name>, <mode>, <transcompress> ) open the file with name <name>
**
** The function 'SyFopen' is called to open the file with the name <name>.
** If <mode> is "r" it is opened for reading, in this case it must exist.
Expand All @@ -606,11 +606,12 @@ void SyBufSetEOF(Int fid)
**
** Right now GAP does not read nonascii files, but if this changes sometimes
** 'SyFopen' must adjust the mode argument to open the file in binary mode.
**
** If <transcompress> is TRUE, files with names ending '.gz' will be
** automatically compressed/decompressed using gzip.
*/

Int SyFopen (
const Char * name,
const Char * mode )
Int SyFopen(const Char * name, const Char * mode, BOOL transcompress)
{
Int fid;
Char namegz [1024];
Expand Down Expand Up @@ -666,16 +667,18 @@ Int SyFopen (
#endif

/* try to open the file */
if (endsgz && (syBuf[fid].gzfp = gzopen(name, mode))) {
if (endsgz && transcompress && (syBuf[fid].gzfp = gzopen(name, mode))) {
syBuf[fid].type = gzip_socket;
syBuf[fid].fp = -1;
syBuf[fid].bufno = -1;
} else if (0 <= (syBuf[fid].fp = open(name, flags, 0644))) {
}
else if (0 <= (syBuf[fid].fp = open(name, flags, 0644))) {
syBuf[fid].type = raw_socket;
syBuf[fid].echo = syBuf[fid].fp;
syBuf[fid].bufno = -1;
}
else if (strncmp(mode, "r", 1) == 0 && SyIsReadableFile(namegz) == 0 &&
else if (strncmp(mode, "r", 1) == 0 && transcompress &&
SyIsReadableFile(namegz) == 0 &&
(syBuf[fid].gzfp = gzopen(namegz, mode))) {
syBuf[fid].type = gzip_socket;
syBuf[fid].fp = -1;
Expand Down
7 changes: 5 additions & 2 deletions src/sysfiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void SyBufSetEOF(Int fid);

/****************************************************************************
**
*F SyFopen( <name>, <mode> ) . . . . . . . . open the file with name <name>
*F SyFopen( <name>, <mode>, <transcompress> ) open the file with name <name>
**
** The function 'SyFopen' is called to open the file with the name <name>.
** If <mode> is "r" it is opened for reading, in this case it must exist.
Expand All @@ -113,8 +113,11 @@ void SyBufSetEOF(Int fid);
** If it is necessary to adjust the filename this should be done here.
** Right now GAP does not read nonascii files, but if this changes sometimes
** 'SyFopen' must adjust the mode argument to open the file in binary mode.
**
** If <transcompress> is TRUE, files with names ending '.gz' will be
** automatically compressed/decompressed using gzip.
*/
Int SyFopen(const Char * name, const Char * mode);
Int SyFopen(const Char * name, const Char * mode, BOOL transcompress);


/****************************************************************************
Expand Down
51 changes: 35 additions & 16 deletions tst/testinstall/compressed.tst
Original file line number Diff line number Diff line change
@@ -1,30 +1,49 @@
#@local dir,fname,isGzippedFile,stream,str
#@local o,dir,fname,rawfname,isGzippedFile,stream,str
gap> START_TEST("compressed.tst");
gap> dir := DirectoryTemporary();;
gap> fname := Filename(dir, "test.g.gz");;
gap> rawfname := Filename(dir, "rawtest.g.gz");;

# Let us check when we have written a compressed file by checking the gzip header
gap> isGzippedFile := function(dir, name)
> local out, str,prog;
> str := "";
> out := OutputTextString(str, true);
> Process(dir, Filename(DirectoriesSystemPrograms(),"cat"), InputTextNone(), out, [name]);
> return str{[1..2]} = "\037\213";
# We need raw file access to do this, so we use 'IO'. We stub out this part of the
# test if IO is not loaded
gap> isGzippedFile := function(fname)
> local ins, str;
> if not IsPackageLoaded("IO") then return true; fi;
> # Use 'ValueGlobal' to avoid warnings about undefined functions
> ins := ValueGlobal("IO_File")(fname, "r");
> str := ValueGlobal("IO_Read")(ins, 2);;
> # All gzipped files should start with these two characters
> return str = [CharInt(31),CharInt(139)];
> end;;
gap> str := "hello\ngoodbye\n";;

# Write a compressed file
gap> FileString( fname, str ) = Length(str);
# Write an uncompressed file
gap> FileString( rawfname, str ) = Length(str);
true

# Write a compressed file, using OutputGzipFile
gap> o := OutputGzipFile(fname, false);;
gap> WriteAll(o, str);
true
gap> CloseStream(o);

# Check file really is compressed
gap> isGzippedFile(dir, "test.g.gz");
gap> isGzippedFile(fname);
true

# Check file really is NOT compressed
gap> isGzippedFile(rawfname);
false

# Check reading compressed file
gap> StringFile( fname ) = str;
true

# Check reading uncompressed file
gap> StringFile( rawfname ) = str;
true

# Check gz is added transparently
gap> StringFile( Filename(dir, "test.g") ) = str;
true
Expand Down Expand Up @@ -68,7 +87,7 @@ true
gap> CloseStream(stream);

# Test multiple writes
gap> stream := OutputTextFile( fname, false );;
gap> stream := OutputGzipFile( fname, false );;
gap> PrintTo( stream, "1");
gap> AppendTo( stream, "2");
gap> PrintTo( stream, "3");
Expand All @@ -77,7 +96,7 @@ true
gap> CloseStream(stream);
gap> stream;
closed-stream
gap> isGzippedFile(dir, "test.g.gz");
gap> isGzippedFile(fname);
true

# verify it
Expand Down Expand Up @@ -113,7 +132,7 @@ gap> stream;
closed-stream

# append to initial data
gap> stream := OutputTextFile( fname, true );;
gap> stream := OutputGzipFile( fname, true );;
gap> PrintTo( stream, "4");
gap> CloseStream(stream);

Expand All @@ -126,7 +145,7 @@ gap> stream;
closed-stream

# overwrite initial data
gap> stream := OutputTextFile( fname, false );;
gap> stream := OutputGzipFile( fname, false );;
gap> PrintTo( stream, "new content");
gap> CloseStream(stream);

Expand All @@ -145,15 +164,15 @@ gap> ReadAll(stream, 3);
gap> CloseStream(stream);

# test PrintFormattingStatus
gap> stream := OutputTextFile( fname, false );;
gap> stream := OutputGzipFile( fname, false );;
gap> PrintFormattingStatus(stream);
true
gap> PrintTo( stream, "a very long line that GAP is going to wrap at 80 chars by default if we don't do anything about it\n");
gap> CloseStream(stream);
gap> StringFile(fname);
"a very long line that GAP is going to wrap at 80 chars by default if we don't\
\\\ndo anything about it\n"
gap> stream := OutputTextFile( fname, false );;
gap> stream := OutputGzipFile( fname, false );;
gap> SetPrintFormattingStatus(stream, false);
gap> PrintFormattingStatus(stream);
false
Expand Down

0 comments on commit a81f6c1

Please sign in to comment.