GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
###########################################################################
##
#W pipeobj.g OpenMath Package Andrew Solomon
#W Marco Costantini
##
#Y Copyright (C) 1999, 2000, 2001, 2006
#Y School Math and Comp. Sci., University of St. Andrews, Scotland
#Y Copyright (C) 2004, 2005, 2006 Marco Costantini
##
## Pipe exactly one OpenMath object from <input stream> to
## <output string>.
##
###########################################################################
##
#F ReadCharSkipSpace( <input> )
##
## Reads and returns next non-space byte from input stream
## returning the associated character.
##
BindGlobal("ReadCharSkipSpace", function(input)
local
b, # byte
c; # character
b := ReadByte(input);
while b <> fail and (CHAR_INT(b) in [' ','\n','\t','\r']) do
b := ReadByte(input);
od;
if b <> fail then
return CHAR_INT(b);
fi;
return fail;
end);
###########################################################################
##
#F ReadChar( <input> )
##
## Reads and returns next byte as a character.
##
BindGlobal("ReadChar", function(input)
local
b, # byte
c; # character
b := ReadByte(input);
if b <> fail then
return CHAR_INT(b);
fi;
return fail;
end);
###########################################################################
##
#F CharIsSpace( <c> )
##
## True iff c is a space, newline or tabstop.
##
BindGlobal("CharIsSpace", c -> c in [' ','\n','\t']);
###########################################################################
##
#F ReadTag( <input>, <firstbyte> )
##
## Read a tag of the form < tag >
## return "<tag>" - no spaces
##
BindGlobal("ReadTag", function(input,firstbyte)
local
s, # the string to return
c, # the character read
d; # string to discard: contains encode or comment
s := "";
# find the first '<'
if CHAR_INT(firstbyte) in [' ','\n','\t','\r'] then
c := ReadCharSkipSpace(input);
else
c := CHAR_INT(firstbyte);
fi;
if c <> '<' then
return fail;
fi;
s[1] := c;
c := ReadCharSkipSpace(input);
# code inserted later to ensure encoding node (i.e <? ... ?>) is ignored
# ignore also things like <!-- this is a comment -->
if c = '?' or c = '!' then
d := "";
repeat
c := ReadChar( input );
if c = fail then
return fail;
fi;
Add( d, c );
until Length( d ) >= 2 and d{[ Length( d ) - 1 .. Length( d ) ]} = "?>"
or Length( d ) >= 3 and d{[ Length( d ) - 2 .. Length( d ) ]} = "-->";
# now find the real beginning of the tag
s := "";
c := ReadCharSkipSpace(input);
if c <> '<' then
return fail;
fi;
s[1] := c;
c := ReadCharSkipSpace(input);
fi;
repeat
if c = fail then
return fail;
fi;
Add( s, c );
c := ReadChar( input );
until c = '>';
while CharIsSpace( s[Length(s)] ) do
Unbind( s[Length(s)] );
od;
Add( s, c );
return s;
end);
###########################################################################
##
#F PipeOpenMathObject( <input>, <output>, <firstbyte> )
##
## Return "true" if we succeed in piping an OMOBJ from
## input to output, fail otherwise.
##
## Based on a very complicated finite state automaton
## which accepts "<OMOBJ>" then any amount of stuff
## and terminates with "<\OMOBJ>" unless it is inside
## a comment "<!-- -->".
##
BindGlobal("PipeOpenMathObject", function(input,output,firstbyte)
local
s, # string
EndOMOBJstates, # list of states all of which behave almost the same way
state, # current state
nextchar, # the next character we expect
c; # the last character read
# first read " <OMOBJ >"
s := ReadTag(input,firstbyte);
if not (IsList( s ) and Length( s ) > 6 and s{[ 1 .. 6 ]} = "<OMOBJ") then
return fail;
fi;
Append( output, s );
EndOMOBJstates:= ["InXMLRead</","InXMLRead</O","InXMLRead</OM",
"InXMLRead</OMO","InXMLRead</OMOB","InXMLRead</OMOBJ"];
# start state
state := "InXML";
c := ReadChar(input);
while c <> fail do
## Start state
if state = "InXML" then
if c = '<' then
state := "InXMLRead<";
fi;
## Read a `<`
elif state = "InXMLRead<" then
if c = '!' then
state := "InXMLRead<!";
elif c = '/' then
state := "InXMLRead</";
elif c <> '<' then # if c = '<' then we stay in this state
state := "InXML";
fi;
## Read some part of InXMLRead</OMOBJ
## these states are all dealt with together
elif state in EndOMOBJstates then
if state <> EndOMOBJstates[Length(EndOMOBJstates)] then # this isn't the last one
nextchar := EndOMOBJstates[Length(EndOMOBJstates)][Length(state)+1];
else
nextchar := '>';
# skip to next nonblank
while c <> fail and CharIsSpace(c) do
Append(output, [c]);
c := ReadChar(input);
od;
if c = fail then
return fail;
elif c = nextchar then
Append(output, [c]);
return true;
fi;
fi;
if c = nextchar then
state := Concatenation(state, [nextchar]);
elif c = '<' then
state := "InXMLRead<";
else
state := "InXML";
fi;
## now on to the comments
elif state = "InXMLRead<!" then
if c = '-' then
state := "InXMLRead<!-";
elif c = '<' then
state := "InXMLRead<";
else
state := "InXML";
fi;
elif state = "InXMLRead<!-" then
if c = '-' then
state := "InComment";
elif c = '<' then
state := "InXMLRead<";
else
state := "InXML";
fi;
elif state = "InComment" then
if c = '-' then
state := "InComment-";
fi;
elif state = "InComment-" then
if c = '-' then
state := "InComment--";
else
state := "InComment";
fi;
elif state = "InComment--" then
if c = '>' then
state := "InXML";
else
state := "InComment";
fi;
else
Error("Invalid state:",state);
fi;
# finally send the character off to the output and get the next one
Append(output, [c]);
c := ReadChar(input);
od;
return fail;
end);
###########################################################################
#E