--ILTFloppyImpl.mesa
--Created by
-- JFung.PASA 14-Dec-83 12:37:04
-- a modified version taken from FloppyStuff.mesa
--last edited by
-- JFung.PASA 20-Dec-83 15:22:23
DIRECTORY
AccessFloppy USING [
Attributes, AttributesRecord, Close, CreateFile, currentVersion,
DeleteFile, Error, ErrorType, GetAttributes, InconsistentFile,
InvalidVersion, leaderLength, LookUp, maxDataSize, maxNameLength,
NoRoomForClientData, Open, tFloppyLeaderPage],
Environment USING [bytesPerPage],
Exec USING [
Confirm, ExecProc, FreeTokenString, GetToken, Handle, MatchPattern,
Outcome, OutputProc],
File USING [Type],
FileTypes USING [tUntypedFile],
Floppy USING [
AlreadyFormatted, Close, CopyFromPilotFile, CopyToPilotFile, Density,
Error, ErrorType, FileHandle, Format, GetAttributes, GetFileAttributes,
GetNextFile, maxCharactersInLabel, nullFileID, Open, Sides,
VolumeHandle],
Format USING [Char, Date, Line, LongDecimal, LongNumber, Number, StringProc],
FormSW USING [
AllocateItemDescriptor, ClientItemsProcType, CommandItem, Destroy,
Display, DisplayItem, Enumerated, EnumeratedItem, FindItem,
FreeHintsProcType, ItemHandle, newLine, MenuProcType, ProcType,
SetTagPlaces, StringItem],
Heap USING [systemZone],
LispToolOps,
MFile USING [
Error, ErrorCode, GetProperties, Handle, ReadOnly, Release,
SetProperties, Type, WriteOnly],
NSString USING [StringFromMesaString],
Process USING [Pause, SecondsToTicks],
Put,
SpecialMFile USING [GetCapaWithAccess, LeaderPages],
String USING [
AppendLongDecimal, AppendString, Copy, Equivalent, InvalidNumber,
Replace, StringToNumber],
StringLookUp USING [InTable, noMatch],
Time USING [Current],
Tool USING [
Create, Destroy, MakeFileSW, MakeFormSW, MakeMsgSW, MakeSWsProc,
UnusedLogName],
ToolDriver USING [Address, NoteSWs, RemoveSWs],
ToolWindow USING [Activate, Deactivate, DisplayProcType, TransitionProcType],
Token USING [Decimal, FreeStringHandle, Handle, StringToHandle, SyntaxError],
Volume,
Window USING [
BitmapPlace, Box, GetChild, GetDisplayProc, GetParent, Handle,
SetDisplayProc, Stack, ValidateTree];
ILTFloppyImpl: PROGRAM
IMPORTS
AccessFloppy, Exec, Floppy, Format, FormSW, Heap, LispToolOps, MFile,
NSString, Process, Put, SpecialMFile, String, StringLookUp, Time, Tool,
ToolDriver, ToolWindow, Token, Volume, Window
EXPORTS LispToolOps =
BEGIN OPEN ILT: LispToolOps;
-- TYPEs
Indicator: TYPE = {off, left, right};
VolHints: TYPE = RECORD [names: SEQUENCE length: CARDINAL OF LONG STRING];
SizeHints: TYPE = RECORD [names: SEQUENCE length: CARDINAL OF CARDINAL];
DataHandle: TYPE = LONG POINTER TO Data;
Data: TYPE = MACHINE DEPENDENT RECORD [
-- Message subwindow stuff
msgSW(0): Window.Handle ← NIL,
-- File subwindow stuff
fileSW(2): Window.Handle ← NIL,
-- Form subwindow stuff
-- Note: enumerateds and booleans must be word boundary
-- aligned as addresses for them must be generated
--formSW: Window.Handle ← NIL,
paramSW(4): Window.Handle ← NIL,
commandSW(6): Window.Handle ← NIL,
busy(8): BOOLEAN ← FALSE, -- command is running
volName(9): LONG STRING ← NIL,
pattern(11): LONG STRING ← NIL,
indicator(13): Indicator ← left];
EnumProc: TYPE = PROCEDURE [
attributes: AccessFloppy.Attributes, fH: Floppy.FileHandle,
name: LONG STRING] RETURNS [stop: BOOLEAN ← FALSE];
active: BOOLEAN ← FALSE;
floppyWH: Window.Handle ← NIL;
debug: BOOLEAN ← TRUE;
toolData: DataHandle ← NIL;
formDisplay: ToolWindow.DisplayProcType ← NIL;
heraldName: STRING ← [50];
indicatorBox: Window.Box = [[10, 10], [16, 16]];
volume: Volume.ID ← Volume.nullID;
dataVersion: CARDINAL = 02222; -- version of clientData
Abort: ERROR [s: STRING] = CODE;
SetOutcome: SIGNAL [value: Exec.Outcome] = CODE;
DeleteFiles: PROCEDURE[] =
BEGIN
name: LONG STRING ← NIL;
v: Floppy.VolumeHandle;
DeleteOne: EnumProc =
BEGIN
Put.Text[toolData.fileSW, name];
Put.Text[toolData.fileSW, "... "L];
AccessFloppy.DeleteFile[NSString.StringFromMesaString[name] !
AccessFloppy.Error =>
SELECT type FROM
fileNotFound => {
Put.Line[toolData.fileSW, "not found"L];
-- Process.Pause[Process.SecondsToTicks[10]];
GOTO error};
ENDCASE];
Put.Line[toolData.fileSW, "deleted"L];
--Process.Pause[Process.SecondsToTicks[10]];
EXITS error => Put.Line[toolData.fileSW, "error"L];
END; --DeleteOne
v ← AccessFloppy.Open[
! AccessFloppy.Error => ERROR Abort["Can't open floppy"L]];
BEGIN
ENABLE UNWIND => {AccessFloppy.Close[ ! Floppy.Error => CONTINUE]};
--name ← toolData.pattern;
--IF toolData.pattern = NIL THEN EXIT;
IF WildCards[toolData.pattern] THEN EnumerateFloppyFiles[v, DeleteOne, toolData.pattern]
ELSE [] ← DeleteOne[NIL, [v, Floppy.nullFileID], toolData.pattern];
END;
AccessFloppy.Close[];
END; --DeleteFiles
EnumerateFloppyFiles: PROCEDURE [
v: Floppy.VolumeHandle, proc: EnumProc, pattern: LONG STRING ← NIL] =
BEGIN
nullFile: Floppy.FileHandle = [volume: v, file: Floppy.nullFileID];
attributes: AccessFloppy.Attributes ← Heap.systemZone.NEW[
AccessFloppy .AttributesRecord[AccessFloppy.maxDataSize]];
name: LONG STRING = LOOPHOLE[@attributes.length];
IF debug THEN {
Put.Line[toolData.fileSW, "EnumerateFloppyFiles...."L];
--Process.Pause[Process.SecondsToTicks[5]];
};
FOR current: Floppy.FileHandle ← Floppy.GetNextFile[nullFile].nextFile,
Floppy.GetNextFile[current].nextFile WHILE current # nullFile DO
ENABLE UNWIND => Heap.systemZone.FREE[@attributes];
IF Floppy.GetFileAttributes[current].type #
AccessFloppy.tFloppyLeaderPage THEN LOOP;
IF debug THEN {
Put.Line[toolData.fileSW, "Floppy.GetNextFile"L];
--Process.Pause[Process.SecondsToTicks[5]];
};
AccessFloppy.GetAttributes[current, attributes];
Put.Text[toolData.fileSW, "Pattern = "L];
Put.Line[toolData.fileSW, pattern];
IF
--(
pattern = NIL
--OR Exec.MatchPattern[string: name, pattern: pattern])
OR proc[attributes, current, name] THEN {
Put.Line[toolData.fileSW, "Exited loop."L];
EXIT;
};
ENDLOOP;
Heap.systemZone.FREE[@attributes];
END; --EnumerateFloppyFiles
FloppyStuff: PUBLIC PROCEDURE =
BEGIN
aborted: BOOLEAN ← FALSE;
IF toolData = NIL THEN toolData ← Heap.systemZone.NEW[Data ← []];
IF debug THEN {
--Put.Line[ILT.toolData.fileSW, "FloppyStuff...."L];
--Process.Pause[Process.SecondsToTicks[5]];
};
floppyWH ← MakeTool[];
BEGIN
ENABLE {
Abort => {Put.Line[toolData.fileSW, s]; aborted ← TRUE; };
AccessFloppy.Error => {
Put.Text[toolData.fileSW, "unexpected "L];
WriteAccessFloppyError[type];
Put.CR[toolData.fileSW];
aborted ← TRUE;
};
AccessFloppy.InconsistentFile => {
Put.Line[toolData.fileSW, "AccessFloppy.InconsistentFile"L];
aborted ← TRUE;
};
AccessFloppy.InvalidVersion => {
Put.Line[toolData.fileSW, "AccessFloppy.InvalidVersion"L];
aborted ← TRUE;
};
AccessFloppy.NoRoomForClientData => {
Put.Line[toolData.fileSW, "AccessFloppy.NoRoomForClientData"L];
aborted ← TRUE;
};
Floppy.Error => {
IF error = writeInhibited THEN
Put.Line[toolData.fileSW, "Floppy is write protected"L]
ELSE {
Put.Text[toolData.fileSW, "unexpected "L];
--WriteFloppyError[error];
Put.CR[toolData.fileSW];
};
aborted ← TRUE;
};
};
END;
END; --FloppyStuff
<<
FormatDisk: PROCEDURE [gSwitches: LONG STRING, h: Exec.Handle] =
BEGIN
Write: Format.StringProc = Exec.OutputProc[h];
density: Floppy.Density ← default;
sides: Floppy.Sides ← default;
label: STRING ← [Floppy.maxCharactersInLabel];
arg, switches: LONG STRING ← NIL;
nFiles: CARDINAL ← 64;
BEGIN
gotError: BOOLEAN ← FALSE;
v: Floppy.VolumeHandle;
v ← Floppy.Open[
!
Floppy.Error =>
SELECT error FROM
invalidFormat => GOTO virgin;
needsScavenging => {gotError ← TRUE; CONTINUE};
ENDCASE];
IF ~gotError THEN {
[] ← Floppy.GetAttributes[v, label];
Floppy.Close[v];
Write["Floppy volume """L];
Write[label];
Write[""" already formatted"L]}
ELSE Write["Floppy probably contains valid information"L];
Write["; formatting will destroy previous contents"L];
IF ~Exec.Confirm[h] THEN ERROR Abort[NIL];
Format.Line[Write, " yes"L];
EXITS virgin => NULL;
END;
label.length ← 0;
String.AppendString[label, "UnnamedFloppy"L];
DO
arg ← Exec.FreeTokenString[arg];
switches ← Exec.FreeTokenString[switches];
[arg, switches] ← Exec.GetToken[h];
IF arg = NIL AND switches = NIL THEN EXIT;
IF switches = NIL THEN LOOP;
FOR i: CARDINAL IN [0..switches.length) DO
SELECT switches[i] FROM
'n => {
label.length ← 0;
FOR j: CARDINAL IN
[0..label.length ← MIN[
arg.length, label.maxlength]) DO
label[j] ← arg[j]; ENDLOOP};
'f =>
nFiles ← String.StringToNumber[
arg ! String.InvalidNumber => CONTINUE];
ENDCASE;
ENDLOOP;
ENDLOOP;
Write["Formatting... "L];
Floppy.Format[
0, nFiles, label, density, sides !
Floppy.Error =>
IF error = badDisk THEN
ERROR Abort[
"Can't format this disk; may be write protected"L];
Floppy.AlreadyFormatted => RESUME ];
Format.Line[Write, "...done"L];
InfoDisk[];
END;
>>
FormSWDeleteProc: FormSW.ProcType =
BEGIN
IF debug THEN {
Put.Line[toolData.fileSW, "FormSWDeleteProc...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
DeleteFiles;
END; --FormSWDeleteProc
FormSWDuplicateProc: FormSW.ProcType =
BEGIN
IF debug THEN {
Put.Line[toolData.fileSW, "FormSWDuplicateProc...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
--InfoDisk;
END; --FormSWDuplicateProc
FormSWFormatProc: FormSW.ProcType =
BEGIN
IF debug THEN {
Put.Line[toolData.fileSW, "FormSWFormatProc...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
END; --FormSWFormatProc
FormSWInfoProc: FormSW.ProcType =
BEGIN
IF debug THEN {
Put.Line[toolData.fileSW, "FormSWInfoProc...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
InfoDisk;
END; --FormSWInfoProc
FormSWListProc: FormSW.ProcType =
BEGIN
IF debug THEN {
Put.Line[toolData.fileSW, "FormSWListProc...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
ListFiles;
END; --FormSWListProc
FormSWReadProc: FormSW.ProcType =
BEGIN
IF toolData # NIL THEN
BEGIN Tool.Destroy[floppyWH]; Heap.systemZone.FREE[@toolData]; END;
END; --FormSWReadProc
FormSWWriteProc: FormSW.ProcType =
BEGIN
IF toolData # NIL THEN
BEGIN Tool.Destroy[floppyWH]; Heap.systemZone.FREE[@toolData]; END;
END; --FormSWWriteProc
FormSWQuitProc: FormSW.ProcType =
BEGIN
IF toolData # NIL THEN
BEGIN Tool.Destroy[floppyWH]; Heap.systemZone.FREE[@toolData]; END;
END; --FormSWQuitProc
FormSWVolHintsProc: FormSW.MenuProcType =
BEGIN
RETURN[
hints: DESCRIPTOR[
@ILT.toolData.volHints[0], ILT.toolData.volHints.length],
freeHintsProc: HintsNoLongerBusy, replace: TRUE];
END;
HintsNoLongerBusy: FormSW.FreeHintsProcType = BEGIN END;
InfoDisk: PROCEDURE[] =
BEGIN
density: Floppy.Density;
sides: Floppy.Sides;
label: STRING ← [Floppy.maxCharactersInLabel];
freeSpace, largestBlock: LONG CARDINAL;
v: Floppy.VolumeHandle;
IF debug THEN {
Put.Line[toolData.fileSW, "AccessFloppy.Open...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
v ← AccessFloppy.Open[
! AccessFloppy.Error => ERROR Abort["Can't open floppy"L]];
IF debug THEN {
Put.Line[toolData.fileSW, "GetAttributes...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
[freeSpace, largestBlock, , , density, sides] ← Floppy.GetAttributes[
v, label];
Put.Text[toolData.fileSW, "Floppy """L];
Put.Text[toolData.fileSW, label];
Put.Text[toolData.fileSW, """; "L];
Put.Text[toolData.fileSW, IF sides = one THEN "single"L ELSE "double"L];
Put.Text[toolData.fileSW, " sided; "L];
Put.Text[toolData.fileSW, IF density = single THEN "single"L ELSE "double"L];
Put.Line[toolData.fileSW, " density"L];
Put.LongDecimal[toolData.fileSW, freeSpace];
Put.Text[toolData.fileSW, " free pages; largest free block = "L];
Put.LongDecimal[toolData.fileSW, largestBlock];
Put.Line[toolData.fileSW, " pages"L];
AccessFloppy.Close[];
END; --InfoDisk
ListFiles: PROCEDURE[] =
BEGIN
pattern: LONG STRING ← NIL;
v: Floppy.VolumeHandle;
ListOne: EnumProc =
BEGIN
Put.CR[toolData.fileSW];
Put.Text[toolData.fileSW, name];
FOR i: CARDINAL IN [name.length + WritePartial[attributes]..24) DO
Put.Text[toolData.fileSW, " "]; ENDLOOP;
Put.Number[toolData.fileSW, attributes.type, [10, FALSE, TRUE, 5]];
Put.Text[toolData.fileSW, " "L];
Put.LongNumber[
toolData.fileSW, attributes.totalSizeInBytes, [
10, FALSE, TRUE, 9]];
Put.Text[toolData.fileSW, " "L];
Put.Date[toolData.fileSW, attributes.createDate, noSeconds];
Put.Text[toolData.fileSW, " "L];
Put.Date[toolData.fileSW, attributes.lastWrittenDate, noSeconds];
END; --ListOne
IF debug THEN {
Put.Line[toolData.fileSW, "ListFiles: AccessFloppy.Open...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
v ← AccessFloppy.Open[
! AccessFloppy.Error => ERROR Abort["Can't open floppy"L]];
Put.Text[toolData.fileSW, " NAME "L]; --23
Put.Text[toolData.fileSW, " TYPE "L]; -- 5+2
Put.Text[toolData.fileSW, " LENGTH "L]; -- 9+2
Put.Text[toolData.fileSW, " CREATE "L]; -- 20+2
Put.Line[toolData.fileSW, " WRITE"L];
EnumerateFloppyFiles[
v, ListOne, pattern !
UNWIND => {AccessFloppy.Close[ ! Floppy.Error => CONTINUE]}];
AccessFloppy.Close[];
END; --ListFiles
MakeAttributes: PROCEDURE [
file: MFile.Handle, name: LONG STRING,
attributes: AccessFloppy.Attributes, type: File.Type] =
BEGIN
attributes.version ← AccessFloppy.currentVersion;
attributes.type ← type;
attributes.lastWrittenDate ← Time.Current[];
attributes.name ← ALL[0];
attributes.clientDataLength ← 2;
attributes.clientData[0] ← dataVersion;
[length: attributes.totalSizeInBytes, create: attributes.createDate,
type: attributes.clientData[1]] ← MFile.GetProperties[file];
attributes.totalSize ← PagesFromBytes[attributes.totalSizeInBytes];
attributes.size ← attributes.totalSize;
attributes.length ← MIN[name.length, AccessFloppy.maxNameLength];
FOR i: CARDINAL IN [0..attributes.length) DO
attributes.name[i] ← LOOPHOLE[name[i]]; ENDLOOP
END; --MakeAttributes
MakeCommands: FormSW.ClientItemsProcType =
BEGIN OPEN FormSW;
tabs: ARRAY [0..5) OF CARDINAL ← [0, 20, 40, 60, 70];
nItems: CARDINAL = 8;
items ← AllocateItemDescriptor[nItems];
items[0] ← CommandItem[
tag: "Info"L, place: newLine, proc: FormSWInfoProc];
items[1] ← CommandItem[tag: "List"L, proc: FormSWListProc];
items[2] ← CommandItem[tag: "Read"L, proc: FormSWReadProc];
items[3] ← CommandItem[tag: "Write"L, proc: FormSWWriteProc];
items[4] ← CommandItem[
tag: "Format"L, place: newLine, proc: FormSWFormatProc];
items[5] ← CommandItem[tag: "Delete"L, proc: FormSWDeleteProc];
items[6] ← CommandItem[tag: "Duplicate"L, proc: FormSWDuplicateProc];
items[7] ← CommandItem[tag: "Quit"L, proc: FormSWQuitProc];
SetTagPlaces[items, DESCRIPTOR[tabs], FALSE];
RETURN[items, TRUE];
END; --MakeCommands
MakeParams: FormSW.ClientItemsProcType =
BEGIN OPEN FormSW;
i, nVols: CARDINAL;
tabs: ARRAY [0..4) OF CARDINAL ← [0, 30, 60, 75];
nItems: CARDINAL = 2;
items ← AllocateItemDescriptor[nItems];
nVols ← ILT.ListLogicalVolumes[];
String.Copy[toolData.volName, ILT.toolData.volHints[0]];
FOR i IN [0..nVols) DO
IF String.Equivalent[ILT.toolData.volHints[i], "Lisp"L] THEN
BEGIN
String.Replace[
@toolData.volName, ILT.toolData.volHints[i],
Heap.systemZone];
EXIT;
END;
ENDLOOP;
items[0] ← StringItem[
tag: "Source Volume"L, place: newLine, string: @toolData.volName,
inHeap: TRUE, menuProc: FormSWVolHintsProc];
items[1] ← StringItem[
tag: "Pattern"L, string: @toolData.pattern, inHeap: TRUE];
SetTagPlaces[items, DESCRIPTOR[tabs], FALSE];
RETURN[items, TRUE]
END; --MakeParams
MakeSWs: Tool.MakeSWsProc =
BEGIN
addresses: ARRAY [0..4) OF ToolDriver.Address;
logName: STRING ← [20];
IF debug THEN {
Put.Line[ILT.toolData.fileSW, "MakeSWs...."L];
Process.Pause[Process.SecondsToTicks[5]];
};
Tool.UnusedLogName[unused: logName, root: "FloppyOptions.log"L];
toolData.msgSW ← Tool.MakeMsgSW[window: window, lines: 1];
toolData.paramSW ← Tool.MakeFormSW[window: window, formProc: MakeParams];
toolData.commandSW ← Tool.MakeFormSW[
window: window, formProc: MakeCommands];
--note: logName is compulsory, else it bombs
toolData.fileSW ← Tool.MakeFileSW[window: window, name: logName];
--Supervisor.AddDependency[client: agent, implementor: Event.toolWindow];
-- do the ToolDriver stuff
addresses ← [
[name: "msgSW"L, sw: toolData.msgSW],
--[name: "formSW"L, sw: toolData.formSW],
[name: "ParamSW"L, sw: toolData.paramSW], [
name: "CmdSW"L, sw: toolData.commandSW], [
name: "fileSW"L, sw: toolData.fileSW]];
ToolDriver.NoteSWs[
tool: "FloppyOptions"L, subwindows: DESCRIPTOR[addresses]];
END; --MakeSWs
MakeTool: PROCEDURE RETURNS [wh: Window.Handle] =
BEGIN
RETURN[
Tool.Create[
makeSWsProc: MakeSWs, initialState: default,
--clientTransition: ClientTransition,
name: "Floppy Options"L]];
--initialBox: [
--place: sw.BitmapPlace[[10, hisBox.dims.h]],
--dims: [hisBox.dims.w - 20, 180]]];
END; --MakeTool
NameFromAttributes: PROCEDURE [attributes: AccessFloppy.Attributes]
RETURNS [LONG STRING] = INLINE {RETURN[LOOPHOLE[@attributes.length]]};
ParsePartial: PROCEDURE [name: LONG STRING]
RETURNS [offset: CARDINAL ← 0, length: CARDINAL ← LAST[CARDINAL]] =
BEGIN
h: Token.Handle;
i: CARDINAL;
IF name = NIL THEN RETURN;
FOR i IN [1..name.length) DO
IF name[i] = '[ THEN EXIT; REPEAT FINISHED => RETURN ENDLOOP;
h ← Token.StringToHandle[name, i + 1];
BEGIN
ENABLE UNWIND => [] ← Token.FreeStringHandle[h];
offset ← Token.Decimal[h];
SELECT h.break FROM
'. =>
IF h.getChar[h] = '. THEN
length ← Token.Decimal[h] - offset + 1
ELSE ERROR Token.SyntaxError[NIL];
'! => length ← Token.Decimal[h];
'] => NULL;
ENDCASE => ERROR Token.SyntaxError[NIL];
END;
name.length ← i;
[] ← Token.FreeStringHandle[h];
END; --ParsePartial
PagesFromBytes: PROCEDURE [bytes: LONG CARDINAL] RETURNS [LONG CARDINAL] =
BEGIN
RETURN[(bytes + Environment.bytesPerPage - 1)/Environment.bytesPerPage];
END; --PagesFromBytes
ReadFiles: PROCEDURE [gSwitches: LONG STRING, h: Exec.Handle] =
BEGIN
attributes: AccessFloppy.Attributes ← NIL;
name, altName, switches: LONG STRING ← NIL;
Write: Format.StringProc = Exec.OutputProc[h];
v: Floppy.VolumeHandle;
ReadOne: EnumProc =
BEGIN
mFile: MFile.Handle;
type: MFile.Type ← unknown;
destName: LONG STRING = IF altName = NIL THEN name ELSE altName;
Write[name];
Write["... "L];
IF attributes.clientDataLength = 2
AND attributes.clientData[0] = dataVersion THEN
type ← attributes.clientData[1];
Write["copying to "L];
Write[destName];
[] ← WritePartial[attributes];
Write["... "L];
mFile ← MFile.WriteOnly[
destName, [], type, attributes.totalSizeInBytes !
MFile.Error => {
Format.Line[Write, "can't write on destination file"L];
SetOutcome[error];
GOTO return}];
MFile.SetProperties[
file: mFile, type: type, length: attributes.totalSizeInBytes,
create: attributes.createDate];
IF attributes.size # 0 THEN
Floppy.CopyToPilotFile[
floppyFile: fH,
pilotFile: SpecialMFile.GetCapaWithAccess[mFile],
firstFloppyPage: AccessFloppy.leaderLength,
firstPilotPage:
SpecialMFile.LeaderPages[] + attributes.offset,
count: attributes.size];
Format.Line[Write, "copied"L];
MFile.Release[mFile];
EXITS return => NULL;
END;
v ← AccessFloppy.Open[
! AccessFloppy.Error => ERROR Abort["Can't open floppy"L]];
DO
ENABLE
UNWIND => {
altName ← Exec.FreeTokenString[altName];
name ← Exec.FreeTokenString[name];
switches ← Exec.FreeTokenString[switches];
Heap.systemZone.FREE[@attributes];
AccessFloppy.Close[ ! Floppy.Error => CONTINUE]};
fFile: Floppy.FileHandle;
failed: BOOLEAN ← FALSE;
IF attributes = NIL THEN
attributes ← Heap.systemZone.NEW[
AccessFloppy .AttributesRecord[AccessFloppy.maxDataSize]];
altName ← Exec.FreeTokenString[altName];
name ← Exec.FreeTokenString[name];
switches ← Exec.FreeTokenString[switches];
[name, switches] ← Exec.GetToken[h];
IF name = NIL AND switches = NIL THEN EXIT;
IF WildCards[name] THEN {
EnumerateFloppyFiles[v, ReadOne, name]; LOOP};
IF switches # NIL AND switches.length # 0 AND switches[0] = 's THEN
{
switches ← Exec.FreeTokenString[switches];
[altName, switches] ← Exec.GetToken[h]};
fFile ← AccessFloppy.LookUp[
NSString.StringFromMesaString[name], attributes !
AccessFloppy.Error =>
IF type = fileNotFound THEN {failed ← TRUE; CONTINUE}
ELSE ERROR Abort["Floppy Error"L]];
IF failed THEN {
Write[name];
Format.Line[Write, " not found"L];
SetOutcome[error];
LOOP}
ELSE
[] ← ReadOne[
attributes, fFile, NameFromAttributes[attributes]];
ENDLOOP;
Heap.systemZone.FREE[@attributes];
AccessFloppy.Close[];
END; -- ReadFile
WriteAccessFloppyError: PROCEDURE [type: AccessFloppy.ErrorType] =
BEGIN
Put.Text[toolData.fileSW, "AccessFloppy.Error["L];
Put.Text[
toolData.fileSW,
SELECT type FROM
attributesNotAllowed => "attributesNotAllowed"L,
fileNotFound => "fileNotFound"L,
invalidParameter => "invalidParameter"L,
nameInUse => "nameInUse"L,
volumeNotOpen => "volumeNotOpen"L,
ENDCASE => "?"L];
Put.Text[toolData.fileSW, "]"L];
END; --WriteAccessFloppyError
WriteFloppyError: PROCEDURE [
Write: Format.StringProc, error: Floppy.ErrorType] =
BEGIN
Write["Floppy.Error["L];
Write[
SELECT error FROM
badDisk => "badDisk"L,
badSectors => "badSectors"L,
endOfFile => "endOfFile"L,
fileListFull => "fileListFull"L,
fileNotFound => "fileNotFound"L,
hardwareError => "hardwareError"L,
incompatibleSizes => "incompatibleSizes"L,
invalidFormat => "invalidFormat"L,
invalidPageNumber => "invalidPageNumber"L,
invalidVolumeHandle => "invalidVolumeHandle"L,
insufficientSpace => "insufficientSpace"L,
needsScavenging => "needsScavenging"L,
noSuchDrive => "noSuchDrive"L,
notReady => "notReady"L,
onlyOneSide => "onlyOneSide"L,
onlySingleDensity => "onlySingleDensity"L,
initialMicrocodeSpaceNotAvailable =>
"initialMicrocodeSpaceNotAvailable"L,
stringTooShort => "stringTooShort"L,
volumeNotOpen => "volumeNotOpen"L,
writeInhibited => "writeInhibited"L,
zeroSizeFile => "zeroSizeFile"L,
ENDCASE => "?"L];
Format.Char[Write, ']];
END; --WriteFloppyError
WritePartial: PROCEDURE [attributes: AccessFloppy.Attributes]
RETURNS [chars: CARDINAL ← 0] =
BEGIN
CountedNumber: PROCEDURE [n: LONG CARDINAL] RETURNS [CARDINAL] = {
s: STRING = [12];
String.AppendLongDecimal[s, n];
Put.Text[toolData.fileSW, s];
RETURN[s.length]};
IF attributes.offset # 0 OR attributes.size # attributes.totalSize THEN {
chars ← 4;
Put.Char[toolData.fileSW, '[];
chars ← chars + CountedNumber[attributes.offset];
-- Write[".."L];
chars ←
chars + CountedNumber[attributes.offset + attributes.size - 1];
Put.Char[toolData.fileSW, ']]};
END; --WritePartial
WriteFiles: PROCEDURE [gSwitches: LONG STRING, h: Exec.Handle] =
BEGIN
attributes: AccessFloppy.Attributes ← NIL;
name, altName, switches: LONG STRING ← NIL;
fileType: File.Type ← FileTypes.tUntypedFile;
mFile: MFile.Handle;
Write: Format.StringProc = Exec.OutputProc[h];
IF gSwitches # NIL THEN
fileType ← [
String.StringToNumber[
gSwitches ! String.InvalidNumber => CONTINUE]];
[] ← AccessFloppy.Open[
! AccessFloppy.Error => ERROR Abort["Can't open floppy"L]];
DO
ENABLE
UNWIND => {
IF altName # name THEN
altName ← Exec.FreeTokenString[altName];
name ← Exec.FreeTokenString[name];
switches ← Exec.FreeTokenString[switches];
IF mFile # NIL THEN MFile.Release[mFile];
Heap.systemZone.FREE[@attributes];
AccessFloppy.Close[ ! Floppy.Error => CONTINUE]};
fFile: Floppy.FileHandle;
failed: BOOLEAN ← FALSE;
mFileError: MFile.ErrorCode;
offset, length: CARDINAL;
IF attributes = NIL THEN
attributes ← Heap.systemZone.NEW[
AccessFloppy .AttributesRecord[AccessFloppy.maxDataSize]];
mFile ← NIL;
IF altName # name THEN altName ← Exec.FreeTokenString[altName];
name ← Exec.FreeTokenString[name];
switches ← Exec.FreeTokenString[switches];
[name, switches] ← Exec.GetToken[h];
IF name = NIL AND switches = NIL THEN EXIT;
[offset, length] ← ParsePartial[
name !
Token.SyntaxError => {
Write[name];
Format.Line[Write, " - bad name syntax"L];
SetOutcome[error];
LOOP}];
IF switches # NIL AND switches.length # 0 THEN
SELECT switches[0] FROM
's => {
switches ← Exec.FreeTokenString[switches];
[altName, switches] ← Exec.GetToken[h]};
't => {
fileType ← [
String.StringToNumber[
name ! String.InvalidNumber => CONTINUE]];
switches ← Exec.FreeTokenString[switches];
LOOP};
ENDCASE
ELSE altName ← name;
mFile ← MFile.ReadOnly[
name, [] ! MFile.Error => {mFileError ← code; CONTINUE}];
IF mFile = NIL THEN
SELECT mFileError FROM
noSuchFile => {
Format.Line[Write, " not found"L];
SetOutcome[error];
LOOP};
conflictingAccess => {
Format.Line[Write, " conflicting access"L];
SetOutcome[error];
LOOP};
ENDCASE => ERROR Abort[" unexpected MFile.Error"L];
MakeAttributes[mFile, altName, attributes, fileType];
attributes.offset ← offset;
attributes.size ← MIN[length, attributes.totalSize - offset];
Write[name];
[] ← WritePartial[attributes];
Write["... "L];
Write["copying to "L];
Write[altName];
Write["... "L];
fFile ← AccessFloppy.CreateFile[
attributes !
AccessFloppy.Error =>
IF type = nameInUse THEN {failed ← TRUE; CONTINUE};
Floppy.Error =>
SELECT error FROM
fileListFull => ERROR Abort["too many files"L];
insufficientSpace => ERROR Abort["floppy is full"L];
ENDCASE];
IF failed THEN {
Format.Line[Write, "floppy file already exists - skipped"L];
SetOutcome[error]}
ELSE {
IF attributes.size # 0 THEN
Floppy.CopyFromPilotFile[
floppyFile: fFile,
pilotFile: SpecialMFile.GetCapaWithAccess[mFile],
firstFloppyPage: AccessFloppy.leaderLength,
firstPilotPage: SpecialMFile.LeaderPages[] + offset,
count: attributes.size];
Format.Line[Write, "copied"L]};
MFile.Release[mFile];
ENDLOOP;
Heap.systemZone.FREE[@attributes];
AccessFloppy.Close[];
END; -- WriteFiles
WildCards: PROCEDURE [pattern: LONG STRING] RETURNS [BOOLEAN] =
BEGIN
IF pattern # NIL THEN
FOR i: CARDINAL IN [0..pattern.length) DO
SELECT pattern[i] FROM '*, '# => RETURN[TRUE]; ENDCASE;
ENDLOOP;
IF debug THEN {
Put.Line[toolData.fileSW, " NOT WildCards"L];
};
RETURN[FALSE];
END;
<<
DoIt: Exec.ExecProc =
BEGIN
MyCommands: TYPE = MACHINE DEPENDENT{
read(0), write, list, delete, information, format,
noMatch(StringLookUp.noMatch)};
DefinedOptions: TYPE = MyCommands [read..format];
commandTable: ARRAY DefinedOptions OF LONG STRING ← [
read: "Read"L, write: "Write"L, list: "List"L, delete: "Delete"L,
information: "Information"L, format: "Format"L];
index: MyCommands;
Write: Format.StringProc = Exec.OutputProc[h];
command, switches: LONG STRING ← NIL;
WHILE outcome = normal DO
ENABLE
UNWIND => {
command ← Exec.FreeTokenString[command];
switches ← Exec.FreeTokenString[switches]};
[command, switches] ← Exec.GetToken[h];
IF command = NIL AND switches = NIL THEN EXIT;
BEGIN
ENABLE {
Abort => {Format.Line[Write, s]; GOTO abort};
AccessFloppy.Error => {
Write["unexpected "L];
WriteAccessFloppyError[Write, type];
Format.Char[Write, Ascii.CR];
GOTO abort};
AccessFloppy.InconsistentFile => {
Format.Line[Write, "AccessFloppy.InconsistentFile"L];
GOTO abort};
AccessFloppy.InvalidVersion => {
Format.Line[Write, "AccessFloppy.InvalidVersion"L];
GOTO abort};
AccessFloppy.NoRoomForClientData => {
Format.Line[Write, "AccessFloppy.NoRoomForClientData"L];
GOTO abort};
Floppy.Error => {
IF error = writeInhibited THEN
Format.Line[Write, "Floppy is write protected"L]
ELSE {
Write["unexpected "L];
WriteFloppyError[Write, error];
Format.Char[Write, Ascii.CR]};
GOTO abort};
SetOutcome => {
IF outcome < value THEN outcome ← value; RESUME }};
index ← LOOPHOLE[StringLookUp.InTable[
key: command,
table: DESCRIPTOR[BASE[commandTable], LENGTH[commandTable]]]];
SELECT index FROM
read => ReadFiles[switches, h];
write => WriteFiles[switches, h];
list => ListFiles[switches, h];
delete => DeleteFiles[switches, h];
information => InfoDisk[switches, h];
format => FormatDisk[switches, h];
ENDCASE => {Write["Unknown command"L]; GOTO abort};
EXITS abort => outcome ← abort;
END;
command ← Exec.FreeTokenString[command];
switches ← Exec.FreeTokenString[switches];
ENDLOOP;
END;
>>
Help: Exec.ExecProc =
BEGIN
Write: Format.StringProc = Exec.OutputProc[h];
Write[
"
Floppy.~ <command> <args>
<args>:
<fileList>: list of file names; /s on a name uses next name as destination
<wildList>: names may contain * and #
<command>:
Read <fileList> | <wildList> - copies files from floppy
Write <fileList> - copies files to floppy
number/t sets File.Type for following files (default tUntypedFile)
add [firstPage..lastPage] to name for writing partial files
List/ltdwv <wildList> - shows files on floppy; switches show:
l => length, t => type, d => create date, w => write date, v => everything
Delete <wildList> - deletes files from floppy
Info - gives information about the floppy volume
Format - formats floppy destroying previous contents, args are:
name/n gives the volume a name (quote names with special characters)
number/f sets max number of files to number (default 64)"L]
END;
END.