-- ComStringA.Mesa Curry - September 26, 1980

DIRECTORY
AltoFileDefs,
Ascii,
ComString,
IODefs,
MiscDefs,
SegmentDefs,
StreamDefs,
StringDefs;

ComStringA: PROGRAM
IMPORTS
IODefs,
MiscDefs,
SegmentDefs,
StreamDefs,
StringDefs
EXPORTS ComString =
BEGIN
OPEN ComString, IODefs, StreamDefs, StringDefs;

OpenCommandLine:PUBLIC PROCEDURE
RETURNS [ in:DiskHandle ]=
BEGIN
OPENAltoFileDefs, MiscDefs, SegmentDefs;
cfa: POINTER TO CFA;
cfa ← CommandLineCFA[];
in ← CreateByteStream[InsertFile[@cfa.fp, Read], Read];
JumpToFA[in, @cfa.fa];
END;

CloseCommandLine
:PUBLIC PROCEDURE[in:StreamHandle]=
BEGIN
OPENAltoFileDefs, MiscDefs, SegmentDefs;
cfa: POINTER TO CFA;
streamIndex:StreamIndex;
cfa ← CommandLineCFA[];
streamIndex ← GetIndex[in];
streamIndex.page ← streamIndex.page + cfa.fa.page;
streamIndex.byte ← streamIndex.byte + cfa.fa.byte;
streamIndex ← NormalizeIndex[streamIndex];
cfa.fa.page ← streamIndex.page;
cfa.fa.byte ← streamIndex.byte;
in.destroy[in];
END;

StrToIndex : PUBLIC PROCEDURE
[ str:STRING, sad:StrArrayDesc ]
RETURNS [ index:CARDINAL ] = -- 0 => Not found
BEGIN
refstr:STRING;
i:CARDINAL;
FOR i←1, i+1 DO
refstr ← sad[i];
IF refstr = NIL THEN EXIT;
IF CompareStrings[refstr,str] = 0 THEN RETURN [i];
ENDLOOP;
RETURN [0];
END;

--
Tries to find str using sad:StrArrayDesc
--
If not found then found ← No
--
If str is part of or equal to only one string then
--
found ← Yes
--
unkstr is filled out
--
if addstr present
--
then addstr gets remainder of string
--
else the remainder is output using IODefs.WriteStr
--
If str is part of more than one string then
--
found ← Multiple
--
unkstr is filled out to point of disaggreement
--
if addstr # NILL
--
then addstr gets additions to string
--
else the additions are output using WriteStr
StrFill: PUBLIC PROCEDURE
[ unkstr:STRING, sad:StrArrayDesc, addstr:STRING ← NIL ]
RETURNS [ found:Found ] =
BEGIN
refstr:STRING ← [1];
tempstr:STRING ← [100];
comp:INTEGER ← 0;
i,j:CARDINAL ← 0;
refSstr, unkSstr:SubStringDescriptor ← [unkstr,0,unkstr.length];
found ← No;
FOR i←1, i+1 DO
refstr ← sad[i];
IF refstr = NIL THEN EXIT;
comp ← CompareStrings[unkstr,refstr];
IF comp = 1 THEN LOOP;
IF comp = 0 THEN GOTO Equal;
IF refstr.length <= unkstr.length THEN LOOP;
refSstr ← [refstr,0,unkstr.length];
IF NOT EquivalentSubString[@unkSstr,@refSstr]
THEN LOOP;
IF found = No
THEN BEGIN
refSstr.offset ← unkstr.length;
refSstr.length ← refstr.length - unkstr.length;
AppendSubString[tempstr, @refSstr]; END
ELSE FOR j IN [0..tempstr.length-1] DO
IF refstr.length > j+unkstr.length
AND tempstr[j] = refstr[j+unkstr.length]
THEN LOOP;
tempstr.length ← j;
IF j=0 THEN GOTO Nohelp;
EXIT; ENDLOOP;
IF found # No THEN found ← Multiple ELSE found ← Yes;
REPEAT
Equal => BEGIN found ← Yes; tempstr.length ← 0; END;
Nohelp => found ← Multiple;
ENDLOOP;
IF tempstr.length > 0 THEN
IF addstr # NIL THEN BEGIN
addstr.length ← 0; AppendString[addstr,tempstr]; END
ELSE WriteString[tempstr];
AppendString[unkstr,tempstr];
END;

GetKeyboardCommand:PUBLIC PROCEDURE
[queststr:STRING, sad:StrArrayDesc]
RETURNS[index:CARDINAL] =
BEGIN OPEN IODefs;
i,j:CARDINAL;
char:CHARACTER;
found:Found ← No;
resultstr:STRING ← [100];
WHILE found # Yes DO
resultstr.length ← 0;
WriteString[queststr];
DO
char ← ReadChar[];
SELECT char FROM
TAB, ESC => GOTO possibles;
’?, DEL, CR => GOTO restart;
ENDCASE =>
BEGIN
WriteChar[char];
AppendChar[resultstr, char];
found ← StrFill[ resultstr, sad];
IF found = Yes THEN GOTO foundIt;
IF found = No THEN GOTO restart;
END;
REPEAT
foundIt => EXIT;
possibles => FOR i←1, i+1 WHILE sad[i] # NIL DO
IF sad[i].length > resultstr.length THEN
FOR j IN [0..resultstr.length) DO
IF sad[i][j] # resultstr[j] THEN EXIT;
REPEAT FINISHED => BEGIN
WriteChar[SP]; WriteString[sad[i]]; END;
ENDLOOP;
ENDLOOP;
restart =>
BEGIN WriteChar[CR];WriteString["Commands are: "];
FOR i IN [1..100) WHILE sad[i] # NIL DO
WriteString[sad[i]]; WriteChar[SP]; ENDLOOP; END;
ENDLOOP;
WriteChar[CR];
ENDLOOP;
index ← StrToIndex[resultstr,sad];
END;

GetStreamCommand:PUBLIC PROCEDURE[
stream:StreamHandle,
sad:StrArrayDesc,
substr:STRING]
RETURNS[index:CARDINAL] = -- 0 if command not found
BEGIN
comstring:STRING ← [100];
[] ← GetStreamArg[stream, comstring, substr];
index ← StrToIndex[comstring,sad]
END;

GetStreamArg:PUBLIC PROCEDURE[
stream:StreamHandle,
argstr:STRING,
substr:STRING ]
RETURNS[argfound:BOOLEAN] =
BEGIN
get:PROCEDURE RETURNS[CHARACTER] =
BEGIN RETURN[ stream.get[stream]] END;
end:PROCEDURE RETURNS[BOOLEAN] =
BEGIN RETURN[ stream.endof[stream]] END;
RETURN[GetArg[get, end, argstr, substr]];
END;

-- Parses sourcestr starting at index to get next arg
-- Returns 0 if arg not found
-- Otherwise returns index of next char
-- Strings rep: SingArgStr/SubStr or SingArgStr[SubStr]
GetStringArg:PUBLIC PROCEDURE[
sourcestr:STRING,
index:CARDINAL,
argstr:STRING,
substr:STRING]
RETURNS[CARDINAL] =
BEGIN
get:PROCEDURE RETURNS[CHARACTER] =
BEGIN index ← index + 1; RETURN[sourcestr[index-1]] END;
end:PROCEDURE RETURNS[BOOLEAN] =
BEGIN RETURN[ index >= sourcestr.length] END;
IF GetArg[get, end, argstr, substr]
THEN RETURN[index]
ELSE RETURN[ 0 ];
END;

-- argstr/substr or argstr[substr]
GetArg:PROCEDURE[
get:PROCEDURE RETURNS[CHARACTER],
end:PROCEDURE RETURNS[BOOLEAN],
argstr, substr:STRING ]
RETURNS[ BOOLEAN ] =
BEGIN OPEN IODefs;
char:CHARACTER;
argstr.length ← substr.length ← 0;
char ← GetNextGoodChar[get, end];
IF char # NUL THEN DO
SELECT char FROM
’/ => GOTO getSingleArg;
’[ => GOTO getMultipleArgs;
SP, TAB, CR, ’, => EXIT;
ENDCASE => AppendChar[argstr, char];
IF end[] THEN EXIT;
char ← get[];
REPEAT
getSingleArg =>
BEGIN
WHILE NOT end[] DO
char ← get[];
IF char = SP
OR char = TAB
OR char = ’,
OR char = CR THEN EXIT;
AppendChar[substr,char];
ENDLOOP;
END;
getMultipleArgs =>
BEGIN
WHILE NOT end[] DO
char ← get[];
IF char = ’] THEN EXIT;
AppendChar[substr,char];
ENDLOOP;
END;
ENDLOOP;
IF argstr.length # 0 OR substr.length # 0
THEN RETURN[ TRUE ]
ELSE RETURN[ FALSE ];
END;


GetNextGoodChar
:PROCEDURE[
get:PROCEDURE RETURNS[CHARACTER],
end:PROCEDURE RETURNS[BOOLEAN] ]
RETURNS[CHARACTER] =
BEGIN char:CHARACTER;
WHILE NOT end[] DO
char ← get[];
SELECT char FROM
IN[’0..’9], IN[’a..’z], IN[’A..’Z], ’. => EXIT;
ENDCASE => LOOP;
REPEAT
FINISHED => RETURN[NUL];
ENDLOOP;
RETURN[char];
END;

END.