diff --git a/src/common.h b/src/common.h index ecda3d4e77..e66340feca 100644 --- a/src/common.h +++ b/src/common.h @@ -205,7 +205,7 @@ typedef const struct init_info StructInitInfo; *T TypInputFile . . . . . . . . . . structure of an open input file, local ** ** This is a forward declaration so that TypInputFile can be used in header -** files. The actual declaration is in io.c and is private. +** files. The actual declaration is in io.h. */ typedef struct TypInputFile TypInputFile; diff --git a/src/gap.c b/src/gap.c index b300878b40..cb31707397 100644 --- a/src/gap.c +++ b/src/gap.c @@ -197,14 +197,13 @@ static Obj Shell(Obj context, if (!OpenOutput(outFile, FALSE)) ErrorQuit("SHELL: can't open outfile %s",(Int)outFile,0); - if(!OpenInput(inFile)) + TypInputFile input = { 0 }; + if (!OpenInput(&input, inFile)) { CloseOutput(); ErrorQuit("SHELL: can't open infile %s",(Int)inFile,0); } - TypInputFile * input = GetCurrentInput(); - oldPrintObjState = SetPrintObjState(0); while ( 1 ) { @@ -255,7 +254,7 @@ static Obj Shell(Obj context, STATE(ErrorLVars) = errorLVars; /* now read and evaluate and view one command */ - status = ReadEvalCommand(errorLVars, input, &evalResult, &dualSemicolon); + status = ReadEvalCommand(errorLVars, &input, &evalResult, &dualSemicolon); if (STATE(UserHasQUIT)) break; @@ -310,14 +309,14 @@ static Obj Shell(Obj context, if (STATE(UserHasQuit)) { - FlushRestOfInputLine(input); + FlushRestOfInputLine(&input); STATE(UserHasQuit) = 0; /* quit has done its job if we are here */ } } SetPrintObjState(oldPrintObjState); - CloseInput(); + CloseInput(&input); CloseOutput(); STATE(ErrorLLevel) = oldErrorLLevel; SetRecursionDepth(oldRecursionDepth); @@ -402,11 +401,12 @@ int realmain( int argc, char * argv[] ) read of init.g somehow*/ /* maybe compile in which case init.g got skipped */ if ( SyCompilePlease ) { - if ( ! OpenInput(SyCompileInput) ) { + TypInputFile input = { 0 }; + if ( ! OpenInput(&input, SyCompileInput) ) { return 1; } - func = READ_AS_FUNC(); - if (!CloseInput()) { + func = READ_AS_FUNC(&input); + if (!CloseInput(&input)) { return 2; } crc = SyGAPCRC(SyCompileInput); diff --git a/src/io.c b/src/io.c index 9dbd809015..92698dcf3d 100644 --- a/src/io.c +++ b/src/io.c @@ -44,57 +44,6 @@ #include -/**************************************************************************** -** -*T TypInputFile . . . . . . . . . . structure of an open input file, local -** -** 'TypInputFile' describes the information stored for open input files. -*/ -struct TypInputFile { - // non-zero if input comes from a stream - BOOL isstream; - - // non-zero if input come from a string stream - BOOL isstringstream; - - // if input comes from a stream, this points to a GAP IsInputStream object - Obj stream; - - // holds the file identifier received from 'SyFopen' and which is passed - // to 'SyFgets' and 'SyFclose' to identify this file - Int file; - - // the name of the file; this is only used in error messages - char name[256]; - - // - UInt gapnameid; - - // a buffer that holds the current input line; always terminated - // by the character '\0'. Because 'line' holds only part of the line for - // very long lines the last character need not be a . - // The actual line data starts in line[1]; the first byte line[0] - // is reserved for the "pushback buffer" used by PEEK_NEXT_CHAR. - char line[32768]; - - // the next line from the stream as GAP string - Obj sline; - - // - Int spos; - - // - BOOL echo; - - // pointer to the current character within the current line - char * ptr; - - // the number of the current line; used in error messages - Int number; - -}; - - /**************************************************************************** ** *T TypOutputFiles . . . . . . . . . structure of an open output file, local @@ -149,16 +98,11 @@ enum { struct IOModuleState { - // The stack of the open input files - TypInputFile * InputStack[MAX_OPEN_FILES]; - int InputStackPointer; - // The stack of open output files TypOutputFile * OutputStack[MAX_OPEN_FILES]; int OutputStackPointer; - // A pointer to the current input file. It points to the top of the stack - // 'InputFiles'. + // A pointer to the current input file TypInputFile * Input; // A pointer to the current output file. It points to the top of the @@ -258,9 +202,9 @@ Char PEEK_NEXT_CHAR(TypInputFile * input) // store the current character char c = *input->ptr; - // read next character; this will increment IO()->Input->ptr and then + // read next character; this will increment input->ptr and then // possibly read in new line data, and so even might end up reseting - // IO()->Input->ptr to point at the start of the line buffer, which is + // input->ptr to point at the start of the line buffer, which is // equal to Input->line+1 char next = GetNextChar(input); @@ -360,23 +304,9 @@ Obj GetCachedFilename(UInt id) */ #if !defined(HPCGAP) -static TypInputFile InputFiles[MAX_OPEN_FILES]; static TypOutputFile OutputFiles[MAX_OPEN_FILES]; #endif -static TypInputFile * PushNewInput(void) -{ - GAP_ASSERT(IO()->InputStackPointer < MAX_OPEN_FILES); - const int sp = IO()->InputStackPointer++; -#ifdef HPCGAP - if (!IO()->InputStack[sp]) { - IO()->InputStack[sp] = AllocateMemoryBlock(sizeof(TypInputFile)); - } -#endif - GAP_ASSERT(IO()->InputStack[sp]); - return IO()->InputStack[sp]; -} - static TypOutputFile * PushNewOutput(void) { GAP_ASSERT(IO()->OutputStackPointer < MAX_OPEN_FILES); @@ -394,22 +324,22 @@ static TypOutputFile * PushNewOutput(void) static GVarDescriptor DEFAULT_INPUT_STREAM; static GVarDescriptor DEFAULT_OUTPUT_STREAM; -static UInt OpenDefaultInput(void) +static UInt OpenDefaultInput(TypInputFile * input) { Obj func, stream; stream = TLS(DefaultInput); if (stream) - return OpenInputStream(stream, FALSE); + return OpenInputStream(input, stream, FALSE); func = GVarOptFunction(&DEFAULT_INPUT_STREAM); if (!func) - return OpenInput("*stdin*"); + return OpenInput(input, "*stdin*"); stream = CALL_0ARGS(func); if (!stream) ErrorQuit("DEFAULT_INPUT_STREAM() did not return a stream", 0, 0); if (IsStringConv(stream)) - return OpenInput(CONST_CSTR_STRING(stream)); + return OpenInput(input, CONST_CSTR_STRING(stream)); TLS(DefaultInput) = stream; - return OpenInputStream(stream, FALSE); + return OpenInputStream(input, stream, FALSE); } static UInt OpenDefaultOutput(void) @@ -461,21 +391,18 @@ static UInt OpenDefaultOutput(void) ** '*stdin*' for that purpose. This file on the other hand cannot be ** closed by 'CloseInput'. */ -UInt OpenInput ( - const Char * filename ) +UInt OpenInput(TypInputFile * input, const Char * filename) { - Int file; + GAP_ASSERT(input); - /* fail if we can not handle another open input file */ - if (IO()->InputStackPointer == MAX_OPEN_FILES) - return 0; + Int file; #ifdef HPCGAP /* Handle *defin*; redirect *errin* to *defin* if the default * channel is already open. */ if (streq(filename, "*defin*") || (streq(filename, "*errin*") && TLS(DefaultInput))) - return OpenDefaultInput(); + return OpenDefaultInput(input); #endif /* try to open the input file */ @@ -484,10 +411,10 @@ UInt OpenInput ( return 0; /* enter the file identifier and the file name */ - TypInputFile * input = IO()->Input = PushNewInput(); + memset(input, 0, sizeof(TypInputFile)); + input->prev = IO()->Input; input->isstream = FALSE; input->file = file; - input->name[0] = '\0'; // enable echo for stdin and errin if (streq("*errin*", filename) || streq("*stdin*", filename)) @@ -504,6 +431,8 @@ UInt OpenInput ( input->ptr = input->line + 1; input->number = 1; + IO()->Input = input; + /* indicate success */ return 1; } @@ -515,14 +444,13 @@ UInt OpenInput ( ** ** The same as 'OpenInput' but for streams. */ -UInt OpenInputStream(Obj stream, BOOL echo) +UInt OpenInputStream(TypInputFile * input, Obj stream, BOOL echo) { - /* fail if we can not handle another open input file */ - if (IO()->InputStackPointer == MAX_OPEN_FILES) - return 0; + GAP_ASSERT(input); /* enter the file identifier and the file name */ - TypInputFile * input = IO()->Input = PushNewInput(); + memset(input, 0, sizeof(TypInputFile)); + input->prev = IO()->Input; input->isstream = TRUE; input->stream = stream; input->isstringstream = (CALL_1ARGS(IsStringStream, stream) == True); @@ -544,6 +472,8 @@ UInt OpenInputStream(Obj stream, BOOL echo) input->ptr = input->line + 1; input->number = 1; + IO()->Input = input; + /* indicate success */ return 1; } @@ -564,39 +494,22 @@ UInt OpenInputStream(Obj stream, BOOL echo) ** Calling 'CloseInput' if the corresponding 'OpenInput' call failed will ** close the current output file, which will lead to very strange behaviour. */ -UInt CloseInput ( void ) +UInt CloseInput(TypInputFile * input) { - /* refuse to close the initial input file */ -#ifdef HPCGAP - // In HPC-GAP, only for the main thread. - if (TLS(threadID) != 0) { - if (IO()->InputStackPointer <= 0) - return 0; - } else -#else - if (IO()->InputStackPointer <= 1) - return 0; -#endif + GAP_ASSERT(input); + GAP_ASSERT(input == IO()->Input); - /* close the input file */ - if (!IO()->Input->isstream) { - SyFclose(IO()->Input->file); + // close the input file + if (!input->isstream) { + SyFclose(input->file); } - /* don't keep GAP objects alive unnecessarily */ - memset(IO()->Input, 0, sizeof(TypInputFile)); + // revert to previous input + IO()->Input = input->prev; - /* revert to last file */ - const int sp = --IO()->InputStackPointer; -#ifdef HPCGAP - if (sp == 0) { - IO()->Input = NULL; - return 1; - } -#endif - IO()->Input = IO()->InputStack[sp - 1]; + // don't keep GAP objects alive unnecessarily + memset(input, 0, sizeof(TypInputFile)); - /* indicate success */ return 1; } @@ -2064,8 +1977,6 @@ static Int InitLibrary ( #if !defined(HPCGAP) static Char OutputFilesStreamCookie[MAX_OPEN_FILES][9]; -static Char InputFilesStreamCookie[MAX_OPEN_FILES][9]; -static Char InputFilesSlineCookie[MAX_OPEN_FILES][9]; #endif static Int InitKernel ( @@ -2078,12 +1989,10 @@ static Int InitKernel ( #if !defined(HPCGAP) for (Int i = 0; i < MAX_OPEN_FILES; i++) { - IO()->InputStack[i] = &InputFiles[i]; IO()->OutputStack[i] = &OutputFiles[i]; } #endif - OpenInput("*stdin*"); OpenOutput("*stdout*", FALSE); InitGlobalBag( &FilenameCache, "FilenameCache" ); @@ -2094,22 +2003,12 @@ static Int InitKernel ( DeclareGVar(&DEFAULT_OUTPUT_STREAM, "DEFAULT_OUTPUT_STREAM"); #else - // Initialize cookies for streams. Also initialize the cookies for the - // GAP strings which hold the latest lines read from the streams and the - // name of the current input file. For HPC-GAP we don't need the cookies + // Initialize cookies for streams. For HPC-GAP we don't need the cookies // anymore, since the data got moved to thread-local storage. for (Int i = 0; i < MAX_OPEN_FILES; i++) { strxcpy(OutputFilesStreamCookie[i], "ostream0", sizeof(OutputFilesStreamCookie[i])); OutputFilesStreamCookie[i][7] = '0' + i; InitGlobalBag(&(OutputFiles[i].stream), &(OutputFilesStreamCookie[i][0])); - - strxcpy(InputFilesStreamCookie[i], "istream0", sizeof(InputFilesStreamCookie[i])); - InputFilesStreamCookie[i][7] = '0' + i; - InitGlobalBag(&(InputFiles[i].stream), &(InputFilesStreamCookie[i][0])); - - strxcpy(InputFilesSlineCookie[i], "isline 0", sizeof(InputFilesSlineCookie[i])); - InputFilesSlineCookie[i][7] = '0' + i; - InitGlobalBag(&(InputFiles[i].sline), &(InputFilesSlineCookie[i][0])); } /* tell GASMAN about the global bags */ diff --git a/src/io.h b/src/io.h index 231dcaa0c3..d5fdc46a04 100644 --- a/src/io.h +++ b/src/io.h @@ -24,6 +24,60 @@ #include "common.h" + +/**************************************************************************** +** +*T TypInputFile . . . . . . . . . . structure of an open input file, local +** +** 'TypInputFile' describes the information stored for open input files. +*/ +struct TypInputFile { + // pointer to the previously active input + struct TypInputFile * prev; + + // non-zero if input comes from a stream + BOOL isstream; + + // non-zero if input come from a string stream + BOOL isstringstream; + + // if input comes from a stream, this points to a GAP IsInputStream object + Obj stream; + + // holds the file identifier received from 'SyFopen' and which is passed + // to 'SyFgets' and 'SyFclose' to identify this file + Int file; + + // the name of the file; this is only used in error messages + char name[256]; + + // + UInt gapnameid; + + // a buffer that holds the current input line; always terminated + // by the character '\0'. Because 'line' holds only part of the line for + // very long lines the last character need not be a . + // The actual line data starts in line[1]; the first byte line[0] + // is reserved for the "pushback buffer" used by PEEK_NEXT_CHAR. + char line[32768]; + + // the next line from the stream as GAP string + Obj sline; + + // + Int spos; + + // + BOOL echo; + + // pointer to the current character within the current line + char * ptr; + + // the number of the current line; used in error messages + Int number; +}; + + /**************************************************************************** ** *F * * * * * * * * * * * open input/output functions * * * * * * * * * * * * @@ -63,7 +117,7 @@ ** '*stdin*' for that purpose. This file on the other hand cannot be ** closed by 'CloseInput'. */ -UInt OpenInput(const Char * filename); +UInt OpenInput(TypInputFile * input, const Char * filename); /**************************************************************************** @@ -72,7 +126,7 @@ UInt OpenInput(const Char * filename); ** ** The same as 'OpenInput' but for streams. */ -UInt OpenInputStream(Obj stream, BOOL echo); +UInt OpenInputStream(TypInputFile * input, Obj stream, BOOL echo); /**************************************************************************** @@ -90,7 +144,7 @@ UInt OpenInputStream(Obj stream, BOOL echo); ** Calling 'CloseInput' if the corresponding 'OpenInput' call failed will ** close the current output file, which will lead to very strange behaviour. */ -UInt CloseInput(void); +UInt CloseInput(TypInputFile * input); /**************************************************************************** diff --git a/src/read.c b/src/read.c index 9e31d2de63..d58d31a328 100644 --- a/src/read.c +++ b/src/read.c @@ -2600,10 +2600,7 @@ ExecStatus ReadEvalCommand(Obj context, // initialize everything and begin an interpreter rs->StackNams = NEW_PLIST( T_PLIST, 16 ); - rs->ReadTop = 0; - rs->ReadTilde = 0; STATE(Tilde) = 0; - rs->CurrLHSGVar = 0; #ifdef HPCGAP lockSP = RegionLockSP(); #endif @@ -2719,10 +2716,7 @@ UInt ReadEvalFile(TypInputFile * input, Obj * evalResult) // initialize everything and begin an interpreter rs->StackNams = NEW_PLIST( T_PLIST, 16 ); - rs->ReadTop = 0; - rs->ReadTilde = 0; STATE(Tilde) = 0; - rs->CurrLHSGVar = 0; // remember the old execution state and start an execution environment Bag oldLVars = SWITCH_TO_BOTTOM_LVARS(); diff --git a/src/streams.c b/src/streams.c index f54b6a979a..e37f790055 100644 --- a/src/streams.c +++ b/src/streams.c @@ -71,24 +71,25 @@ static Obj IsOutputStream; *F * * * * * * * * * streams and files related functions * * * * * * * * * * */ -static UInt OpenInputFileOrStream(const char * funcname, Obj input) +static UInt OpenInputFileOrStream(const char * funcname, + TypInputFile * input, + Obj inputObj) { - if (IsStringConv(input)) { - return OpenInput(CONST_CSTR_STRING(input)); + if (IsStringConv(inputObj)) { + return OpenInput(input, CONST_CSTR_STRING(inputObj)); } - else if (CALL_1ARGS(IsInputStream, input) == True) { - return OpenInputStream(input, FALSE); + else if (CALL_1ARGS(IsInputStream, inputObj) == True) { + return OpenInputStream(input, inputObj, FALSE); } - RequireArgumentEx(funcname, input, "", + RequireArgumentEx(funcname, inputObj, "", "must be a string or an input stream"); } -static Int READ_COMMAND(Obj *evalResult) +static Int READ_COMMAND(TypInputFile * input, Obj *evalResult) { ExecStatus status; ClearError(); - TypInputFile * input = GetCurrentInput(); status = ReadEvalCommand(0, input, evalResult, 0); if( status == STATUS_EOF ) return 0; @@ -170,19 +171,18 @@ Obj READ_ALL_COMMANDS(Obj instream, Obj echo, Obj capture, Obj resultCallback) RequireInputStream("READ_ALL_COMMANDS", instream); /* try to open the streams */ - if (!OpenInputStream(instream, echo == True)) { + TypInputFile input = { 0 }; + if (!OpenInputStream(&input, instream, echo == True)) { return Fail; } - TypInputFile * input = GetCurrentInput(); - if (capture == True) { outstreamString = NEW_STRING(0); outstream = DoOperation2Args(ValGVar(GVarName("OutputTextString")), outstreamString, True); } if (outstream && !OpenOutputStream(outstream)) { - CloseInput(); + CloseInput(&input); return Fail; } @@ -195,7 +195,7 @@ Obj READ_ALL_COMMANDS(Obj instream, Obj echo, Obj capture, Obj resultCallback) SET_LEN_STRING(outstreamString, 0); } - status = ReadEvalCommand(0, input, &evalResult, &dualSemicolon); + status = ReadEvalCommand(0, &input, &evalResult, &dualSemicolon); if (!(status & (STATUS_EOF | STATUS_QUIT | STATUS_QQUIT))) { result = NEW_PLIST(T_PLIST, 5); @@ -229,7 +229,7 @@ Obj READ_ALL_COMMANDS(Obj instream, Obj echo, Obj capture, Obj resultCallback) if (outstream) CloseOutput(); - CloseInput(); + CloseInput(&input); ClearError(); return resultList; @@ -262,13 +262,14 @@ static Obj FuncREAD_COMMAND_REAL(Obj self, Obj stream, Obj echo) SET_ELM_PLIST(result, 1, False); /* try to open the file */ - if (!OpenInputStream(stream, echo == True)) { + TypInputFile input = { 0 }; + if (!OpenInputStream(&input, stream, echo == True)) { return result; } - status = READ_COMMAND(&evalResult); - - CloseInput(); + status = READ_COMMAND(&input, &evalResult); + + CloseInput(&input); if( status == 0 ) return result; @@ -353,11 +354,10 @@ static void READ_INNER(TypInputFile * input) ** ** Read the current input as function and close the input stream. */ -Obj READ_AS_FUNC ( void ) +Obj READ_AS_FUNC(TypInputFile * input) { /* now do the reading */ ClearError(); - TypInputFile * input = GetCurrentInput(); Obj evalResult; UInt type = ReadEvalFile(input, &evalResult); ClearError(); @@ -489,11 +489,12 @@ Int READ_GAP_ROOT ( const Char * filename ) if (SyDebugLoading) { Pr("#I READ_GAP_ROOT: loading '%s' as GAP file\n", (Int)filename, 0); } - if (OpenInput(path)) { - TypInputFile * input = GetCurrentInput(); + + TypInputFile input = { 0 }; + if (OpenInput(&input, path)) { while (1) { ClearError(); - UInt type = ReadEvalCommand(0, input, 0, 0); + UInt type = ReadEvalCommand(0, &input, 0, 0); if (STATE(UserHasQuit) || STATE(UserHasQUIT)) break; if (type & (STATUS_RETURN_VAL | STATUS_RETURN_VOID)) { @@ -503,7 +504,7 @@ Int READ_GAP_ROOT ( const Char * filename ) break; } } - CloseInput(); + CloseInput(&input); ClearError(); return 1; } @@ -849,14 +850,15 @@ static Obj FuncAPPEND_TO_STREAM(Obj self, Obj args) ** ** Read the current input and close the input stream. */ -static Obj FuncREAD(Obj self, Obj input) +static Obj FuncREAD(Obj self, Obj inputObj) { - if (!OpenInputFileOrStream(SELF_NAME, input)) + TypInputFile input = { 0 }; + if (!OpenInputFileOrStream(SELF_NAME, &input, inputObj)) return False; // read the file - READ_INNER(GetCurrentInput()); - if (!CloseInput()) { + READ_INNER(&input); + if (!CloseInput(&input)) { ErrorQuit("Panic: READ cannot close input", 0, 0); } return True; @@ -872,14 +874,15 @@ static Obj FuncREAD(Obj self, Obj input) ** a live prompt. This is initially designed for the files read from the ** command line. */ -static Obj FuncREAD_NORECOVERY(Obj self, Obj input) +static Obj FuncREAD_NORECOVERY(Obj self, Obj inputObj) { - if (!OpenInputFileOrStream(SELF_NAME, input)) + TypInputFile input = { 0 }; + if (!OpenInputFileOrStream(SELF_NAME, &input, inputObj)) return False; // read the file - READ_INNER(GetCurrentInput()); - if (!CloseInput()) { + READ_INNER(&input); + if (!CloseInput(&input)) { ErrorQuit("Panic: READ_NORECOVERY cannot close input", 0, 0); } if (STATE(UserHasQuit)) { @@ -907,21 +910,22 @@ static Obj FuncREAD_STREAM_LOOP_WITH_CONTEXT(Obj self, RequireInputStream(SELF_NAME, instream); RequireOutputStream(SELF_NAME, outstream); - if (!OpenInputStream(instream, FALSE)) { + TypInputFile input = { 0 }; + if (!OpenInputStream(&input, instream, FALSE)) { return False; } if (!OpenOutputStream(outstream)) { - res = CloseInput(); + res = CloseInput(&input); GAP_ASSERT(res); return False; } LockCurrentOutput(1); - READ_TEST_OR_LOOP(context, GetCurrentInput()); + READ_TEST_OR_LOOP(context, &input); LockCurrentOutput(0); - res = CloseInput(); + res = CloseInput(&input); GAP_ASSERT(res); res &= CloseOutput(); @@ -940,13 +944,14 @@ static Obj FuncREAD_STREAM_LOOP(Obj self, Obj stream, Obj catcherrstdout) ** *F FuncREAD_AS_FUNC( , ) . read a file or stream as a function */ -static Obj FuncREAD_AS_FUNC(Obj self, Obj input) +static Obj FuncREAD_AS_FUNC(Obj self, Obj inputObj) { - if (!OpenInputFileOrStream(SELF_NAME, input)) + TypInputFile input = { 0 }; + if (!OpenInputFileOrStream(SELF_NAME, &input, inputObj)) return False; - Obj func = READ_AS_FUNC(); - if (!CloseInput()) { + Obj func = READ_AS_FUNC(&input); + if (!CloseInput(&input)) { ErrorQuit("Panic: READ_AS_FUNC cannot close input", 0, 0); } return func; diff --git a/src/streams.h b/src/streams.h index bba30194b6..5ee4121877 100644 --- a/src/streams.h +++ b/src/streams.h @@ -29,7 +29,7 @@ ** Read the current input as function. The caller is responsible for opening ** and closing the input. */ -Obj READ_AS_FUNC(void); +Obj READ_AS_FUNC(TypInputFile * input); /****************************************************************************