DIRECTORY AMBridge USING [TVToCardinal], AMEventsExtra USING [Boot], AMTypes USING [--Error,-- Index, IndexToName, NValues, Type, Value], Ascii USING [SP], Booting USING [ Boot, Bootee, BootFileNumber, defaultSwitches, GetBootFileNumber, MakeBootable, MicrocodeType, nullMicrocode, Switches], Buttons USING [Button, ButtonProc, Create, SetDisplayStyle], Containers USING [ChildXBound, Container, Create], ConvertUnsafe USING [AppendRope, ToRefText, ToRope], DCSFileTypes USING [tLeaderPage], Directory USING [Error, GetNext, ignore, Lookup, VolumeError], File USING [Capability, GetAttributes, nullCapability, PageNumber], Heap USING [systemZone], IO USING [char, EndOf, Error, GetCard, PutFToRope, rope, RIS, STREAM], Labels USING [Create], List USING [Compare, Comparison, Reverse, Sort], Menus USING [AppendMenuEntry, CreateMenu, CreateEntry, Menu, MenuLine, MenuProc], MessageWindow USING [Append, Blink, Clear, Confirm], PhysicalVolume USING [ GetAttributes, GetNext, GetNextLogicalVolume, ID, maxNameLength, nullID], Process USING [Detach], Rope USING [ Cat, Concat, Equal, Fetch, Find, FromChar, FromRefText, Length, Lower, Map, ROPE, Substr, ToRefText, Upper], Rules USING [Create, Rule], Runtime USING[IsBound], UserProfile USING [Line], VFonts USING [FontHeight, StringWidth], ViewerClasses USING [Viewer], ViewerOps USING [ChangeColumn, EnumerateViewers, EnumProc, OpenIcon, SetMenu, SetOpenHeight], ViewerSpecs USING [openRightWidth], ViewerTools USING [ GetContents, InhibitUserEdits, MakeNewTextViewer, SelPosRec, SetContents, SetSelection], Volume USING [ GetLabelString, GetNext, ID, maxNameLength, NeedsScavenging, nullID, systemID, Unknown], VolumeExtras USING [OpenVolume]; BootTool: CEDAR MONITOR IMPORTS AMBridge, AMEventsExtra, AMTypes, Booting, Buttons, Containers, ConvertUnsafe, Directory, File, Heap, IO, Labels, List, Menus, MessageWindow, PhysicalVolume, Process, Rope, Rules, Runtime, UserProfile, VFonts, ViewerOps, ViewerSpecs, ViewerTools, Volume, VolumeExtras = BEGIN entryHeight: NAT = VFonts.FontHeight[] + 2; entryVSpace: NAT = VFonts.FontHeight[]*2/3; entryHSpace: NAT = 10; BootToolHandle: TYPE = REF BootToolHandleRec; BootToolHandleRec: TYPE = RECORD [ outer: Containers.Container _ NIL, height: NAT _ 0, s1Data: S1Data, s2Data: S2Data ]; SimpleButtonRef: TYPE = REF SimpleButtonRec; SimpleButtonRec: TYPE = RECORD [ volume: Volume.ID, switches: Rope.ROPE ]; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- MakeBootTool: ENTRY Buttons.ButtonProc = { menu: Menus.Menu; handle: BootToolHandle; IF mouseButton # blue THEN {MakeBootButtons[]; RETURN}; menu _ Menus.CreateMenu[lines: 2]; handle _ NEW[BootToolHandleRec]; handle.outer _ Containers.Create[info: [ name: "Boot Tool", iconic: TRUE, column: right, scrollable: FALSE], paint: FALSE]; MakeSimpleButtonsMenu[menu, 0]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Boot", proc: DoBoot, clientData: handle, fork: TRUE, guarded: TRUE], 1]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Reset", proc: ResetDefaults, clientData: handle, fork: TRUE], 1]; ViewerOps.SetMenu[viewer: handle.outer, menu: menu]; BuildSection1[handle]; BuildSection2[handle]; ResetDefaultsInternal[handle]; ViewerOps.SetOpenHeight[handle.outer, handle.height]; ViewerOps.OpenIcon[icon: handle.outer, bottom: FALSE]; }; buttonsCreated: BOOLEAN _ FALSE; MakeBootButtons: PROC = { volID: Volume.ID _ Volume.nullID; IF buttonsCreated THEN RETURN ELSE buttonsCreated _ TRUE; UNTIL (volID _ Volume.GetNext[volID, ALL[TRUE]]) = Volume.nullID DO volName: STRING _ [Volume.maxNameLength]; label, switches: Rope.ROPE; TRUSTED{ Volume.GetLabelString[volID, volName]; label_ConvertUnsafe.ToRope[volName] }; IF (switches _ GetSwitches[label]).Length[] > 0 THEN label _ label.Cat["/", switches]; [] _ Buttons.Create[info: [name: label], proc: SimpleBootProc, clientData: NEW[SimpleButtonRec _ [volID, switches]], fork: TRUE, guarded: TRUE]; ENDLOOP; [] _ Buttons.Create[info: [name: "Alto"], proc: AltoBootProc, clientData: NIL, fork: TRUE, guarded: TRUE]; [] _ Buttons.Create[info: [name: "BB"], proc: BootButtonProc, clientData: NIL, fork: TRUE, guarded: TRUE]; [] _ Buttons.Create[info: [name: "Basic"], proc: BasicCedarDorado, clientData: NIL, fork: TRUE, guarded: TRUE]; }; MakeSimpleButtonsMenu: INTERNAL PROC [menu: Menus.Menu, line: Menus.MenuLine] = { volID: Volume.ID _ Volume.nullID; UNTIL (volID _ Volume.GetNext[volID, ALL[TRUE]]) = Volume.nullID DO volName: STRING _ [Volume.maxNameLength]; label, switches: Rope.ROPE; TRUSTED{ Volume.GetLabelString[volID, volName]; label_ConvertUnsafe.ToRope[volName] }; IF (switches _ GetSwitches[label]).Length[] > 0 THEN label _ label.Cat["/", switches]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: label, proc: SimpleBootProc, clientData: NEW[SimpleButtonRec _ [volID, switches]], fork: TRUE, guarded: TRUE], line]; ENDLOOP; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Alto", proc: AltoBootProc, clientData: NIL, fork: TRUE, guarded: TRUE], line]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "BB", proc: BootButtonProc, clientData: NIL, fork: TRUE, guarded: TRUE], line]; Menus.AppendMenuEntry[menu, Menus.CreateEntry[name: "Basic", proc: BasicCedarDorado, clientData: NIL, fork: TRUE, guarded: TRUE], line]; }; GetSwitches: PROC [name: Rope.ROPE] RETURNS [switches: Rope.ROPE] = { name _ name.Concat["Switches"]; switches _ UserProfile.Line[name]; IF switches.Length[] = 0 THEN switches _ UserProfile.Line[Rope.Concat["Boot.", name]]; }; AddSeparatingRule: PROC [handle: BootToolHandle] = { rule: Rules.Rule = Rules.Create[info: [ parent: handle.outer, wy: handle.height, ww: handle.outer.cw, wh: 1 ]]; Containers.ChildXBound[handle.outer, rule]; -- constrain rule to be width of parent handle.height _ handle.height + entryVSpace; -- spacing after rule }; MakeCenteredLabel: PROC [handle: BootToolHandle, name: Rope.ROPE] = { [] _ Labels.Create[info: [ name: name, parent: handle.outer, wx: (ViewerSpecs.openRightWidth - VFonts.StringWidth[name])/2, wy: handle.height, wh: entryHeight, border: FALSE ]]; handle.height _ handle.height + entryHeight + entryVSpace; }; ResetDefaultsInternal: INTERNAL PROC [handle: BootToolHandle] = { ResetSection1[handle]; ResetSection2[handle]; }; ---- ---- ---- ---- ---- ---- ---- ---- Section1Data: TYPE = RECORD [ selected: BooteeClass _ volume, bootees: ARRAY BooteeClass OF Bootee _ ALL[NIL], microcodeListDone: BOOL _ FALSE, microcodeListBuilt: CONDITION _ [timeout: 0] ]; S1Data: TYPE = REF Section1Data; BooteeClass: TYPE = {volume, file, ucode, physicalVolume}; Bootee: TYPE = REF BooteeObject; BooteeObject: TYPE = RECORD [ button: Buttons.Button _ NIL, choices: ChoiceList _ NIL, currentChoice: ChoiceList _ NIL, -- currentChoice.first is what's interesting displayedChoice: ViewerClasses.Viewer _ NIL ]; ChoiceList: TYPE = LIST OF REF ANY; ChoiceRef: TYPE = REF ChoiceDesc; ChoiceDesc: TYPE = RECORD [ name: Rope.ROPE, value: REF ANY]; VolumeVal: TYPE = REF Volume.ID; FileVal: TYPE = REF File.Capability; MicrocodeVal: TYPE = REF Booting.BootFileNumber; PhysicalVolumeVal: TYPE = REF PhysicalVolume.ID; BuildSection1: INTERNAL PROC [handle: BootToolHandle] = { s1Data: S1Data = NEW[Section1Data _ []]; MakeBootee: PROC [ buttonName: Rope.ROPE, buttonProc: Buttons.ButtonProc, choicesProc: PROC RETURNS [ChoiceList] _ NIL] RETURNS [bootee: Bootee] = { bootee _ NEW[BooteeObject _ []]; bootee.button _ Buttons.Create[ info: [name: buttonName, wx: entryHSpace, wy: handle.height, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: handle.outer, border: TRUE ], proc: buttonProc, fork: TRUE, clientData: handle ]; IF choicesProc ~= NIL THEN bootee.choices _ choicesProc[]; bootee.displayedChoice _ ViewerTools.MakeNewTextViewer[info: [ parent: handle.outer, wx: bootee.button.wx + bootee.button.ww + entryHSpace, wy: handle.height, ww: 50, -- ugly, but necessary preparation for Containers.ChildXBound wh: entryHeight, data: NIL, scrollable: FALSE, border: FALSE ]]; Containers.ChildXBound[container: handle.outer, child: bootee.displayedChoice]; handle.height _ handle.height + entryHeight + entryVSpace; }; AddSeparatingRule[handle]; MakeCenteredLabel[handle, "Booting Sources"]; s1Data.bootees[volume] _ MakeBootee["Volume", SelectVolumeBootee, BuildVolumeList]; ViewerTools.InhibitUserEdits[s1Data.bootees[volume].displayedChoice]; s1Data.bootees[file] _ MakeBootee["File", SelectFileBootee]; TRUSTED{ Process.Detach[FORK BuildBootFileListEntry[handle]] }; s1Data.bootees[ucode] _ MakeBootee["Microcode", SelectMicrocodeBootee]; s1Data.bootees[physicalVolume] _ MakeBootee["Physical Volume", SelectPhysicalVolumeBootee, BuildPhysicalVolumeList]; ViewerTools.InhibitUserEdits[s1Data.bootees[physicalVolume].displayedChoice]; handle.s1Data _ s1Data; BuildMicrocodeList[handle]; }; ResetSection1: INTERNAL PROC [handle: BootToolHandle] = { s1Data: S1Data = handle.s1Data; SelectBootee[s1Data, volume]; s1Data.bootees[volume].currentChoice _ s1Data.bootees[volume].choices; SetChoice[s1Data.bootees[volume]]; s1Data.bootees[file].choices _ s1Data.bootees[file].currentChoice _ NIL; SetChoice[s1Data.bootees[file]]; s1Data.bootees[ucode].currentChoice _ s1Data.bootees[ucode].choices; SetChoice[s1Data.bootees[ucode]]; s1Data.bootees[physicalVolume].currentChoice _ s1Data.bootees[physicalVolume].choices; SetChoice[s1Data.bootees[physicalVolume]]; }; SetChoice: PROC [bootee: Bootee, deselect: BOOL _ FALSE] = { name: Rope.ROPE = IF bootee.currentChoice = NIL THEN NIL ELSE NARROW[bootee.currentChoice.first, ChoiceRef].name; ViewerTools.SetContents[bootee.displayedChoice, name]; IF deselect THEN ViewerTools.SetSelection[bootee.displayedChoice, NEW[ViewerTools.SelPosRec _ [start: Rope.Length[name], length: 0]]]; }; BuildVolumeList: INTERNAL PROC RETURNS [volumes: ChoiceList _ NIL] = { volume: Volume.ID _ Volume.nullID; UNTIL (volume _ Volume.GetNext[volume, ALL[TRUE]]) = Volume.nullID DO IF volume ~= Volume.systemID THEN volumes _ CONS[VolumeToChoice[volume], volumes]; ENDLOOP; volumes _ List.Sort[volumes, CompareChoiceNames]; RETURN [CONS[SystemVolumeChoice[], volumes]] }; SystemVolumeChoice: PROC RETURNS [ChoiceRef] = INLINE {RETURN [VolumeToChoice[Volume.systemID]]}; VolumeToChoice: PROC [volume: Volume.ID] RETURNS [ChoiceRef] = TRUSTED { volName: STRING = [Volume.maxNameLength]; volID: VolumeVal = NEW[Volume.ID _ volume]; Volume.GetLabelString[volume, volName]; RETURN [NEW[ChoiceDesc _ [Rope.FromRefText[ConvertUnsafe.ToRefText[volName]], volID]]] }; CompareChoiceNames: PROC [ref1, ref2: REF ANY] RETURNS [List.Comparison] = {RETURN[List.Compare[NARROW[ref1, ChoiceRef].name, NARROW[ref2, ChoiceRef].name]]}; BuildBootFileListEntry: ENTRY PROC [handle: BootToolHandle] = { handle.s1Data.bootees[file].choices _ BuildBootFileList[handle ! ANY => CONTINUE]}; BuildBootFileList: INTERNAL PROC [handle: BootToolHandle] RETURNS [bootFiles: ChoiceList _ NIL] = { NormalizeFileName: PROC [file: Rope.ROPE] RETURNS [front, back: Rope.ROPE _ NIL] = { sysDir: Rope.ROPE = "SysDir>"; i: INT _ file.Find[sysDir, 0, FALSE]; IF i >= 0 THEN file _ Rope.Concat[file.Substr[0, i], file.Substr[i+sysDir.Length[]]]; IF (i _ file.Find[">"]) = -1 THEN {back _ file; RETURN}; IF file.Fetch[0] ~= '< THEN front _ Rope.Concat["<", file.Substr[0, i+1]] ELSE front _ file.Substr[0, i+1]; front _ front.Concat[sysDir]; back _ file.Substr[i+1]; }; GetNextBootFile: PROC [file: Rope.ROPE] RETURNS [nextFile: Rope.ROPE, nextCap: File.Capability] = TRUSTED { path, thisFile: Rope.ROPE; pathS: LONG STRING; EndsInDotBoot: PROC [file: LONG STRING] RETURNS [BOOL] = TRUSTED { bootExt: STRING = ".boot"L; bootLen: NAT = bootExt.length; len: NAT = IF file = NIL THEN 0 ELSE file.length; IF len < bootLen THEN RETURN[FALSE]; FOR i: NAT IN [0..bootLen) DO IF Rope.Lower[file[len-bootLen+i]] ~= bootExt[i] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE] }; thisFileS: LONG STRING = [100]; [path, thisFile] _ NormalizeFileName[file]; pathS _ LOOPHOLE[Rope.ToRefText[path]]; ConvertUnsafe.AppendRope[thisFileS, thisFile]; DO nextFile _ NIL; nextCap _ Directory.GetNext[ pathName: pathS, currentName: thisFileS, nextName: thisFileS ! Directory.VolumeError--[volume]-- => IF type = volumeNotOpen THEN { VolumeExtras.OpenVolume[volume: volume, readOnly: TRUE ! Volume.Unknown, Volume.NeedsScavenging => EXIT]; RETRY} ELSE EXIT ]; SELECT TRUE FROM thisFileS.length = 0 => EXIT; EndsInDotBoot[thisFileS] => {nextFile _ ConvertUnsafe.ToRope[thisFileS]; EXIT}; ENDCASE; ENDLOOP; }; DoBootFilesWithPrefix: PROC [file: Rope.ROPE] = { DO cap: File.Capability; [file, cap] _ GetNextBootFile[file ! Directory.Error, Directory.VolumeError => { PostMessage[handle, "Incorrect file path"]; EXIT}]; IF file = NIL THEN EXIT; bootFiles _ CONS[NEW[ChoiceDesc _ [file, NEW[File.Capability _ cap]]], bootFiles]; ENDLOOP; }; front, back: Rope.ROPE; [front, back] _ NormalizeFileName[ViewerTools.GetContents[handle.s1Data.bootees[file].displayedChoice]]; IF front.Length[] > 0 AND back.Length[] = 0 THEN DoBootFilesWithPrefix[front] ELSE FOR c: ChoiceList _ handle.s1Data.bootees[volume].choices, c.rest UNTIL c = NIL DO DoBootFilesWithPrefix[Rope.Cat["<", NARROW[c.first, ChoiceRef].name, ">SysDir>"]]; ENDLOOP; RETURN [List.Reverse[bootFiles]] }; BuildMicrocodeList: INTERNAL PROC [handle: BootToolHandle] = { OPEN Booting; handle.s1Data.bootees[ucode].choices _ LIST[NEW[ChoiceDesc _ ["(default)", NEW[BootFileNumber _ nullMicrocode]]]]; TRUSTED{ Process.Detach[FORK BuildFullMicrocodeList[handle]] }; }; BuildFullMicrocodeList: PROC [handle: BootToolHandle] = { OPEN Booting; InstallMicrocodeList: ENTRY PROC [handle: BootToolHandle, microcode: ChoiceList] = { handle.s1Data.bootees[ucode].choices _ microcode; handle.s1Data.microcodeListDone _ TRUE; NOTIFY handle.s1Data.microcodeListBuilt; }; microcode: ChoiceList _ LIST[NEW[ChoiceDesc _ ["(default)", NEW[BootFileNumber _ nullMicrocode]]]]; BEGIN ENABLE --AMTypes.Error-- ANY => CONTINUE; Massage: PROC [name: Rope.ROPE] RETURNS [newName: Rope.ROPE] = { OPEN Rope; XOR: PROC [a, b: BOOL] RETURNS [BOOL] = INLINE {RETURN [(a AND b) OR (~a AND ~b)]}; start: INT _ 1; doingLower: BOOL _ FALSE; newName _ FromChar[Upper[Fetch[name, 0]]]; DO next: INT _ start; UNTIL next = Length[name] OR XOR[doingLower, ~(Fetch[name, next] IN ['a..'z])] DO next _ next + 1; ENDLOOP; newName _ Concat[newName, Substr[name, start, next - start]]; IF next = Length[name] THEN EXIT ELSE start _ next; IF doingLower THEN newName _ Concat[newName, FromChar[Ascii.SP]]; doingLower _ ~doingLower; ENDLOOP; }; uT: AMTypes.Type = LOOPHOLE[CODE[MicrocodeType]]; FOR i: AMTypes.Index IN [1..AMTypes.NValues[uT]] DO name: Rope.ROPE = Massage[AMTypes.IndexToName[uT, i]]; ucodeType: MicrocodeType; TRUSTED{ ucodeType _ LOOPHOLE[AMBridge.TVToCardinal[AMTypes.Value[uT, i]]] }; microcode _ CONS[ NEW[ChoiceDesc _ [name, NEW[BootFileNumber _ GetBootFileNumber[ucodeType]]]], microcode]; ENDLOOP; END; InstallMicrocodeList[handle, List.Reverse[microcode]]; }; BuildPhysicalVolumeList: INTERNAL PROC RETURNS [physicalVolumes: ChoiceList _ NIL] = TRUSTED { physicalVolume: PhysicalVolume.ID _ PhysicalVolume.nullID; UNTIL (physicalVolume _ PhysicalVolume.GetNext[physicalVolume]) = PhysicalVolume.nullID DO IF PhysicalVolume.GetNextLogicalVolume[physicalVolume, Volume.nullID] ~= Volume.nullID THEN physicalVolumes _ CONS[PhysicalVolumeToChoice[physicalVolume], physicalVolumes]; ENDLOOP; physicalVolumes _ List.Sort[physicalVolumes, CompareChoiceNames]; }; PhysicalVolumeToChoice: PROC [physicalVolume: PhysicalVolume.ID] RETURNS [ChoiceRef] = TRUSTED { volName: STRING = [PhysicalVolume.maxNameLength]; volID: PhysicalVolumeVal = NEW[PhysicalVolume.ID _ physicalVolume]; [] _ PhysicalVolume.GetAttributes[physicalVolume, volName]; RETURN [NEW[ChoiceDesc _ [Rope.FromRefText[ConvertUnsafe.ToRefText[volName]], volID]]] }; ---- ---- ---- ---- ---- ---- ---- ---- Section2Data: TYPE = RECORD [ switchesButton: Buttons.Button _ NIL, switches: ViewerClasses.Viewer _ NIL ]; S2Data: TYPE = REF Section2Data; BuildSection2: INTERNAL PROC [handle: BootToolHandle] = { s2Data: S2Data = NEW[Section2Data _ []]; AddSeparatingRule[handle]; MakeCenteredLabel[handle, "Booting Options"]; s2Data.switchesButton _ Buttons.Create[ info: [name: "Switches:", wx: entryHSpace, wy: handle.height, wh: entryHeight, -- specify rather than defaulting so line is uniform parent: handle.outer, border: FALSE ], proc: SelectBootSwitches, fork: TRUE, clientData: handle ]; s2Data.switches _ ViewerTools.MakeNewTextViewer[info: [ parent: handle.outer, wx: s2Data.switchesButton.wx + s2Data.switchesButton.ww + entryHSpace, wy: handle.height, ww: 50, -- ugly, but necessary preparation for Containers.ChildXBound wh: entryHeight, data: NIL, -- initial contents scrollable: FALSE, border: FALSE ]]; Containers.ChildXBound[container: handle.outer, child: s2Data.switches]; handle.height _ handle.height + entryHeight + entryVSpace; handle.s2Data _ s2Data; }; ResetSection2: INTERNAL PROC [handle: BootToolHandle] = { s2Data: S2Data = handle.s2Data; ViewerTools.SetContents[s2Data.switches, UserProfile.Line["Boot.Switches"]]; }; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- PostMessage: PROC [handle: BootToolHandle, msg: Rope.ROPE] = {MessageWindow.Clear[]; MessageWindow.Append[msg]}; SelectVolumeBootee: ENTRY Buttons.ButtonProc = { handle: BootToolHandle = NARROW[clientData]; s1Data: S1Data = handle.s1Data; previouslySelected: BOOL = (s1Data.selected = volume); previousContents: Rope.ROPE = ViewerTools.GetContents[s1Data.bootees[volume].displayedChoice]; IF ~previouslySelected THEN SelectBootee[s1Data, volume]; ViewerTools.SetSelection[s1Data.bootees[volume].displayedChoice, NEW[ViewerTools.SelPosRec _ [start: Rope.Length[previousContents], length: 0]]]; IF previouslySelected THEN AdvanceName[s1Data.bootees[volume]]; }; SelectFileBootee: ENTRY Buttons.ButtonProc = { handle: BootToolHandle = NARROW[clientData]; s1Data: S1Data = handle.s1Data; previouslySelected: BOOL = (s1Data.selected = file); IF ~previouslySelected THEN SelectBootee[s1Data, file]; ViewerTools.SetSelection[viewer: s1Data.bootees[file].displayedChoice, selection: NIL]; IF previouslySelected THEN { IF s1Data.bootees[file].choices = NIL OR (mouseButton ~= red) THEN s1Data.bootees[file].choices _ BuildBootFileList[handle]; AdvanceName[s1Data.bootees[file]]; }; }; SelectMicrocodeBootee: ENTRY Buttons.ButtonProc = { handle: BootToolHandle = NARROW[clientData]; s1Data: S1Data = handle.s1Data; previouslySelected: BOOL = (s1Data.selected = ucode); IF ~previouslySelected THEN SelectBootee[s1Data, ucode]; ViewerTools.SetSelection[viewer: s1Data.bootees[ucode].displayedChoice, selection: NIL]; IF previouslySelected THEN { UNTIL handle.s1Data.microcodeListDone DO WAIT handle.s1Data.microcodeListBuilt; ENDLOOP; AdvanceName[s1Data.bootees[ucode]]; }; }; SelectPhysicalVolumeBootee: ENTRY Buttons.ButtonProc = { handle: BootToolHandle = NARROW[clientData]; s1Data: S1Data = handle.s1Data; previouslySelected: BOOL = (s1Data.selected = physicalVolume); previousContents: Rope.ROPE = ViewerTools.GetContents[s1Data.bootees[physicalVolume].displayedChoice]; IF ~previouslySelected THEN SelectBootee[s1Data, physicalVolume]; ViewerTools.SetSelection[s1Data.bootees[physicalVolume].displayedChoice, NEW[ViewerTools.SelPosRec _ [start: Rope.Length[previousContents], length: 0]]]; IF previouslySelected THEN AdvanceName[s1Data.bootees[physicalVolume]]; }; SelectBootee: INTERNAL PROC [s1Data: S1Data, booteeClass: BooteeClass] = { SetButton[s1Data.bootees[s1Data.selected].button, FALSE]; SetButton[s1Data.bootees[booteeClass].button, TRUE]; s1Data.selected _ booteeClass; }; AdvanceName: INTERNAL PROC [bootee: Bootee] = { choiceRef: ChoiceRef = IF bootee.currentChoice = NIL THEN NIL ELSE NARROW[bootee.currentChoice.first]; IF bootee.choices = NIL THEN RETURN; IF choiceRef = NIL OR ~Rope.Equal[choiceRef.name, ViewerTools.GetContents[bootee.displayedChoice], FALSE] OR (bootee.currentChoice _ bootee.currentChoice.rest) = NIL THEN bootee.currentChoice _ bootee.choices; SetChoice[bootee: bootee, deselect: TRUE]; }; SelectBootSwitches: ENTRY Buttons.ButtonProc = { handle: BootToolHandle = NARROW[clientData]; ViewerTools.SetSelection[viewer: handle.s2Data.switches, selection: NIL]; }; SetButton: INTERNAL PROC [button: Buttons.Button, on: BOOL] = { IF on THEN Buttons.SetDisplayStyle[button: button, style: $WhiteOnBlack] ELSE Buttons.SetDisplayStyle[button: button, style: $BlackOnWhite]; }; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ActualBoot: PROC[boot: Booting.Bootee, switches: Booting.Switches _ Booting.defaultSwitches] = TRUSTED { IF Runtime.IsBound[AMEventsExtra.Boot] THEN AMEventsExtra.Boot[boot, switches] ELSE Booting.Boot[boot, switches] }; SimpleBootProc: Menus.MenuProc = { data: SimpleButtonRef = NARROW[clientData]; bootSwitches: Booting.Switches; error: Rope.ROPE; IF SomethingWorthSaving[] THEN RETURN; [bootSwitches, error] _ RopeToSwitches[data.switches]; IF error ~= NIL THEN MessageWindow.Append["Illegal boot switches.", TRUE] ELSE ActualBoot[[logical[data.volume]], bootSwitches]; }; AltoBootProc: Menus.MenuProc = { IF ~SomethingWorthSaving[] THEN ActualBoot[[microcode[Booting.GetBootFileNumber[altoMesa]]]]; }; BootButtonProc: Menus.MenuProc = { IF ~SomethingWorthSaving[] THEN ActualBoot[[bootButton[]]]; }; BasicCedarDorado: Menus.MenuProc = { cap: File.Capability = DirLookup["BasicCedarDorado.boot"]; IF cap ~= File.nullCapability THEN { switches: Booting.Switches; error: Rope.ROPE; bias: NAT = IF File.GetAttributes[cap].type = DCSFileTypes.tLeaderPage THEN 1 ELSE 0; [switches, error] _ RopeToSwitches[UserProfile.Line["FileSwitches"]]; IF error = NIL AND ~SomethingWorthSaving[] THEN { Booting.MakeBootable[[cap, bias]]; ActualBoot[[file[[cap, bias]]], switches]; } ELSE MessageWindow.Append[error, TRUE]; } ELSE MessageWindow.Append["BasicCedarDorado.boot not found.", TRUE]; }; DoBoot: Menus.MenuProc = { CantBoot: ERROR = CODE; DoBootEntry: ENTRY PROC = --INLINE-- TRUSTED { ENABLE UNWIND => NULL; handle: BootToolHandle = NARROW[clientData]; bootee: Bootee = handle.s1Data.bootees[handle.s1Data.selected]; isCurrentChoice: BOOL = bootee.currentChoice ~= NIL AND Rope.Equal[ ViewerTools.GetContents[bootee.displayedChoice], NARROW[bootee.currentChoice.first, ChoiceRef].name]; choiceRef: ChoiceRef = IF isCurrentChoice THEN NARROW[bootee.currentChoice.first] ELSE NIL; switches: Booting.Switches; ProcessOptions: PROC = CHECKED { error: Rope.ROPE; [switches, error] _ RopeToSwitches[ViewerTools.GetContents[handle.s2Data.switches]]; IF error ~= NIL THEN {PostMessage[handle, error]; ERROR CantBoot}; }; SELECT handle.s1Data.selected FROM volume => { volume: Volume.ID; IF ~isCurrentChoice THEN ERROR; volume _ NARROW[choiceRef.value, VolumeVal]^; ProcessOptions[]; ActualBoot[[logical[volume]], switches]; }; file => { cap: File.Capability; firstPage: File.PageNumber; IF isCurrentChoice THEN cap _ NARROW[choiceRef.value, FileVal]^ ELSE { fileName: Rope.ROPE = ViewerTools.GetContents[bootee.displayedChoice]; IF (cap _ DirLookup[fileName]) = File.nullCapability THEN { PostMessage[handle, IO.PutFToRope["Unrecognizable file name '%g'", IO.rope[fileName]]]; ERROR CantBoot; }; }; firstPage _ IF File.GetAttributes[cap].type = DCSFileTypes.tLeaderPage THEN 1 ELSE 0; ProcessOptions[]; Booting.MakeBootable[[cap, firstPage]]; ActualBoot[[file[[cap, firstPage]]], switches]; }; ucode => { bfn: Booting.BootFileNumber; IF isCurrentChoice THEN bfn _ NARROW[choiceRef.value, MicrocodeVal]^ ELSE { rs: IO.STREAM = IO.RIS[ViewerTools.GetContents[bootee.displayedChoice]]; bfnC: LONG CARDINAL = IO.GetCard[rs ! IO.Error => GO TO badBfn]; IF ~rs.EndOf[] OR bfnC > LAST[CARDINAL]--Booting.BootFileNumber-- THEN GO TO badBfn; bfn _ [bfnC]; -- can't cause a fault EXITS badBfn => { PostMessage[handle, "Bad microcode specification"]; ERROR CantBoot; }; }; ProcessOptions[]; ActualBoot[[microcode[bfn]]]; }; physicalVolume => { physicalVolume: PhysicalVolume.ID; IF ~isCurrentChoice THEN ERROR; physicalVolume _ NARROW[choiceRef.value, PhysicalVolumeVal]^; ProcessOptions[]; ActualBoot[ [physical[PhysicalVolume.GetNextLogicalVolume[physicalVolume, Volume.nullID]]], switches]; }; ENDCASE; }; IF SomethingWorthSaving[] THEN RETURN; DoBootEntry[ ! CantBoot => CONTINUE]; }; ResetDefaults: ENTRY Menus.MenuProc = { ResetDefaultsInternal[NARROW[clientData, BootToolHandle]]; }; DirLookup: PROC [fileName: Rope.ROPE] RETURNS [cap: File.Capability _ File.nullCapability] = TRUSTED { fileS: LONG STRING _ Heap.systemZone.NEW[StringBody[Rope.Length[fileName]]]; ConvertUnsafe.AppendRope[from: fileName, to: fileS]; cap _ Directory.Lookup[fileName: fileS, permissions: Directory.ignore ! Directory.Error => CONTINUE; Directory.VolumeError => IF type = volumeNotOpen THEN { VolumeExtras.OpenVolume[volume: volume, readOnly: TRUE]; RETRY} ELSE CONTINUE]; Heap.systemZone.FREE[@fileS]; }; RopeToSwitches: PROC [textSwitches: Rope.ROPE] RETURNS [switches: Booting.Switches _ Booting.defaultSwitches, error: Rope.ROPE _ NIL] = { errorChar: CHAR; SetBootSwitch: PROC [c: CHAR] RETURNS [stop: BOOL] = { SELECT Rope.Lower[c] FROM 'a => switches.a _ down; 'b => switches.b _ down; 'c => switches.c _ down; 'd => switches.d _ down; 'e => switches.e _ down; 'f => switches.f _ down; 'g => switches.g _ down; 'h => switches.h _ down; 'i => switches.i _ down; 'j => switches.j _ down; 'k => switches.k _ down; 'l => switches.l _ down; 'm => switches.m _ down; 'n => switches.n _ down; 'o => switches.o _ down; 'p => switches.p _ down; 'q => switches.q _ down; 'r => switches.r _ down; 's => switches.s _ down; 't => switches.t _ down; 'u => switches.u _ down; 'v => switches.v _ down; 'w => switches.w _ down; 'x => switches.x _ down; 'y => switches.y _ down; 'z => switches.z _ down; '0 => switches.zero _ down; '1 => switches.one _ down; '2 => switches.two _ down; '3 => switches.three _ down; '4 => switches.four _ down; '5 => switches.five _ down; '6 => switches.six _ down; '7 => switches.seven _ down; '8 => switches.eight _ down; '9 => switches.nine _ down; ENDCASE => {errorChar _ c; RETURN [TRUE]}; RETURN [FALSE] }; IF Rope.Map[base: textSwitches, action: SetBootSwitch] THEN error _ IO.PutFToRope["Unrecognizable boot switch '%g'", IO.char[errorChar]]; }; SomethingWorthSaving: PROC RETURNS [BOOLEAN] = BEGIN dirty: BOOLEAN _ FALSE; CheckDirty: ViewerOps.EnumProc = { IF v.newVersion OR v.newFile THEN dirty _ TRUE ELSE RETURN; IF v.offDeskTop THEN ViewerOps.ChangeColumn[v, left]}; ViewerOps.EnumerateViewers[CheckDirty]; IF dirty THEN { MessageWindow.Blink[]; IF ~MessageWindow.Confirm["Confirm discard of edits . . . "] THEN { MessageWindow.Append["boot aborted."]; RETURN[TRUE]}}; RETURN[FALSE]; END; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- [] _ Buttons.Create[info: [name: "Boot"], proc: MakeBootTool, fork: TRUE]; END. JBootTool.mesa last edited by Roy Levin on January 7, 1983 1:14 pm last edited by Andrew Birrell on February 6, 1983 11:41 am Last Edited by: Maxwell, February 23, 1983 9:30 am Tool Construction The following turns off pending delete, and sets the type-in point at the end of the text if user editing is not inhibited The catch phrase below is intended to short-circuit catastrophic errors so that at least some minimal form of booting is possible, even if not all booting sources work. back, SysDir>back, volume>back, volume>SysDir>back all yield front = SysDir> SysDir>back and back yield front = NIL It would be nice if we didn't have to pick some a-priori upper bound for this string, but the Directory interface gives us no choice. Better error reporting someday, maybe... Button Action Procedures Kill pending delete selection elsewhere in tool Kill pending delete selection elsewhere in tool Menu Action Procedures This procedure can't be INLINE until Trinity (catch phrase in caller). The Main Body Edited on December 20, 1982 5:39 pm, by Levin Add forking of Boot file list construction on startup changes to: BuildSection1 - add FORK, BuildBootFileListEntry - new, BuildBootFileList - made INTERNAL, SimpleButtonRef, SimpleButtonRec, SimpleBootProc - make simple boot switches work, [], MakeSimpleButtonsMenu, AltoBootProc, BootButtonProc, BasicCedarDorado Edited on January 4, 1983 5:45 pm, by Levin Add forking of Microcode list construction and bullet-proof it against inability to locate MicrocodeBooting symbols changes to: BuildSection1, BuildMicrocodeList, BuildFullMicrocodeList, InstallMicrocodeList (local of BuildFullMicrocodeList), Massage (local of BuildFullMicrocodeList), Section1Data, SelectMicrocodeBootee, [] Edited on February 6, 1983 11:48 am, by Birrell Converted to CEDAR module (because Viewers is now SAFE); added TRUSTED as appropriate. Edited on February 6, 1983 1:51 pm, by Birrell Converted uses of MicrocodeBooting and TemporaryBooting to be Booting. Edited on February 8, 1983 11:37 am, by Levin Inserted catch phrases for ANY in the following procedures to try to recover gracefully when booting is required to escape out-of-VM. This doesn't guarantee that the tool will work, but it should work more often, and the buttons-only variants should work almost always. changes to: BuildBootFileListEntry, BuildFullMicrocodeList Edited on February 23, 1983 9:30 am, by Maxwell Made left and middle mouse clicks put up system buttons instead of creating a boot tool. SomethingWorthSaving[] now moves dirty viewers onto the screen if they are off the screen. Κ– "Cedar" style˜J˜Jšœ ™ Jšœ3™3Jšœ:™:J™2J™JšΟk ˜ ˜Jšœ œ˜Jšœœ˜JšœœΟc œ+˜DJšœœœ˜šœœ˜Jšœx˜x—Jšœœ/˜Jšœœ9˜CJšœœ˜Jšœœ1œœ˜FJšœœ ˜Jšœœ&˜0JšœœF˜QJšœœ!˜4šœ˜JšœI˜I—Jšœœ ˜šœœ˜ JšœLœ˜l—Jšœœ˜Jšœœ ˜Jšœ œ˜Jšœœ˜'Jšœœ ˜Jšœ œP˜_Jšœ œ˜#šœ œ˜J˜X—šœœ˜Jšœœ=˜X—Jšœ ˜ J˜—Jšœ œ˜J˜š˜Jšœfœ₯˜J˜—Jš˜J˜Jšœ œ˜+Jšœ œ˜+Jšœ œ˜J˜Jšœœœ˜-J˜šœœœ˜"Jšœœ˜"Jšœœ˜J˜J˜J˜—J˜Jšœœœ˜,J˜šœœœ˜ Jšœ˜Jšœ˜J˜—J˜J˜Jšžœžœžœžœžœžœžœž˜'Jšœ™Jšžœžœžœžœžœžœžœž˜'J˜šœœ˜*J˜Jšœ˜Jšœœœ˜7J˜"Jšœ œ˜ ˜(Jšœœœ˜DJšœœ˜—Jšœ˜˜JšœHœ œ˜]Jšœ˜—˜JšœPœ˜VJšœ˜—Jšœ4˜4J˜J˜J˜J˜J˜J˜Jšœ5˜5Jšœ/œ˜6J˜—J˜šœœœ˜ J˜—šΟnœœ˜Jšœœ˜!Jš œœœœœ˜9šœ œœ˜CJšœ œ˜)Jšœœ˜JšœO˜VJšœ.œ"˜Všœ>˜>Jšœ œ-œ œ˜Q—Jšœ˜—šœ>˜>Jšœ œœ œ˜,—šœ>˜>Jšœ œœ œ˜,—šœC˜CJšœ œœ œ˜,—J˜J˜—šŸœœœ-˜QJšœœ˜!šœ œœ˜CJšœ œ˜)Jšœœ˜JšœO˜VJšœ.œ"˜Všœ˜šœ4˜4Jšœ œ-œ œ˜Q—Jšœ˜—Jšœ˜—šœ˜Jšœ@œœ œ˜`Jšœ˜—šœ˜Jšœ@œœ œ˜`Jšœ˜—šœ˜JšœEœœ œ˜eJšœ˜—J˜—J˜š Ÿ œœ œœœ˜EJšœ˜Jšœ"˜"šœ˜Jšœ8˜8—J˜J˜—šŸœœ˜4˜'J˜J˜J˜J˜Jšœ˜—Jšœ,ž'˜SJšœ-ž˜BJ˜J˜—šŸœœ%œ˜E˜J˜ J˜J˜>J˜J˜Jšœ˜ Jšœ˜—J˜:J˜J˜—šŸœœœ˜AJ˜J˜J˜J˜—Jšžœžœžœžœžœžœžœž˜'J˜šœœœ˜J˜Jš œ œ œ œœ˜0Jšœœœ˜ Jšœ œ˜,J˜J˜—Jšœœœ˜ J˜Jšœ œ)˜:J˜Jšœœœ˜ šœœœ˜Jšœœ˜Jšœœ˜Jšœœž,˜NJšœ(˜+J˜J˜—Jš œ œœœœœ˜#J˜Jšœ œœ ˜!šœ œœ˜Jšœ œ˜Jšœœœ˜J˜—Jšœ œœœ˜ Jšœ œœ˜$Jšœœœ˜0Jšœœœœ˜0J˜J˜šŸ œ œ˜9Jšœœ˜(šŸ œœ˜Jšœœ!˜6Jš œ œœœœ˜JJšœ œ˜ ˜˜J˜J˜Jšœž4˜GJ˜Jšœ˜ J˜—J˜Jšœœ˜ J˜J˜—Jšœœœ ˜:˜>J˜J˜6J˜Jšœ ž=˜FJ˜Jšœœ˜ Jšœ œ˜Jšœ˜ Jšœ˜—J˜OJ˜:J˜—J˜J˜-J˜SJ˜EJ˜Jšœ ˜ šœ&˜&Jšœœœ$˜K—Jšœœ#˜?J˜—J˜šŸœœ˜9Jšœ ˜ šŸœ œœ˜TJšœ1˜1Jšœ"œ˜'Jšœ"˜(J˜—šœ˜Jšœœœ$˜K—Jš˜Jšœžœœœ˜)š Ÿœœ œœœ˜@Jšœ˜ š œœœœœ˜.Jš œœœœœ˜$—Jšœœ˜Jšœ œœ˜J˜*š˜Jšœœ ˜š œœœ!œ ˜QJ˜Jšœ˜—J˜=Jšœœœœ˜3Jšœ œ*œ˜AJ˜Jšœ˜—J˜—Jšœœœ˜1šœœ˜3Jšœ œ'˜6Jšœ˜Jšœœ0˜Mšœ œ˜Jšœœ2˜MJ˜ —Jšœ˜—Jšœ˜Jšœ6˜6J˜—J˜š Ÿœœœœ œœ˜^Jšœœ˜:šœS˜ZšœU˜[Jšœœ:˜P—Jšœ˜—JšœA˜AJ˜—J˜š Ÿœœ!œœœ˜`Jšœ œ"˜1Jšœœœ˜CJšœ;˜;JšœœK˜VJ˜J˜J˜—Jšžœžœžœžœžœžœžœž˜'J˜šœœœ˜Jšœ!œ˜%Jšœ!˜$J˜J˜—Jšœœœ˜ J˜J˜šŸ œ œ˜9Jšœœ˜(J˜J˜-˜'˜J˜J˜Jšœž4˜GJ˜Jšœ˜ J˜—J˜Jšœœ˜ J˜J˜—˜7J˜J˜FJ˜Jšœ ž=˜FJ˜Jšœœž˜Jšœ œ˜Jšœ˜ Jšœ˜—J˜HJ˜:J˜J˜J˜—šŸ œœœ˜9J˜JšœL˜LJ˜J˜J˜—Jšžœžœžœžœžœžœžœž˜'Jšœ™Jšžœžœžœžœžœžœžœž˜'J˜šŸ œœ$œ˜šœœ˜JšœH˜H—Jšœœ&˜AJšœ/™/šœH˜HJšœM˜P—Jšœœ-˜GJ˜J˜—šŸ œœœ/˜JJšœ2œ˜9Jšœ.œ˜4J˜J˜J˜—šŸ œœœ˜/˜Jš œœœœœœ˜O—Jšœœœœ˜$šœ œ˜JšœMœ˜Všœ5œ˜=J˜&——Jšœ$œ˜*J˜J˜—šœœ˜0Jšœœ˜-JšœDœ˜IJ˜J˜—šŸ œœœœ˜?Jšœœ>˜HJšœ?˜CJ˜J˜J˜—Jšžœžœžœžœžœžœžœž˜'J™Jšžœžœžœžœžœžœžœž˜'J˜šŸ œœOœ˜hšœ%˜+Jšœ"˜"—Jšœ˜!J˜J˜—˜"Jšœœ ˜+J˜Jšœ œ˜Jšœœœ˜&J˜6Jšœ œœ0œ˜IJšœ2˜6J˜J˜—šœ ˜ šœ˜Jšœ=˜=—J˜J˜—šœ"˜"Jšœœ˜;J˜J˜—˜$Jšœ:˜:šœœ˜$J˜Jšœ œ˜Jš œœœ9œœ˜UJšœE˜Ešœ œœœ˜1Jšœ"˜"Jšœ*˜*J˜—Jšœœ˜'J˜—Jšœ:œ˜DJ˜—J˜˜Jšœ œœ˜š Ÿ œœœž œœ˜.JšœF™FJšœœœ˜Jšœœ ˜,J˜?šœœœ˜7˜ J˜0Jšœ.˜4——˜Jš œœœœœ˜D—J˜šŸœœœ˜ Jšœ œ˜JšœT˜TJšœ œœœ ˜BJ˜—šœ˜"˜ Jšœœ˜Jšœœœ˜Jšœ œ˜-J˜Jšœ(˜(J˜—˜ J˜J˜Jšœœœ˜?šœ˜Jšœœ3˜Fšœ3œ˜;˜Jšœ-œ˜C—Jšœ ˜J˜—J˜—Jšœ œ9œœ˜UJ˜J˜'J˜/J˜—˜ J˜šœ˜Jšœœ ˜,—šœ˜Jš œœœœœ2˜HJš œœœœœ œœ ˜@Jšœ œœœžœœœ˜TJšœž˜$š˜˜ J˜3Jšœ ˜J˜——J˜—J˜Jšœ˜J˜—˜Jšœœ˜"Jšœœœ˜Jšœœ&˜=J˜šœ ˜ JšœO˜OJšœ ˜ —J˜—Jšœ˜—J˜—Jšœœœ˜&Jšœœ˜%J˜J˜—šœœ˜'Jšœœ˜:J˜J˜—š Ÿ œœœœ0œ˜fJšœœœœ$˜LJ˜4˜GJšœœ˜˜šœœ˜Jšœ2œœ˜?—Jšœœ˜——Jšœœ ˜J˜—J˜šŸœœœ˜.JšœDœœ˜ZJšœ œ˜š Ÿ œœœœœ˜6šœ˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜Jšœœœ˜*—Jšœœ˜J˜—šœ5˜;Jšœœ/œ˜M—J˜—J˜šŸœœœœ˜.Jš˜Jšœœœ˜šœ"˜"Jš œœ œ œœœ˜;Jšœœ"˜6—J˜'šœœ˜J˜šœ;œ˜CJ˜&Jšœœ˜——Jšœœ˜Jšœ˜J˜J˜J˜—Jšžœžœžœžœžœžœžœž˜'Jšœ ™ Jšžœžœžœžœžœžœžœž˜'˜J˜—JšœDœ˜JJ˜J™J˜Jšœ˜J˜J˜™-J™5Jš œ Οr œ  œ œ 2œ! K™ƒ—J™™+J™sJšœ  Oœ"  œ" )™Ρ—J™™/J™W—J™™.J™F—J™™-J™ŽJšœ  .™:J™—™/J™΄—J™—…—i–χ