--LTFloppyImpl.mesa --Created by -- JFung.PASA 14-Dec-83 12:37:04 -- a modified version taken from FloppyStuff.mesa --last edited by -- JFung.PASA 12-Mar-84 15:51:16 DIRECTORY AccessFloppy, AccessFloppyUtil, Environment, Exec, File, FileAttributes, FileTypes USING [tUntypedFile], Floppy, Format, FormSW, Heap USING [systemZone], Inline, LispToolOps, MFile, MStream, NSString USING [StringFromMesaString], Process USING [Pause, SecondsToTicks], Put, Runtime, Space, SpecialMFile USING [GetCapaWithAccess, LeaderPages], Storage, Stream, String, StringLookUp, Time, Tool USING [ Create, Destroy, MakeFileSW, MakeFormSW, MakeMsgSW, MakeSWsProc, UnusedLogName], ToolDriver, ToolWindow, Token, Version, Volume, Window; LTFloppyImpl: PROGRAM IMPORTS AccessFloppy, AccessFloppyUtil, Exec, Floppy, Format, FormSW, Heap, Inline, LispToolOps, MFile, MStream, NSString, Process, Put, Space, SpecialMFile, Storage, String, Time, Tool, ToolDriver, Token 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]; LptNextFile: TYPE = LONG POINTER TO NextFile; NextFile: TYPE = RECORD [ file: LONG STRING _ NIL, size: LONG CARDINAL _ 0, -- file size including leader page if it has one. type: File.Type _ AccessFloppy.tFloppyLeaderPage, -- specify whether it has leader page. next: LptNextFile _ NIL]; 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, floppyName(14): LONG STRING _ NIL, stream(16): MStream.Handle _ NIL, from(18): LONG STRING _ NIL, to(20): LONG STRING _ NIL, numberOfFiles(22): INTEGER _ 0, current(23): LptNextFile _ NIL, fileList(25): LptNextFile _ NIL]; EnumProc: TYPE = PROCEDURE [ attributes: AccessFloppy.Attributes, fH: Floppy.FileHandle, name: LONG STRING] RETURNS [stop: BOOLEAN _ FALSE]; -- constant nullNextFile: NextFile = []; -- global variables Abort: ERROR [s: STRING] = CODE; active: BOOLEAN _ FALSE; attributes: AccessFloppy.Attributes _ NIL; bufferSize: Space.PageCount _ 30; dataVersion: CARDINAL = 02222; -- version of clientData debug: BOOLEAN _ TRUE; floppyWH: Window.Handle _ NIL; formDisplay: ToolWindow.DisplayProcType _ NIL; heraldName: STRING _ [50]; indicatorBox: Window.Box = [[10, 10], [16, 16]]; nullFile: Floppy.FileHandle; opened: BOOLEAN _ FALSE; spaceHandle: Space.Handle _ Space.nullHandle; toolData: DataHandle _ NIL; vH: Floppy.VolumeHandle _ Floppy.nullVolumeHandle; volume: Volume.ID _ Volume.nullID; z: UNCOUNTED ZONE = Heap.systemZone; SetOutcome: SIGNAL [value: Exec.Outcome] = CODE; -- Private procedures CleanUp: PROC = BEGIN current: LptNextFile _ toolData.fileList; releaseData: MFile.ReleaseData _ [NIL, NIL]; WHILE current^ # nullNextFile DO file: MFile.Handle _ NIL; scratchName: LONG STRING _ [120]; String.AppendString[scratchName, current.file]; String.AppendString[scratchName, ".Scratch$"L]; toolData.current _ current.next; file _ MFile.Acquire[ scratchName, MFile.Access[delete], releaseData]; MFile.Delete[file]; --current.file _ Storage.FreeStringNil[current.file]; Storage.Free[current]; current _ toolData.current; ENDLOOP; toolData.fileList _ toolData.current _ Storage.FreeNodeNil[ toolData.current]; toolData.from _ Storage.FreeStringNil[toolData.from]; toolData.to _ Storage.FreeStringNil[toolData.to]; END; -- CleanUp. CopyCmd: PROCEDURE = BEGIN floppyOpened: BOOLEAN _ FALSE; skip: BOOLEAN _ FALSE; IF debug THEN { Put.Line[toolData.fileSW, "AccessFloppy.Open...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [vH] _ OpenFloppy[]; IF ~opened THEN RETURN; IF debug THEN { Put.Line[toolData.fileSW, "Floppy.GetAttributes...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [] _ Floppy.GetAttributes[vH, toolData.floppyName]; toolData.numberOfFiles _ 0; --IF toolData.to # NIL THENtoolData.to _ Storage.FreeStringNil[toolData.to]; -- toolData.to _ Storage.String[Floppy.maxCharactersInLabel]; IF debug THEN { Put.Line[toolData.fileSW, "z.NEW[NextFile _ []...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; toolData.fileList _ z.NEW[NextFile _ []]; toolData.current _ toolData.fileList; IF debug THEN { Put.Line[toolData.fileSW, "AccessFloppyUtil.CreateBuffer..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [spaceHandle, bufferSize] _ CreateBuffer[bufferSize]; IF debug THEN { Put.Line[toolData.fileSW, ".FloppyToDisk...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; FloppyToDisk[]; [skip] _ FormatAndOpen[]; IF skip THEN RETURN; -- now ask user remove current one, insert a new one, format and open it. IF debug THEN { Put.Line[toolData.fileSW, ".DiskToFloppy...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; DiskToFloppy[]; IF debug THEN { Put.Line[toolData.fileSW, ".DiskToFloppy...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; CleanUp[]; -- trace fileList to delete disk file, release NextFile nodes, and release data.from and data.to strings. IF debug THEN { Put.Line[toolData.fileSW, ".DiskToFloppy...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; AccessFloppyUtil.DeleteBuffer[spaceHandle]; END; -- CopyCmd. -- from AccessFloppyUtil CreateBuffer: PUBLIC PROC [size: Space.PageCount] RETURNS [spH: Space.Handle, spSize: Space.PageCount] = BEGIN volID: Volume.ID; volOpen: BOOLEAN _ FALSE; spSize _ MIN[size, 200]; IF debug THEN { Put.Line[toolData.fileSW, "toolData.volName...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; PutVolumeName[]; [volID, volOpen] _ ILT.GetVolumeID[toolData.volName]; IF ~volOpen THEN RETURN; IF ~ILT.Confirm[] THEN RETURN; IF debug THEN { Put.Line[toolData.fileSW, ".Space.Create...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; spH _ Space.Create[ spSize, Space.virtualMemory ! Space.InsufficientSpace => IF available # 0 THEN {spSize _ available; RETRY}]; IF debug THEN { Put.Line[toolData.fileSW, ".Space.Map...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; Space.Map[spH]; END; -- CreateBuffer. DeleteBuffer: PUBLIC PROC [spH: Space.Handle] = BEGIN Space.Kill[spH]; Space.Unmap[spH]; Space.Delete[spH]; END; -- DeleteBuffer. 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]; IF debug THEN Process.Pause[Process.SecondsToTicks[10]]; GOTO error}; ENDCASE]; Put.Line[toolData.fileSW, "deleted"L]; IF debug THEN Process.Pause[Process.SecondsToTicks[10]]; EXITS error => Put.Line[toolData.fileSW, "error"L]; END; --DeleteOne [vH] _ OpenFloppy[]; IF ~opened THEN RETURN; 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; IF debug THEN { Put.Text[toolData.fileSW, "AccessFloppy.Close"L]; Process.Pause[Process.SecondsToTicks[5]]; }; AccessFloppy.Close[]; END; --DeleteFiles DiskToFloppy: PROC = BEGIN storeFile: Floppy.FileHandle _ nullFile; FOR current: LptNextFile _ toolData.fileList, current.next WHILE current^ # nullNextFile DO handle: MStream.Handle _ NIL; scratchName: LONG STRING _ [120]; String.AppendString[scratchName, current.file]; String.AppendString[scratchName, ".Scratch$"L]; handle _ MStream.ReadOnly[scratchName, [NIL, NIL]]; storeFile _ Floppy.CreateFile[vH, current.size, current.type]; StoreFilePiece[handle, storeFile, current.size]; handle.delete[handle]; ENDLOOP; -- will have current points to a NextFile[NIL, NIL]. END; -- DiskToFloppy. DisplayFloppyName: PROCEDURE[] = BEGIN IF debug THEN { Put.Line[toolData.fileSW, "DisplayFile...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; FormSW.DisplayItem[toolData.paramSW, 3]; END; --DisplayFloppyName EnumerateFloppyFiles: PROCEDURE [ v: Floppy.VolumeHandle, proc: EnumProc, pattern: LONG STRING] = 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]]; Put.Text[toolData.fileSW, "Pattern = "L]; Put.Line[toolData.fileSW, pattern]; }; AccessFloppy.GetAttributes[current, attributes]; 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 attributes = NIL THEN attributes _ z.NEW[ AccessFloppy .AttributesRecord[AccessFloppy.maxDataSize]]; 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 FloppyToDisk: PROC = BEGIN handle: MStream.Handle _ NIL; releaseData: MStream.ReleaseData _ []; FOR current: Floppy.FileHandle _ Floppy.GetNextFile[nullFile].nextFile, Floppy.GetNextFile[current].nextFile WHILE current # nullFile DO scratchName: LONG STRING _ [120]; IF debug THEN { Put.Line[toolData.fileSW, ".Floppy.GetFileAttributes...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [toolData.current.size, toolData.current.type] _ Floppy.GetFileAttributes[current]; IF debug THEN { Put.Line[ toolData.fileSW, ".AccessFloppy.GetFileAttributes...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; AccessFloppy.GetAttributes[current, attributes]; IF debug THEN { Put.Line[toolData.fileSW, ".String.MakeString...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; toolData.current.file _ String.MakeString[ z, AccessFloppy.maxNameLength]; IF debug THEN { Put.Line[ toolData.fileSW, "AccessFloppyUtil.MesaStringFromAttributes...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; MesaStringFromAttributes[attributes, toolData.current.file]; IF debug THEN { Put.Line[toolData.fileSW, ".String.AppendString...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; String.AppendString[scratchName, toolData.current.file]; String.AppendString[scratchName, ".Scratch$"L]; IF debug THEN { Put.Line[toolData.fileSW, ".String.AppendString...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; handle _ MStream.ReadWrite[ name: scratchName, release: releaseData, type: MFile.Type[unknown]]; attributes.size _ toolData.current.size; -- modify size to actual file size. IF debug THEN { Put.Line[toolData.fileSW, "RetrieveFilePiece..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; RetrieveFilePiece[current, handle, attributes]; toolData.numberOfFiles _ toolData.numberOfFiles + 1; toolData.current _ toolData.current.next _ z.NEW[NextFile _ []]; IF debug THEN { Put.Line[toolData.fileSW, "handle.delete..."L]; Process.Pause[Process.SecondsToTicks[5]]; }; handle.delete[handle]; ENDLOOP; -- will have current points to a NextFile[NIL, NIL]. END; -- FloppyToDisk. FormatAndOpen: PROC[] RETURNS [skip: BOOLEAN] = BEGIN density: Floppy.Density _ double; sides: Floppy.Sides _ two; nFile: CARDINAL _ 2*toolData.numberOfFiles + 1; ok: BOOLEAN; skip _ TRUE; Put.Line[toolData.fileSW, "Please Remove Floppy Disk, are you ready? "L]; IF ~ILT.Confirm[] THEN RETURN; Put.Line[toolData.fileSW, "format..."L]; [ok] _ FormatDisk[nFile, toolData.floppyName, sides, density]; IF ~ok THEN {CleanUp; RETURN}; Put.Line[toolData.fileSW, "...ted"L]; vH _ AccessFloppy.Open[]; nullFile _ [vH, Floppy.nullFileID]; skip _ FALSE; END; -- FormatAndOpen. FormatDisk: PROCEDURE [ nFiles: CARDINAL, label: LONG STRING, sides: Floppy.Sides, density: Floppy.Density] RETURNS [gotError: BOOLEAN] = BEGIN gotError: BOOLEAN _ FALSE; BEGIN v: Floppy.VolumeHandle; v _ AccessFloppy.Open[ ! Floppy.Error => SELECT error FROM invalidFormat => GOTO virgin; needsScavenging => {gotError _ TRUE; CONTINUE}; ENDCASE => gotError _ TRUE;]; IF ~gotError THEN { [] _ Floppy.GetAttributes[v, label]; Floppy.Close[v]; Put.Text[toolData.fileSW, "Floppy volume """L]; Put.Text[toolData.fileSW, label]; Put.Line[toolData.fileSW, """ already formatted"L]; } ELSE Put.Line[toolData.fileSW, "Floppy probably contains valid information"L]; EXITS virgin => NULL; END; Put.Line[ toolData.fileSW, "Formatting will DESTROY all contents, confirm to continue"L]; IF ~ILT.Confirm[] THEN RETURN; --label.length _ 0; IF label = NIL THEN { Put.Line[toolData.fileSW, "Please supply floppy name"]; Process.Pause[Process.SecondsToTicks[5]]; RETURN; }; << IF label # NIL THEN toolData.floppyName _ String.CopyToNewString[ s: label, z: Heap.systemZone] ELSE toolData.floppyName _ String.CopyToNewString[ s: "UnnamedFloppy"L, z: Heap.systemZone]; >> IF label # NIL OR toolData.floppyName # NIL THEN { Put.Text[toolData.fileSW, "label # Nil:"L]; Put.Text[toolData.fileSW, label]; Put.Line[toolData.fileSW, "<"L]; Process.Pause[Process.SecondsToTicks[5]]; toolData.floppyName _ label; Put.Text[toolData.fileSW, "floppyName:"L]; Put.Text[toolData.fileSW, toolData.floppyName]; Put.Line[toolData.fileSW, "<"L]; Process.Pause[Process.SecondsToTicks[5]]; toolData.floppyName _ String.CopyToNewString[ s: label, z: Heap.systemZone]; Put.Text[toolData.fileSW, "floppyName:"L]; Put.Text[toolData.fileSW, toolData.floppyName]; Put.Line[toolData.fileSW, "<"L]; }; IF debug THEN { Put.Line[toolData.fileSW, toolData.floppyName]; Process.Pause[Process.SecondsToTicks[5]]; }; IF ~ILT.Confirm[] THEN RETURN; --temp Put.Text[toolData.fileSW, "Formatting... "L]; Floppy.Format[ 0, nFiles, toolData.floppyName, density, sides ! Floppy.Error => SELECT error FROM onlyOneSide => {sides _ one; RETRY}; onlySingleDensity => {density _ single; RETRY}; badDisk => { Put.Line[ toolData.fileSW, "Can't format this disk; may be write protecte"L]; gotError _ TRUE; Process.Pause[Process.SecondsToTicks[5]]; GOTO noGood; }; ENDCASE; -- ERROR Abort["Can't format this disk; may be write protected"L]; Floppy.AlreadyFormatted => RESUME ]; Put.Line[toolData.fileSW, "...done"L]; EXITS noGood => RETURN; END; -- FormatDisk 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]]; }; Put.Line[toolData.fileSW, "to be implemented"L]; CopyCmd; END; --FormSWDuplicateProc FormSWFormatProc: FormSW.ProcType = BEGIN ok: BOOLEAN; IF debug THEN { Put.Line[toolData.fileSW, "FormSWFormatProc...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [ok] _ FormatDisk[256, toolData.floppyName, default, default]; 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 debug THEN { Put.Line[toolData.fileSW, "FormSWReadProc...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; Put.Line[toolData.fileSW, "to be implemented"L]; END; --FormSWReadProc FormSWWriteProc: FormSW.ProcType = BEGIN IF debug THEN { Put.Line[toolData.fileSW, "FormSWWriteProc...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; Put.Line[toolData.fileSW, "to be implemented"L]; 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, "InfoDisk...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [v] _ OpenFloppy[]; IF ~opened THEN RETURN; IF debug THEN { Put.Line[toolData.fileSW, "GetAttributes...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [freeSpace, largestBlock, , , density, sides] _ Floppy.GetAttributes[ v, label]; toolData.floppyName _ String.CopyToNewString[ s: label, z: Heap.systemZone]; Put.CR[toolData.fileSW]; 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[]; FormSW.DisplayItem[toolData.paramSW, 2]; 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] _ OpenFloppy[]; IF ~opened THEN RETURN; 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, "*"L ! UNWIND => {AccessFloppy.Close[ ! Floppy.Error => CONTINUE]}]; AccessFloppy.Close[]; END; --ListFiles MesaStringFromAttributes: PUBLIC PROC [ attris: AccessFloppy.Attributes, name: LONG STRING] = BEGIN -- should protect against a bogus attris (i.e., one from a non AccessFloppy file). name.length _ 0; IF attris = NIL THEN RETURN WITH ERROR AccessFloppy.Error[invalidParameter]; IF attris.length > attris.maxlength THEN -- invalidAttributes? RETURN WITH ERROR AccessFloppy.Error[invalidParameter]; IF name.maxlength < attris.length THEN RETURN WITH ERROR AccessFloppy.Error[invalidParameter]; IF debug THEN { Put.Line[toolData.fileSW, "Inline.LongCOPY...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; [] _ Inline.LongCOPY[ to: @name.text, nwords: attris.length/2, from: @attris.name]; name.length _ attris.length; IF name.length # 0 THEN -- pick up odd character. name[name.length - 1] _ LOOPHOLE[attris.name[name.length - 1]]; END; -- MesaStringFromAttributes. 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 = 3; 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]; items[2] _ StringItem[ tag: "Floppy Name"L, string: @toolData.floppyName, place: newLine, 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 heraldName: STRING _ [80]; String.AppendString[heraldName, "XSIS:Xerox Floppy Option"L]; --String.AppendString[heraldName, " of "L]; --Time.Append[heraldName, Time.Unpack[Runtime.GetBcdTime[]]]; --heraldName.length _ heraldName.length - 3; --String.AppendString[heraldName, " on Pilot Version "L]; --Version.Append[heraldName]; RETURN[ Tool.Create[ makeSWsProc: MakeSWs, initialState: default, --clientTransition: Transit, name: heraldName]]; --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]]}; OpenFloppy: PROCEDURE[] RETURNS [v: Floppy.VolumeHandle] = BEGIN IF debug THEN { Put.Line[toolData.fileSW, "OpenFloppy...."L]; Process.Pause[Process.SecondsToTicks[5]]; }; opened _ TRUE; v _ AccessFloppy.Open[ ! Floppy.Error => SELECT error FROM notReady => { Put.Line[toolData.msgSW, "Floppy Not Closed"L]; GOTO noGood; }; invalidFormat => { Put.Line[toolData.msgSW, "Invalid Floppy Format"L]; GOTO noGood;}; needsScavenging => { Put.Line[ toolData.msgSW, "Floppy Needs Scavenging"L]; GOTO noGood; }; ENDCASE]; EXITS noGood => opened _ FALSE; END; -- OpenFloppy 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 PutVolumeName: PROCEDURE[] = BEGIN Put.Text[toolData.fileSW, "Volume = "L]; Put.LongString[toolData.fileSW, toolData.volName]; Put.CR[toolData.fileSW]; END; --PutVolumeName 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 RetrieveFilePiece: PROC [ floppyFile: Floppy.FileHandle, mStream: MStream.Handle, attributes: AccessFloppy.Attributes] = BEGIN mFile: MFile.Handle _ NIL; block: Environment.Block; bufferSizeInBytes, bytesRemaining, bytesToRead, bytesTransfered: AccessFloppy.LengthInBytes; start, pagesToRead: File.PageNumber; bytesTransfered _ 0; -- starting page number of the floppy file, page count of the floppy file, and byte count of the floppy file. start _ 0; bytesRemaining _ attributes.size*Environment.bytesPerPage; bufferSizeInBytes _ bufferSize*Environment.bytesPerPage; -- set attributes mFile _ MStream.GetFile[mStream]; MFile.SetTimes[ file: mFile, create: attributes.createDate, write: attributes.lastWrittenDate]; MFile.SetType[mFile, MFile.Type[binary]]; MStream.SetLength[mStream, bytesRemaining]; -- set up block block.blockPointer _ Space.LongPointer[spaceHandle]; block.startIndex _ 0; --copy as many chunks of the standard buffer size as possible..... UNTIL bytesRemaining = 0 DO bytesToRead _ MIN[bytesRemaining, bufferSizeInBytes]; pagesToRead _ PagesFromBytes[bytesToRead]; Floppy.Read[floppyFile, start, pagesToRead, block.blockPointer]; block.stopIndexPlusOne _ Inline.LowHalf[bytesToRead]; mStream.put[mStream, block, FALSE]; start _ start + pagesToRead; bytesTransfered _ bytesTransfered + bytesToRead; bytesRemaining _ bytesRemaining - bytesToRead; ENDLOOP; END; -- RetrieveFilePiece. StoreFilePiece: PROC [ mStream: MStream.Handle, floppyFile: Floppy.FileHandle, size: File.PageNumber] = BEGIN -- store data from disk to floppy block: Environment.Block; bufferSizeInBytes, bytesRemaining, bytesToWrite, bytesTransfered: AccessFloppy.LengthInBytes; start, pagesToWrite: File.PageNumber; why: Stream.CompletionCode _ normal; bytesTransfered _ 0; -- starting page number of the floppy file, page count of the floppy file, and byte count of the floppy file. start _ 0; bytesRemaining _ (size*Environment.bytesPerPage); bufferSizeInBytes _ bufferSize*Environment.bytesPerPage; -- set up block block.blockPointer _ Space.LongPointer[spaceHandle]; block.startIndex _ 0; bytesToWrite _ bytesRemaining; --copy as many chunks of the standard buffer size as possible..... UNTIL bytesRemaining = 0 OR why = endOfStream DO bytesToWrite _ MIN[bytesRemaining, bufferSizeInBytes]; block.stopIndexPlusOne _ Inline.LowHalf[bytesToWrite]; [bytesToWrite, why, ] _ mStream.get[ mStream, block, Stream.defaultInputOptions]; pagesToWrite _ PagesFromBytes[bytesToWrite]; Floppy.Write[floppyFile, start, pagesToWrite, block.blockPointer]; start _ start + pagesToWrite; bytesTransfered _ bytesTransfered + bytesToWrite; bytesRemaining _ bytesRemaining - bytesToWrite; ENDLOOP; END; -- StoreFilePiece. Transit: ToolWindow.TransitionProcType = BEGIN SELECT TRUE FROM old = inactive => BEGIN IF toolData = NIL THEN toolData _ Heap.systemZone.NEW[Data _ []]; IF attributes = NIL THEN attributes _ z.NEW[ AccessFloppy .AttributesRecord[AccessFloppy.maxDataSize]]; --UserInput.ResetUserAbort[window]; --data.logSW _ window; -- data.window _ ToolWindow.WindowForSubwindow[window]; -- data.ttyWindow _ TTYSW.GetTTYHandle[window]; -- destroy _ FALSE; active _ TRUE; END; new = inactive => BEGIN IF toolData # NIL THEN BEGIN FormSW.Destroy[toolData.paramSW]; FormSW.Destroy[toolData.commandSW]; Heap.systemZone.FREE[@toolData]; END; IF attributes # NIL THEN { z.FREE[@attributes]; attributes _ NIL}; --ToolDriver.RemoveSWs[tool: "LispTool"L]; active _ FALSE; END; ENDCASE; END; -- Transit 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.~ : : list of file names; /s on a name uses next name as destination : names may contain * and # : Read | - copies files from floppy Write - 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 - shows files on floppy; switches show: l => length, t => type, d => create date, w => write date, v => everything Delete - 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.