-- File: OthelloLisp.mesa
-- Created 9-Jul-84 15:06:38 Lichtenberg
DIRECTORY
CommonSoftwareFileTypes USING [tCarryVolumeDirectory],
Environment USING [wordsPerPage, Byte],
File USING [Type,
Create, Delete, File, MakePermanent, nullFile, PageNumber, PageCount, GetSize, SetSize, Unknown ],
FileTypes USING [tUntypedFile],
Floppy USING [Open, Close, FileHandle, nullFileID,GetNextFile, ErrorType, Error,
VolumeHandle, Read, PageCount, PageNumber],
Inline USING [LongCOPY],
OthelloDefs,
OthelloOps USING [
BootFileType,
MakeBootable, MakeUnbootable,
GetPhysicalVolumeBootFile, VoidPhysicalVolumeBootFile,
SetVolumeBootFile, GetVolumeBootFile, VoidVolumeBootFile
],
PhysicalVolume USING [ID],
System USING [GreenwichMeanTime, gmtEpoch],
Space USING [Map, CopyIn, Unmap, Window],
TemporaryBooting USING [InvalidParameters],
Time USING [Unpacked,Unpack,Append],
Volume USING [Close, ID, GetAttributes, nullID, InsufficientSpace, Open ];
-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
OthelloLisp: PROGRAM
IMPORTS
File, OthelloDefs, OthelloOps, Floppy,
Space, TemporaryBooting, Time, Volume, Inline =
BEGIN
-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-- These definitions stolen from AccessFloppy
-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Attributes: TYPE = LONG POINTER TO AttributesRecord;
AttributesRecord: TYPE = MACHINE DEPENDENT RECORD[ -- used by directory or leader page.
-- identity attributes
seal: WORD ← sealValue, -- used to check consistency of a file.
version: CARDINAL, -- version of attributes record type.
type: File.Type, -- file type of containing file.
-- activity attributes
createDate: FloppyTime, -- the creation data of the disk file.
lastWrittenDate: FloppyTime, -- the date the disk file was last modified prior to copying to the floppy.
-- file attributes
size: Floppy.PageCount ← 0, -- number of pages in the floppy file not including the leader page.
offset: Floppy.PageNumber ← 0, -- page number in the disk file correspoinding to the first page in the floppy file piece.
totalSize: Floppy.PageCount ← 0, -- number of pages in the disk file.
totalSizeInBytes: LengthInBytes ← 0, -- the number of bytes in the disk file
-- name attributes
length: CARDINAL ← 0,
maxLength: CARDINAL ← maxNameLength, -- so that @length is STRING.
name: PACKED ARRAY [0..maxNameLength) OF Environment.Byte,
-- client attributes
clientDataLength: CARDINAL ← 0 ,-- number of component in client's private data.
clientData: SEQUENCE maxlength: CARDINAL OF UNSPECIFIED
];
LengthInBytes: TYPE = LONG CARDINAL;
FloppyTime: TYPE = System.GreenwichMeanTime;
tFloppyLeaderPage: File.Type = CommonSoftwareFileTypes.tCarryVolumeDirectory;
-- Constants
leaderLength: CARDINAL = 1;
-- leaderLength*Environment.wordsPerPage must be greater than SIZE[AttributesRecord]
maxDataSize: CARDINAL = leaderLength*Environment.wordsPerPage - SIZE[AttributesRecord];
maxNameLength: CARDINAL = 100;
-- includes words field.
nullTime: FloppyTime = System.gmtEpoch;
sealValue: WORD = 125252B; -- 1010101010101010 bits pattern
-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
CopyVM: PROC = BEGIN
fromVolume, toVolume: Volume.ID;
fromFile, toFile: File.File;
pvID: PhysicalVolume.ID;
error: BOOLEAN ← FALSE;
currentBase: File.PageNumber;
nextCount: File.PageCount;
fromWindow,toWindow: Space.Window;
toPointer: LONG POINTER;
fromFileSize: File.PageCount;
tries: CARDINAL;
toFileSize: File.PageCount;
minFileSize: File.PageCount;
OthelloDefs.MyNameIs[
myNameIs: "Copy Lisp From Another Volume"L,
myHelpIs: "Copies lisp from one volume to another"L];
[pvID, fromVolume] ← OthelloDefs.GetLvIDFromUser[prompt:"Volume to copy from: "L];
IF fromVolume = Volume.nullID THEN OthelloDefs.AbortingCommand["Invalid volume."L];
toVolume ← OthelloDefs.GetLvIDFromUser[prompt:"Volume to copy to: "L].lvID;
IF toVolume = Volume.nullID THEN OthelloDefs.AbortingCommand["Invalid volume."L];
-- Open up the volumes
Volume.Open[fromVolume];
Volume.Open[toVolume];
-- Is there a source file?
fromFile ← OthelloOps.GetVolumeBootFile[fromVolume,hardMicrocode].file;
IF fromFile = File.nullFile THEN {
Volume.Close[fromVolume];
Volume.Close[toVolume];
OthelloDefs.AbortingCommand["No Lisp sysout on source volume"L];
};
-- Is there a dest file? Delete it if yes.
toFile ← OthelloOps.GetVolumeBootFile[toVolume,hardMicrocode].file;
IF toFile # File.nullFile THEN {
OthelloOps.VoidVolumeBootFile[toVolume,hardMicrocode];
File.Delete[toFile];
IF OthelloOps.GetPhysicalVolumeBootFile[pvID,hardMicrocode].file = toFile
THEN OthelloOps.VoidPhysicalVolumeBootFile[pvID,hardMicrocode];
};
-- Create the dest file
fromFileSize ← File.GetSize[fromFile];
toFileSize ← fromFileSize;
tries ← 20;
toFile ← File.Create[toVolume, toFileSize, FileTypes.tUntypedFile
! Volume.InsufficientSpace =>
{ tries ← tries - 1;
toFileSize ← toFileSize - 100;
OthelloDefs.WriteString["."L];
IF tries = 0 OR toFileSize < 0 THEN {error ← TRUE;
CONTINUE}
ELSE RETRY;};];
IF error THEN {Volume.Close[fromVolume];
Volume.Close[toVolume];
OthelloDefs.AbortingCommand["Destination volume does not contain sufficient space!"L];};
File.MakePermanent[toFile];
-- Create windows onto the file
OthelloDefs.WriteString["Copying..."L];
currentBase ← 0;
nextCount ← 100;
minFileSize ← fromFileSize;
IF toFileSize < fromFileSize THEN minFileSize ← toFileSize;
DO -- until file has been copied
fromWindow ← [file: fromFile,
base: currentBase,
count: nextCount];
toWindow ← [file: toFile,
base: currentBase,
count: nextCount];
toPointer ← Space.Map[toWindow].pointer;
nextCount ← Space.CopyIn[toPointer,fromWindow];
toPointer ← Space.Unmap[toPointer];
currentBase ← currentBase + nextCount;
OthelloDefs.WriteString["."L];
IF currentBase >= minFileSize THEN EXIT;
ENDLOOP;
OthelloDefs.WriteString["Installing..."L];
OthelloOps.MakeBootable[toFile, hardMicrocode, OthelloDefs.leaderPages
! TemporaryBooting.InvalidParameters => {
OthelloDefs.WriteLine["Warning, trouble making bootable"L]; CONTINUE}];
OthelloOps.SetVolumeBootFile[toFile,hardMicrocode,OthelloDefs.leaderPages];
OthelloDefs.WriteLine["done"L];
Volume.Close[fromVolume];
Volume.Close[toVolume];
END;
-- UGH.. This kludge sets the file's size to be as big as Pilot will let it be, on 100 page increments.
SetBootFileSize: PRIVATE PROC[file: File.File, lvID: Volume.ID] = BEGIN
tries: CARDINAL;
oldSize: File.PageCount ← File.GetSize[file];
newSize: File.PageCount ← oldSize + Volume.GetAttributes[lvID].freePageCount;
tries ← 20;
OthelloOps.MakeUnbootable[file, hardMicrocode, OthelloDefs.leaderPages];
File.SetSize[file, newSize
! File.Unknown => {OthelloDefs.WriteLine["Warning: Trouble making file fill volume - File.Unknown"L];
CONTINUE};
Volume.InsufficientSpace => {OthelloDefs.WriteString["."L]; newSize ← newSize - 100;
tries ← tries - 1;
IF tries = 0 OR newSize < oldSize THEN {OthelloDefs.WriteLine["Warning: Expanding volume failed!"]; CONTINUE;} ELSE RETRY};];
OthelloOps.MakeBootable[file,hardMicrocode, OthelloDefs.leaderPages];
END;
ExpandVM: PROC = BEGIN
pvID: PhysicalVolume.ID;
exVolume: Volume.ID;
exFile: File.File;
OthelloDefs.MyNameIs[
myNameIs: "Expand Vmem File"L,
myHelpIs: "Expand the lisp virtual mem file on a volume"L];
[pvID, exVolume] ← OthelloDefs.GetLvIDFromUser[prompt:"Volume to expand: "L];
IF exVolume = Volume.nullID THEN OthelloDefs.AbortingCommand["Invalid volume."L];
Volume.Open[exVolume];
exFile ← OthelloOps.GetVolumeBootFile[exVolume, hardMicrocode].file;
IF exFile = File.nullFile THEN OthelloDefs.AbortingCommand["No sysout on volume."L];
OthelloDefs.WriteString["Expanding file..."L];
SetBootFileSize[exFile,exVolume];
OthelloDefs.WriteLine["Done."L];
Volume.Close[exVolume];
END;
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- FLOPPY commands
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ListFloppyFiles: PROC = BEGIN
floppyHandle: Floppy.VolumeHandle;
attRec: AttributesRecord;
floppyFileAttributes: Attributes ← @attRec;
currentFloppyFile: Floppy.FileHandle ← [floppyHandle,Floppy.nullFileID];
i: CARDINAL;
timeTemp: STRING;
unpackedTime: Time.Unpacked;
floppyFileAttributes ← @attRec;
-- Open floppy
OthelloDefs.MyNameIs[myNameIs: "List Floppy Files"L,
myHelpIs: "List files on pilot floppy"L];
floppyHandle ← Floppy.Open[
! Floppy.Error => {PrintNames: PROC [x: Floppy.ErrorType] =
{ShowFloppyError[x]};};];
-- Enumerate files
DO
currentFloppyFile ← Floppy.GetNextFile[currentFloppyFile];
IF currentFloppyFile.file = Floppy.nullFileID THEN EXIT;
ReadLeaderPage[currentFloppyFile, floppyFileAttributes];
FOR i IN [0..floppyFileAttributes.length) DO
OthelloDefs.WriteChar[LOOPHOLE[floppyFileAttributes.name[i]]];
ENDLOOP;
THROUGH [0..(60-floppyFileAttributes.length)) DO
OthelloDefs.WriteChar[' ];
ENDLOOP;
OthelloDefs.WriteLongNumber[floppyFileAttributes.size];
OthelloDefs.WriteString[" "L];
unpackedTime ← Time.Unpack[time: floppyFileAttributes.createDate];
timeTemp ← " ";
Time.Append[timeTemp,unpackedTime];
OthelloDefs.WriteLine[timeTemp];
ENDLOOP;
Floppy.Close[floppyHandle];
END;
ShowFloppyError: PROC [error:Floppy.ErrorType] = {
errString: ARRAY Floppy.ErrorType OF STRING = [
notReady: "Floppy drive not ready."L,
noSuchDrive: "noSuchDrive"L,
invalidFormat: "Floppy not in pilot format"L,
needsScavenging: "Floppy needs scavenging"L,
invalidVolumeHandle: "invalidVolumeHandle"L,
volumeNotOpen: "volumeNotOpen"L,
fileNotFound: "File Not Found"L,
endOfFile: "End of File"L,
writeInhibited: "Floppy is write-protected"L,
hardwareError: "Floppy hardware error"L,
incompatibleSizes: "incompatibleSizes"L,
insufficientSpace: "Floppy volume is full."L,
zeroSizeFile: "Floppy file is zero-size!"L,
fileListFull: "Floppy file list is full."L,
invalidPageNumber: "invalidPageNumber"L,
badDisk: "badDisk"L,
badSectors: "badSectors"L,
onlyOneSide: "onlyOneSide"L,
onlySingleDensity: "onlySingleDensity"L,
initialMicrocodeSpaceNotAvailable: "initialMicrocodeSpaceNotAvailable"L,
stringTooShort: "stringTooShort"L,
fileListLengthTooShort: "fileListLengthTooShort"L,
floppyImageInvalid: "floppyImageInvalid"L,
floppySpaceTooSmall: "floppySpaceTooSmall"L];
OthelloDefs.WriteString["Unexpected floppy problem: "L];
OthelloDefs.WriteString[errString[error]];
OthelloDefs.AbortingCommand["Floppy command aborted."L];
};
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- The following procs were stolen (more or less) from AccessFloppyImpl
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ReadLeaderPage: PROC [
file: Floppy.FileHandle, attributes: Attributes] =
BEGIN
-- make the buffer for the AttributesRecord in full pages.
buffer: ARRAY [1..maxDataSize + SIZE[AttributesRecord]] OF WORD ← ALL[0];
length: CARDINAL ← 0;
localAttributes: Attributes ← LOOPHOLE[LONG[@buffer]];
Floppy.Read[file, 0, leaderLength, localAttributes];
IF localAttributes.clientDataLength > attributes.maxlength THEN
localAttributes.clientDataLength ← 0;
length ← SIZE[AttributesRecord] + localAttributes.clientDataLength;
[] ← Inline.LongCOPY[to: attributes, nwords: length, from: localAttributes];
END; -- ReadLeaderPage.
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Central commands
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
commandProcessor: OthelloDefs.CommandProcessor ← [LispCommands];
LispCommands: PROC [index: CARDINAL] = {
SELECT index FROM
0 => CopyVM[];
1 => ExpandVM[];
2 => ListFloppyFiles[];
ENDCASE => OthelloDefs.IndexTooLarge};
-- Initialize
OthelloDefs.RegisterCommandProc[@commandProcessor];
END...