# SPDX-License-Identifier: GPL-2.0-or-later # IO_ForHomalg: IO capabilities for the homalg project # # Implementations #
## Implementation stuff to use the GAP4 I/O package of Max Neunhoeffer.
#################################### # # install global functions: # ####################################
##
InstallGlobalFunction( SendForkingToCAS, function ( f, st )
local pid, len;
IO_Flush( f );
pid := IO_fork( );
if pid = -1then
return fail; fi;
if pid = 0then
len := IO_Write( f, st );
IO_Flush( f );
IO_exit( 0 ); fi;
return pid;
end );
##
InstallGlobalFunction( SendToCAS, function( s, command ) # Note that it is the responsibility of the caller of this # function to call IO_WaitPid on the resulting pid eventually, # if the result is an integer rather than fail!
local cmd,pid;
if IsBound( s.SEARCH_READY_TWICE ) and s.SEARCH_READY_TWICE = true then
SEARCH_READY_TWICE := true; else
SEARCH_READY_TWICE := false; fi;
if IsBound( s.handle_output ) and s.handle_output = true then
handle_output := true; else
handle_output := false; fi;
if IsBound( s.original_lines ) and s.original_lines = true then
original_lines := true; else
original_lines := false; fi;
gotsomething := false;
while true do# will be exited with break or return
l := [ IO_GetFD( s.stdout ), IO_GetFD( s.stderr ) ];
nr := IO_select( l, [], [], 0, 0 ); #Print( "select: nr=", nr, "\n" );
if nr = 0then if original_lines then
s.LINES := ShallowCopy( s.lines ); ## for debugging purposes fi; if handle_output then## a Singular specific
len := Length( s.lines ); while len > 0 and s.lines[len] = '\n'do
Remove( s.lines );
len := len - 1;
od; fi;
if not ( gotsomething ) then
return fail; fi; # nothing new whatsoever
if nr = fail then continue; fi; # probably an interupted system call...
if l[1] <> fail then# something on stdout
pos := Length( s.lines );
bytes := IO_read( l[1], s.lines, pos, s.BUFSIZE ); if bytes > 0then #Print( "stdout bytes:", bytes, "\n" );
gotsomething := true;
pos := PositionSublist( s.lines, READY, pos - READY_LENGTH + 1 ); # ........NEWNEWNEWNEWNEW # ^ # pos if pos <> fail then
s.casready := true; if handle_output then## a Singular specific if original_lines then
s.lines_original := ShallowCopy( s.lines ); ## for debugging purposes fi;
s.pos := pos;
len := Length( s.lines ); if s.lines[1] = '\n'then
s.lines := Concatenation( s.lines{ [ 2 .. pos - 1 ] },
s.lines{ [ pos + READY_LENGTH + 1 .. len ] } ); elif s.lines[len] = '\n'then
s.lines := Concatenation( s.lines{ [ 1 .. pos - 1 ] },
s.lines{ [ pos + READY_LENGTH + 1 .. len - 1 ] } ); else
s.lines := Concatenation( s.lines{ [ 1 .. pos - 1 ] },
s.lines{ [ pos + READY_LENGTH + 1 .. len ] } ); fi; elif SEARCH_READY_TWICE then## a Macaulay2 specific
pos2 := PositionSublist( s.lines, READY );
pos3 := PositionSublist( s.lines, READY, pos2 + 1 ); if pos3 = fail then
gotsomething := false; else ## Print("s.lines", s.lines); ## die Feuerwehr
pos1 := PositionSublist( s.lines, "\n\n" ); if pos1 = fail then
pos1 := 1; fi;
pos3 := PositionSublist( s.lines, "\no", pos1 ); if pos3 <> fail then
pos4 := PositionSublist( s.lines, "=", pos3 + 1 ); if pos4 <> fail then
s.lines := Concatenation( s.lines{ [ 1 .. pos3 ] },
s.lines{ [ pos4 + 2 .. Length( s.lines ) ] } );
pos2 := pos2 - ( pos4 + 2 - pos3 ); else
s.lines := Concatenation( s.lines{ [ 1 .. pos3 ] },
s.lines{ [ pos3 + 2 .. Length( s.lines ) ] } );
pos2 := pos2 - 2; fi;
s.lines := s.lines{ [ pos1 + 2 .. pos2 - 2 ] };
pos3 := PositionSublist( s.lines, "\n\no" ); if pos3 <> fail then
s.lines := s.lines{ [ 1 .. pos3 - 1 ] }; fi; else
s.lines := s.lines{ [ pos1 + 4 .. pos2 - 2 ] }; fi; fi; else
s.lines := s.lines{ [ CUT_POS_BEGIN .. Length( s.lines ) - READY_LENGTH - CUT_POS_END ] }; fi; fi; else if IsBound( s.name ) then
CAS := Concatenation( s.name, " " ); else
CAS := ""; fi; if IsBound( s.pid ) then
PID := Concatenation( "(which should be running with PID ", String( s.pid ), ") " ); else
PID := ""; fi; if IsBound( HOMALG_IO.color_display ) and HOMALG_IO.color_display = true then
COLOR := "\033[5;31;43m"; else
COLOR := ""; fi; if not IsEmpty( s.errors ) then
ERRORS := Concatenation( "The last error was:\n", s.errors, "\n" ); else
ERRORS := ""; fi;
Error( COLOR, "the external CAS ", CAS, PID, "seems to have died!", "\033[0m\n", ERRORS ); fi; fi;
if l[2] <> fail then# something on stderr
bytes := IO_read( l[2], s.errors, Length( s.errors ), s.BUFSIZE ); if bytes > 0then #Print( "stderr bytes:", bytes, "\n" );
gotsomething := true; else if IsBound( s.name ) then
CAS := Concatenation( s.name, " " ); else
CAS := ""; fi; if IsBound( s.pid ) then
PID := Concatenation( "(which should be running with PID ", String( s.pid ), ") " ); else
PID := ""; fi; if IsBound( HOMALG_IO.color_display ) and HOMALG_IO.color_display = true then
COLOR := "\033[5;31;43m"; else
COLOR := ""; fi; if not IsEmpty( s.errors ) then
ERRORS := Concatenation( "The last error was:\n", s.errors, "\n" ); else
ERRORS := ""; fi;
Error( COLOR, "the external CAS ", CAS, PID, "seems to have died!", "\033[0m\n", ERRORS ); fi; fi;
od; # never reached
pid := SendToCAS( s, command );
repeat
l := [ IO_GetFD( s.stdout ), IO_GetFD( s.stderr ) ];
nr := IO_select( l, [], [], fail, fail ); # wait for input ready!
until CheckOutputOfCAS( s ) = true; if pid <> fail then IO_WaitPid(pid,true); fi;
end );
##
InstallGlobalFunction( TryLaunchCAS_IO_ForHomalg, function( arg )
local nargs, HOMALG_IO_CAS, executables, options, env, e, x, s;
nargs := Length( arg );
HOMALG_IO_CAS := arg[1];
executables := [ ];
if nargs > 1 and IsStringRep( arg[2] ) then
Add( executables, arg[2] ); fi;
if nargs > 2 and IsList( arg[3] ) then if IsString( arg[3] ) then
options := [ arg[3] ]; else
options := arg[3]; fi; else
options := HOMALG_IO_CAS.options; fi;
if IsBound( HOMALG_IO_CAS.executable ) then if IsStringRep( HOMALG_IO_CAS.executable ) then
Add( executables, HOMALG_IO_CAS.executable ); elif ForAll( HOMALG_IO_CAS.executable, IsStringRep ) then
Append( executables, HOMALG_IO_CAS.executable ); fi; fi;
if executables = [ ] then
Error( "either the name of the ", HOMALG_IO_CAS.name, " executable must exist as a component of the CAS specific record (normally called HOMALG_IO_", HOMALG_IO_CAS.name, " and which probably have been provided as the first argument), or the name must be provided as a second argument:\n", HOMALG_IO_CAS, "\n" ); fi;
if IsBound( HOMALG_IO_CAS.environment ) then
e := HOMALG_IO_CAS.environment; if env = fail then
Info( InfoWarning, 1, "the entry HOMALG_IO_CAS.environment is set but there is no executable `env'\n" ); fi; else
e := [ ]; fi;
for x in executables do
s := Filename( DirectoriesSystemPrograms( ), x );
if s <> fail then if not env = fail then
s := IO_Popen3( env, Concatenation( e, [ s ], options ) ); else
s := IO_Popen3( s, options ); fi; fi;
if s <> fail then
break; fi;
od;
if s = fail then
return rec( success := false, name := HOMALG_IO_CAS.name, executables := executables ); else
return s; fi;
end );
InstallGlobalFunction( LaunchCAS_IO_ForHomalg, function( arg )
local s;
s := CallFuncList( TryLaunchCAS_IO_ForHomalg, arg );
if not IsBound( s.stdout ) then
Error( "found no ", s.name, " executable in PATH while searching the following list:\n", s.executables, "\n" ); fi;
s.stdout!.rbufsize := false; # switch off buffering
s.stderr!.rbufsize := false; # switch off buffering
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.