-- The Program FogIO.
-- The file handler for program Fog.

-- Documentation on [Ivy]<McKeeman>FogReport.press.
-- Last edited by McKeeman on December 17, 1980 3:41 PM
-- Last edited by Brotz on December 16, 1980 2:51 PM
-- Version for Laurel RUN command.
-- Author: W.M. McKeeman.
-- Consultants: J.J. Horning, D. Brotz.

DIRECTORY
Ascii,
FogDefs,
FrameDefs,
inD: FROM "InteractorDefs",
InlineDefs,
InsertMailDefs,
intCommon,
IODefs,
LaurelExecDefs,
SegmentDefs,
StreamDefs,
TimeDefs,
ovD: FROM "OverviewDefs",
vmD: FROM "VirtualMgrDefs";

FogIO:
PROGRAM
IMPORTS FogDefs, FrameDefs, InlineDefs, InsertMailDefs,
intC: intCommon, IODefs, LaurelExecDefs, SegmentDefs, StreamDefs,
TimeDefs, vmD
EXPORTS FogDefs =
BEGIN OPEN FogDefs;
-- Global variables and constants.
-- A counter for the last LA characters after EoF is sensed.
chleft:INTEGER;
-- A counter for the input characters processed.
chprocessed:LONG CARDINAL ← 0;
laurelPresent: BOOLEAN = FrameDefs.IsBound[LaurelExecDefs.MakeMenuCommandCallable];
message: vmD.ComposeMessagePtr
← IF laurelPresent THEN LOOPHOLE[intC.cmTextNbr.message] ELSE NIL;
messageLength: ovD.CharIndex
← IF laurelPresent AND message # NIL THEN
vmD.GetMessageSize[message] ELSE 0;
charIndex: ovD.CharIndex ← 0;
outMessage: vmD.ComposeMessagePtr ← NIL;

Ch: PUBLIC ARRAY [0..LA] OF CHARACTER;
-- Steady state:EoF=FALSEchleft=2 |ch|ch|ch|
-- after EoFEoF=TRUEchleft=1 |ch|ch|? |
-- EoF=TRUEchleft=0 |ch|? |? |

FileIn, FileOut, Keyboard: StreamDefs.StreamHandle;
EoS:PUBLIC SIGNAL = CODE; -- End of Stream, LA characters after EoF.
QuickQuit:SIGNAL = CODE; -- User hit DEL to stop processing.

Open
:
PROCEDURE[FileName: STRING] RETURNS [h: StreamDefs.StreamHandle] =
BEGIN
-- Hook onto composition window.
SELECT TRUE FROM
laurelPresent =>
BEGIN
h ← NIL;
IF FileName[4] = ’o THEN -- kludge to identify "Fog.out"
BEGIN
outMessage ← vmD.AllocateComposeMessageObject[];
vmD.InitComposeMessage[outMessage, ""L];
END;
END;
FileName[4] = ’o => -- kludge to identify "Fog.out"
BEGIN
h ← StreamDefs.CreateByteStream[
SegmentDefs.NewFile
[FileName, StreamDefs.Write+StreamDefs.Append,
SegmentDefs.DefaultVersion],
StreamDefs.Write+StreamDefs.Append];
IODefs.SetOutputStream[h];
END;
FileName[4] = ’i => -- kludge to identify "Fog.in"
BEGIN
h ← StreamDefs.CreateByteStream[
SegmentDefs.NewFile[FileName, StreamDefs.Read, SegmentDefs.DefaultVersion],
StreamDefs.Read];
IODefs.SetInputStream[h];
END;
ENDCASE => ERROR;
END;
Close:
PROCEDURE[File: StreamDefs.StreamHandle] =
BEGIN
IF laurelPresent THEN
BEGIN
IF outMessage # NIL THEN
BEGIN
InsertMailDefs.InsertVMInMailFile
[outMessage, vmD.GetFirstFreeTOCIndex[]];
vmD.FreeVirtualMessageObject[outMessage];
END;
outMessage ← NIL;
END
ELSE File.destroy[File];
END;
EoF:
PUBLIC PROCEDURE[File: StreamDefs.StreamHandle] RETURNS[BOOLEAN] =
BEGIN -- Detect end-of-file in composition window.
IF laurelPresent THEN RETURN[charIndex >= messageLength]
ELSE RETURN[File.endof[File]];
END;

GetChar:
PUBLIC PROCEDURE[] RETURNS[char: CHARACTER] =
BEGIN -- Read character from input file.
IF laurelPresent THEN
BEGIN
char ← vmD.GetMessageChar[message, charIndex];
charIndex ← charIndex + 1;
END
ELSE RETURN[IODefs.ReadChar[]];
chprocessed ← chprocessed + 1; -- Count the input characters.
END;

PutChar:
PUBLIC PROCEDURE[ch: CHARACTER] =
BEGIN -- Pass character to output file.
IF laurelPresent THEN [] ← vmD.AppendMessageChar[outMessage, ch]
ELSE IODefs.WriteChar[ch] -- Pass ch to the output file.
END;

PutString:
PUBLIC PROCEDURE[s: STRING] =
BEGIN -- Pass string to output file.
FOR i: CARDINAL IN [0..s.length) DO PutChar[s[i]] ENDLOOP;
END;

PutDecimal:
PUBLIC PROCEDURE[n: LONG CARDINAL] =
BEGIN -- Pass character to output file.
digit: ARRAY[0..20] OF CHARACTER;
i, j: INTEGER;
FOR i DECREASING IN [0..20] DO
digit[i] ← ’0 + InlineDefs.LowHalf[n MOD 10];
n ← n / 10;
IF n = 0 THEN EXIT;
ENDLOOP;
FOR j IN [i..20] DO PutChar[digit[j]] ENDLOOP;
END;

StepInputOutput:
PUBLIC PROCEDURE =
BEGIN -- Pass examined character to output file and update lookahead.
PutChar[FogDefs.Ch[0]];
StepInput[];
END;
StepInput:
PUBLIC PROCEDURE =
BEGIN -- Update lookahead with fresh input (if any).
i: INTEGER;
-- Give the user a chance to signal DEL.
WHILE ~Keyboard.endof[Keyboard] DO
IF Keyboard.get[Keyboard] = Ascii.DEL THEN SIGNAL QuickQuit;
ENDLOOP;
IF chleft=0 THEN SIGNAL EoS;

-- Push lookahead up.
FOR i IN [0..FogDefs.LA) DO FogDefs.Ch[i] ← FogDefs.Ch[i+1] ENDLOOP;
FogDefs.Ch[FogDefs.LA] ← Ascii.NUL; -- Default lookahead beyond EoF.
IF chleft = FogDefs.LA AND EoF[FileIn] THEN chleft ← FogDefs.LA-1
ELSE IF chleft = FogDefs.LA THEN FogDefs.Ch[FogDefs.LA] ← GetChar[]
ELSE chleft ← chleft-1;
END;
ReportStatistics:
PUBLIC PROCEDURE[Index, Fogp, Fogs, Fogw: LONG INTEGER] =
BEGIN
PutChar[Ascii.CR]; PutChar[Ascii.CR];
PutString["‘‘‘ Fog Analysis: [P S W] = ["];
PutDecimal[Fogp];
PutChar[Ascii.SP];
PutDecimal[Fogs]; PutChar[Ascii.SP];
PutDecimal[Fogw]; PutString["], Fog Index = "];
PutDecimal[Index]; PutChar[’.];
PutChar[Ascii.CR]; PutChar[Ascii.CR];
END;
Prolog:
PROCEDURE =
BEGIN
i: INTEGER;
d: STRING ← [100];

Keyboard ← IODefs.GetInputStream[];
-- Set up IO path to composition window.
FileIn ← Open["Fog.in"];
FileOut ← Open["Fog.out"];

-- Header.
PutString["Date: "];
d.length ← 0;
TimeDefs.AppendDayTime[d, TimeDefs.UnpackDT[TimeDefs.CurrentDayTime[]]];
PutString[d];
PutChar[Ascii.CR];
PutString["From: Fog"];
PutChar[Ascii.CR];
PutString["Subject: Analysis: [P S W] signifies complexity is in Paragraph, Sentence and Word structure, respectively."];
PutChar[Ascii.CR]; PutChar[Ascii.CR];

-- Set up lookahead.
IF EoF[FileIn] THEN SIGNAL EoS; -- Ridiculously short file.
FOR i IN [0..FogDefs.LA]
DO
IF EoF[FileIn] THEN EXIT -- Ridiculously short file.
ELSE FogDefs.Ch[i] ← GetChar[];
chleft ← i;
ENDLOOP;
END;
Epilog:
PROCEDURE[ReportParagraphs, RecordFog, TotalFog, Reports: LONG INTEGER] =
BEGIN
-- Print trailing information.
PutChar[Ascii.CR]; PutChar[Ascii.CR];
PutString["‘‘‘ End of fog index utility run:"];
PutChar[Ascii.CR];
PutDecimal[ReportParagraphs];
PutString[" paragraphs consisting of "];
PutDecimal[chprocessed];
PutString[" characters processed."];
PutChar[Ascii.CR];
PutString["Maximum index = "];
PutDecimal[RecordFog];
IF Reports>0 THEN
BEGIN -- Avoid divide by zero in pathological cases.
PutString[", average index = "];
PutDecimal[TotalFog/Reports];
END;
PutChar[Ascii.CR];
END;
Main:
PROCEDURE =
BEGIN
ENABLE
BEGIN
EoS => GOTO NullFile;
QuickQuit => GOTO QuickAbort;
END;
ReportParagraphs, RecordFog, TotalFog, Reports: LONG INTEGER;
Prolog[];

[ReportParagraphs, RecordFog, TotalFog, Reports] ← FogDefs.ComputeFog[];


-- Report results in composition window.
Epilog[ReportParagraphs, RecordFog, TotalFog, Reports];
Close[FileIn]; Close[FileOut];

EXITS
NullFile =>
BEGIN
PutString["‘‘‘ Empty input file."];
Close[FileIn]; Close[FileOut];
END;

QuickAbort =>
BEGIN
PutChar[Ascii.CR];
PutString["‘‘‘ User-requested abrupt termination."];
PutChar[Ascii.CR];
Close[FileIn]; Close[FileOut];
END;

END;
Main[];
END.