-- N.Wirth June 1, 1977
-- S.Andler August 24, 1977 10:52 PM
-- C.Geschke August 31, 1977 12:00 PM
-- E.Satterthwaite September 9, 1977 10:41 AM
DIRECTORY
AltoFileDefs: FROM "AltoFileDefs",
DirectoryDefs: FROM "DirectoryDefs",
InlineDefs: FROM "InlineDefs",
IODefs: FROM "IODefs",
SegmentDefs: FROM "SegmentDefs",
StreamDefs: FROM "StreamDefs",
StringDefs: FROM "StringDefs",
SystemDefs: FROM "SystemDefs",
TeleSilDefs: FROM "TeleSilDefs",
TeleSilProcDefs: FROM "TeleSilProcDefs";

DEFINITIONS FROM
StreamDefs,
-- StreamHandle, CreateWordStream, ReadBlock,
-- WriteBlock, destroy, get, put, endof
SegmentDefs;
-- FileHandle, InsertFile, Read, Write, Append

--------------------------------------------------------------------
TeleSilIO: PROGRAM
IMPORTS
DirectoryDefs, IODefs, SegmentDefs, StreamDefs, StringDefs, SystemDefs,
TeleSilProcDefs
EXPORTS TeleSilProcDefs =
BEGIN
OPEN
TeleSilProcDefs,
-- Confirm, Error, FontLoaded, FontName,
-- AllocateObject, Rover
TeleSilDefs;

IsLetter: PROCEDURE[ch: CHARACTER] RETURNS[BOOLEAN]=
BEGIN RETURN [ch IN [’a..’z] OR ch IN [’A..’Z]] END;

--------------------------------------------------------------------
-- INPUT/OUTPUT
-- defines Input, Output, DefaultExtension

FileCodeWord: CARDINAL= 31459;
fileName: STRING ← [40];
FileObject: TYPE= MACHINE DEPENDENT RECORD[
kind: ObjKind,
state: ObjState,
fill: [0..777B],
-- keep specifics right justified
specifics: [0..7], -- shade for area, fontno for text
zone: Zone,
dummy: WORD];

Input: PUBLIC PROCEDURE=
BEGIN OPEN IODefs;
old: BOOLEAN;
sh: StreamHandle;
fh: FileHandle;
fp: AltoFileDefs.FP;
eof: BOOLEAN ← FALSE;

EndOfFile: PROCEDURE RETURNS[BOOLEAN] = BEGIN RETURN[eof] END;
GetWord: PROCEDURE RETURNS[WORD]=
BEGIN
eof ← sh.endof[sh];
RETURN[IF eof THEN 0 ELSE sh.get[sh]]
END;
GetBlock: PROCEDURE[address: POINTER, words: INTEGER]=
BEGIN
eof ← sh.endof[sh];
IF eof THEN RETURN;
[]←ReadBlock[sh, address, words]
END;

WriteString["File: "]; ReadID[fileName];
DefaultExtension[fileName, "telesil"]; WriteLine[""];
old ← DirectoryDefs.DirectoryLookup[@fp, fileName, FALSE];
IF NOT old THEN BEGIN Error["File not found"]; RETURN END;
fh ← InsertFile[@fp, Read];
sh ← CreateWordStream[fh, Read];
InputFile[EndOfFile, GetWord, GetBlock];
sh.destroy[sh]
END;

InputFile: PUBLIC PROCEDURE[
EndOfFile: PROCEDURE RETURNS[BOOLEAN],
GetWord: PROCEDURE RETURNS[WORD],
GetBlock: PROCEDURE[address: POINTER, words: INTEGER]]=
BEGIN
n: CARDINAL;
ppObj: POINTER TO ObjPtr ← Rover[];
fileObj: FileObject;

IF GetWord[]#FileCodeWord THEN Error["Not a picture file"]
ELSE
DO
GetBlock[@fileObj, SIZE[FileObject]];
IF EndOfFile[] THEN EXIT;
AllocateObject[fileObj.kind];
ppObj.zone ← fileObj.zone;
ppObj.state ← fileObj.state;
WITH ppObj↑ SELECT FROM
area => shade ← fileObj.specifics;
text =>
BEGIN
fontno ← fileObj.specifics;
n ← GetWord[];
str ← SystemDefs.AllocateHeapString[n];
str.length ← n;
IF NOT FontLoaded[fontno] THEN fontno ← 0;
GetBlock[str+2, StringDefs.WordsForString[n]-2]
END;
ENDCASE;
ENDLOOP;
END;

Output: PUBLIC PROCEDURE=
BEGIN OPEN IODefs;
old: BOOLEAN;
sh: StreamHandle;
fh: FileHandle;
fp: AltoFileDefs.FP;

PutWord: PROCEDURE[word: WORD] = BEGIN sh.put[sh, word] END;
PutBlock: PROCEDURE[address: POINTER, words: INTEGER]=
BEGIN [] ← WriteBlock[sh, address, words] END;

WriteString["File: "]; ReadID[fileName];
DefaultExtension[fileName, "telesil"]; WriteLine[""];
old ← DirectoryDefs.DirectoryLookup[@fp, fileName, TRUE];
IF old THEN
BEGIN
WriteString["Existing file"];
IF NOT Confirm[] THEN RETURN
END;
fh ← InsertFile[@fp, Write+Append];
sh ← CreateWordStream[fh, Write+Append];
OutputFile[PutWord, PutBlock];
sh.destroy[sh]
END;

OutputFile: PUBLIC PROCEDURE[
PutWord: PROCEDURE[word: WORD],
PutBlock: PROCEDURE[address: POINTER, words: INTEGER]]=
BEGIN
n: CARDINAL;
rover: ObjPtr ← Rover[]↑;
stop: ObjPtr ← rover;
fileObj: FileObject;

PutWord[FileCodeWord];
IF rover#NIL THEN
DO
IF rover.state#dead THEN
BEGIN
fileObj.kind ← rover.kind;
fileObj.state ← rover.state;
fileObj.fill ← 0;
fileObj.specifics ←
WITH rover SELECT FROM
area => shade,
text => fontno,
ENDCASE => 0;
fileObj.zone ← rover.zone;
fileObj.dummy ← 0;
PutBlock[@fileObj, SIZE[FileObject]];
WITH rover SELECT FROM
text =>
BEGIN
n ← str.length;
PutWord[n];
PutBlock[str+2, StringDefs.WordsForString[n]-2]
END;
ENDCASE;
END;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP;
END;

DefaultExtension: PUBLIC PROCEDURE[fileName, extension: STRING]=
BEGIN -- check if fileName has an extension, otherwise extend it
i: CARDINAL;
FOR i IN [0..fileName.length) DO IF fileName[i]=’. THEN RETURN ENDLOOP;
StringDefs.AppendString[fileName, "."]; IODefs.WriteString["."];
StringDefs.AppendString[fileName, extension]; IODefs.WriteString[extension]
END;

--------------------------------------------------------------------
-- HARDCOPY: Generate press format file
-- defines HardCopy

HardCopy: PUBLIC PROCEDURE=
BEGIN OPEN InlineDefs, --
BITAND, BITOR, BITSHIFT
IODefs;
scale: CARDINAL= 35; -- 35 micas per unit length
i, k, k1, pad: CARDINAL;
n: CARDINAL ← 0; -- no. of words written
even: BOOLEAN ← TRUE; -- no. of bytes written is even
buf: UNSPECIFIED;
old: BOOLEAN;
rover: ObjPtr ← Rover[]↑;
stop: ObjPtr ← rover;
sh: StreamHandle;
fh: FileHandle;
fp: AltoFileDefs.FP;
PartDirPageNo, FontDirPageNo: CARDINAL;
fchar: CHARACTER;
fname: STRING;
hardCopyFileName: STRING ← [40];

PW: PROCEDURE[w: UNSPECIFIED]=
BEGIN -- write one word on file
IF even THEN sh.put[sh, w]
ELSE
BEGIN
sh.put[sh, BITOR[BITSHIFT[buf,8], BITSHIFT[w,-8]]];
buf ← BITAND[w, 377B]
END;
n ← n+1
END;

PB: PROCEDURE[b: UNSPECIFIED]=
BEGIN -- write one byte on wordfile
IF even THEN buf ← b
ELSE BEGIN sh.put[sh, BITOR[BITSHIFT[buf,8], b]]; n ← n+1 END;
even ← NOT even
END;

Fill: PROCEDURE=
BEGIN
N: CARDINAL ← 0;
IF NOT even THEN PB[0];
WHILE N < n DO N ← N+256 ENDLOOP;
WHILE n < N DO sh.put[sh, 0]; n ← n+1 ENDLOOP
END;

Position: PROCEDURE=
BEGIN
PB[356B]; PW[scale * rover.zone.point.x];
PB[357B]; PW[scale*(BMMaxHeight-rover.zone.point.y-rover.zone.h)];
END;

Size: PROCEDURE=
BEGIN PB[376B]; PW[scale * rover.zone.w]; PW[scale * rover.zone.h] END;

FOR i IN [0..fileName.length) DO
IF fileName[i] = ’. THEN EXIT
ELSE hardCopyFileName[i] ← fileName[i]
ENDLOOP;
IF fileName.length = 0 THEN i ← 0;
hardCopyFileName.length ← i;
StringDefs.AppendString[hardCopyFileName, ".press"];
WriteString["File: "]; ReadID[hardCopyFileName];
DefaultExtension[hardCopyFileName, "press"]; WriteLine[""];
old ← DirectoryDefs.DirectoryLookup[@fp, hardCopyFileName, TRUE];
IF old THEN
BEGIN WriteString[" Existing file"]; IF NOT Confirm[] THEN RETURN END;
fh ← InsertFile[@fp, Write+Append];
sh ← CreateWordStream[fh, Write+Append];

-- 1: the printed page

IF rover#NIL THEN
DO
IF rover.state#dead THEN
WITH rover SELECT FROM
text => FOR i IN [0..str.length) DO PB[str[i]] ENDLOOP;
ENDCASE;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP;
IF even THEN k ← 2*n ELSE BEGIN k ← 2*n+1; PB[0] END;
PW[0]; k1 ← n;
IF rover#NIL THEN
DO
IF rover.state#dead THEN
WITH rover SELECT FROM
area => BEGIN Position; PB[370B]; PB[(black - shade) * 40B]; Size END;
ENDCASE;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP;
PB[370B]; PB[0];
IF rover#NIL THEN
DO
IF rover.state#dead THEN
WITH rover SELECT FROM
line => BEGIN Position; Size END;
area => NULL;
text => BEGIN Position; PB[fontno + 160B]; PB[360B]; PB[str.length] END;
ENDCASE;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP;
IF NOT even THEN PB[377B];
PB[0]; PB[0]; PW[0]; PW[0]; PW[0]; PW[k]; -- entity trailer
PW[0]; PW[0]; PW[0]; PW[0]; PW[0]; PW[0];
PW[n-k1+1]; -- entity length
pad ← n; Fill; pad ← n-pad;

-- 2: the font directory

FontDirPageNo ← n/256;
FOR i IN FontNumber DO
IF FontLoaded[i] THEN
BEGIN
PW[16]; PB[0]; PB[i]; PB[0]; PB[177B];
fname ← FontName[i];
FOR k ← 0, k+1 WHILE IsLetter[fname[k]] DO ENDLOOP;
PB[k];
FOR k1 IN [0..k) DO
fchar ← fname[k1];
IF fchar>’Z THEN fchar ← LOOPHOLE[BITAND[LOOPHOLE[fchar], 137B]];
PB[fchar]
ENDLOOP;
THROUGH [k..19) DO PB[0] ENDLOOP;
k1 ← 0; fchar ← fname[k];
WHILE fchar IN [’0..’9] DO
k1 ← 10*k1+(LOOPHOLE[fchar, CARDINAL]-60B);
k ← k+1; fchar ← fname[k]
ENDLOOP;
PB[0]; PB[0]; PW[k1]; PW[0]
END
ENDLOOP;
PW[0]; Fill;

-- 3: the part directory

PartDirPageNo ← n/256;
PW[0]; PW[0]; PW[FontDirPageNo]; PW[pad];
PW[1]; PW[FontDirPageNo]; PW[1]; PW[0];
PW[0]; Fill;

-- 4: the document directory

PW[27183]; PW[n/256+1]; PW[2]; PW[PartDirPageNo];
PW[1]; PW[0]; PW[-1]; PW[-1]; PW[0]; PW[0];
Fill; sh.destroy[sh]
END;

END.