From ae0c5c18fcab38bb4888da942d27878607c349b2 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 2 Oct 2020 12:30:07 +0200 Subject: [PATCH] kernel: remove input stream stack Instead of pre-allocating a fixed number of TypInputFile instances on each thread, we allocate the required storage dynamically on the stack. This arguably makes it easier to reason about the global state of GAP. It also enables future simplifications and improvements, e.g. further decoupling the input file code from the line buffering and potential optimizations resulting from that. --- src/common.h | 2 +- src/gap.c | 18 ++--- src/io.c | 179 ++++++++++---------------------------------------- src/io.h | 60 ++++++++++++++++- src/read.c | 6 -- src/streams.c | 85 +++++++++++++----------- src/streams.h | 2 +- 7 files changed, 146 insertions(+), 206 deletions(-) diff --git a/src/common.h b/src/common.h index ecda3d4e77d..e66340feca5 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 b300878b408..cb31707397a 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 9dbd809015d..603c6c281f1 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; } @@ -1489,17 +1402,6 @@ static void PutChrTo(TypOutputFile * stream, Char ch) } } -/**************************************************************************** -** -*F FuncToggleEcho( ) -** -*/ -static Obj FuncToggleEcho(Obj self) -{ - IO()->Input->echo = !IO()->Input->echo; - return (Obj)0; -} - /**************************************************************************** ** *F FuncCPROMPT( ) @@ -2029,7 +1931,6 @@ static Obj FuncGET_FILENAME_CACHE(Obj self) static StructGVarFunc GVarFuncs [] = { - GVAR_FUNC_0ARGS(ToggleEcho), GVAR_FUNC_0ARGS(CPROMPT), GVAR_FUNC_1ARGS(PRINT_CPROMPT, prompt), GVAR_FUNC_0ARGS(ALL_KEYWORDS), @@ -2064,8 +1965,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 +1977,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 +1991,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 231dcaa0c3c..d5fdc46a04b 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 9e31d2de63a..d58d31a3281 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 f54b6a979ac..e37f790055d 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 bba30194b69..5ee4121877b 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); /****************************************************************************