--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.~ : : 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.