<<>> <> <> <> <> <> <> <> <<>> DIRECTORY Basics, BasicTime, Commander, Convert, GlobalRunDefaults, IncrementalLoad, InstallationComforts, IO, LibSearch, List, MesaLoadState, PFS, PFSNames, Process, ProcessProps, RegisterRefLiteral, Rope, SimpleFeedback, SymTab, UXStrings; RunCommandsImpl: CEDAR PROGRAM IMPORTS Basics, BasicTime, Commander, Convert, GlobalRunDefaults, IncrementalLoad, InstallationComforts, IO, LibSearch, List, MesaLoadState, PFS, PFSNames, Process, ProcessProps, RegisterRefLiteral, Rope, SimpleFeedback, SymTab, UXStrings = BEGIN OPEN IL: IncrementalLoad; ROPE: TYPE ~ Rope.ROPE; PATH: TYPE = PFSNames.PATH; RopeList: TYPE ~ LIST OF ROPE; UnixString: TYPE ~ POINTER TO Basics.RawChars; InstallFunc: TYPE ~ PROC; ProcRep: TYPE ~ MACHINE DEPENDENT RECORD [pcStart: IL.CProc, staticLink: CARD32]; SearchResult: TYPE ~ RECORD [torun: PATH, hacks: RopeList]; unixLag: CARD32 = (365+366)*24*60*60; <> <> <> <<>> workingDirectories: SymTab.Ref ~ SymTab.Create[case: TRUE]; runInfoTab: SymTab.Ref <> ~ SymTab.Create[case: TRUE]; RunInfo: TYPE ~ PACKED RECORD [unixName: ROPE, torun: PATH, moduleName: ROPE, hasInstall, hasStart: BOOL]; RunInternal: PROC [cmd: Commander.Handle, name: ROPE, unboundOK: SymTab.Ref, runEvenIfAlreadyRun, runEvenIfUnbound, loadOnly, quote, preferOptimized, printTimings: BOOL, patchByteSize: CARD] RETURNS [error: BOOL ¬ FALSE] ~ TRUSTED { given: ROPE ~ PFS.RopeFromPath[PFS.AbsoluteName[PFS.PathFromRope[name]]]; baseStart: INT ~ given.FindBackward["/"]+1; afterBase: INT ~ given.SkipTo[baseStart, ".!"]; moduleName: ROPE ~ given.Substr[start: baseStart, len: afterBase-baseStart]; hasExt: BOOL ~ given.Find[".", baseStart] >= 0; startFind: CARD ~ BasicTime.GetClockPulses[]; searchResult: SearchResult ~ FindWithHacks[given, quote, preferOptimized, baseStart, afterBase, Append]; findPulses: CARD ~ BasicTime.GetClockPulses[] - startFind; torun: PATH ~ searchResult.torun; unixName: ROPE ~ PFS.PFSNameToUnixName[torun]; install: IL.SymEntry ¬ NIL; start: IL.SymEntry ¬ NIL; thisFile: IL.FileEntry ¬ NIL; thisTime: BasicTime.GMT ¬ BasicTime.nullGMT; thisSize: CARD ¬ 0; hasInstall, hasStart: BOOL; ilPulses, libPulses, commitPulses, installPulses, runPulses: CARD ¬ 0; dont: BOOL ¬ FALSE; wasAborted: BOOL ¬ FALSE; Append: PROC [err: BOOL, fmt: ROPE, v: LIST OF IO.Value] ~ CHECKED { Process.CheckForAbort[]; IF err OR NOT Basics.IsBound[SimpleFeedback.PutFL] THEN { s: IO.STREAM ~ IF err THEN cmd.err ELSE cmd.out; IO.PutFL[s, fmt, v]; IO.PutChar[s, '\n]; error ¬ TRUE; } ELSE { SimpleFeedback.PutFL[routerName: $RunCommands, msgType: oneLiner, msgClass: $Ran, format: fmt, list: v] }; IF err THEN error ¬ TRUE; }; Bitch: PROC [format: ROPE] ~ CHECKED { Append[FALSE, format, LIST[[rope[PFS.RopeFromPath[torun]]], [cardinal[thisSize]], [time[thisTime]]] ] }; BitchAsErr: PROC [format: ROPE] ~ CHECKED { Append[TRUE, format, LIST[[rope[PFS.RopeFromPath[torun]]], [cardinal[thisSize]], [time[thisTime]]] ] }; TestErr: UNSAFE PROC [ile: IL.Error, from: ROPE] RETURNS [BOOL] ~ { IF ile=NIL THEN RETURN [FALSE]; Append[TRUE, "%g => Error[%g, %g, \"%q\"]", LIST[[rope[from]], [integer[ile.fatal]], [integer[ile.code]], [rope[UXStrings.ToRope[ile.msg]]]]]; RETURN [TRUE]}; Seconds: PROC[p: BasicTime.Pulses] RETURNS[REAL] ~ CHECKED INLINE { RETURN[BasicTime.PulsesToSeconds[p]]; }; Inner: PROC = TRUSTED { ENABLE UNWIND => [] ¬ TestErr[IL.AbortIncrementalLoad[], "UNWIND"]; PatchSizeCProc: PROCEDURE [] RETURNS [IL.CProc] ~ TRUSTED { PatchSizeProcAddress: PROCEDURE [] RETURNS [CARD32] ~ TRUSTED MACHINE CODE { "PatchSizeProcAddress" }; cProc: IL.CProc ~ [PatchSizeProcAddress[]]; RETURN [cProc]; }; PatchSizeClientData: PROCEDURE [byteSize: CARD] RETURNS [POINTER] ~ TRUSTED { clientData: REF CARD ~ NEW[CARD ¬ byteSize]; RETURN [LOOPHOLE[clientData]]; }; uname: UnixString ~ UXStrings.Create[unixName]; install ¬ LookupText["_XR_install_", moduleName]; start ¬ LookupText["_XR_run_", moduleName]; ilPulses ¬ BasicTime.GetClockPulses[]; IF TestErr[ ile: IL.IncrementalLoadFile[ fName: uname, patchSizeProc: PatchSizeCProc[], patchSizeClientData: PatchSizeClientData[byteSize: patchByteSize]], from: "Load"] THEN GOTO Abort; thisFile ¬ IL.GetPrevFileEntry[NIL]; thisTime ¬ LOOPHOLE[thisFile.fMTime+unixLag]; thisSize ¬ thisFile.fSize; IF (NOT runEvenIfAlreadyRun) AND (install#NIL AND install.fe#NIL AND install.fe.fMTime=thisFile.fMTime AND install.fe.fSize=thisFile.fSize OR start#NIL AND start.fe#NIL AND start.fe.fMTime=thisFile.fMTime AND start.fe.fSize=thisFile.fSize) THEN { BitchAsErr["%g (s=%g m=%g) already loaded"]; dont ¬ TRUE; GOTO Abort}; BEGIN tmpPulses: CARD; ilPulses ¬ (libPulses ¬ commitPulses ¬ BasicTime.GetClockPulses[]) - ilPulses; WHILE NOT dont AND IL.CommitIncrementalLoad[] # NIL DO missing: LIST OF ROPE ¬ NIL; Consumer: IL.UndefinedSymbolProc ~ TRUSTED { missing ¬ CONS[UXStrings.ToRope[se.name], missing]; RETURN [TRUE]}; consumer: POINTER TO ProcRep ~ LOOPHOLE[Consumer]; IL.EnumerateUndefinedSymbols[consumer.pcStart, consumer]; IF missing=NIL THEN EXIT; WHILE missing#NIL DO missingU: UnixString ~ UXStrings.Create[missing.first]; found: LibSearch.Bool; libfd: LibSearch.FD; liboffset, magic: INT; modulenameU: UnixString; moduleName: ROPE; fileName: ROPE; Append[FALSE, "Searching libraries for undefined UNIX symbol %g.", LIST[[rope[missing.first]]]]; TRUSTED {found ¬ LibSearch.SymFind[missingU, @libfd, @liboffset, @magic, @modulenameU]}; IF found = LibSearch.False THEN { Append[TRUE, "Cannot resolve UNIX-level unbound symbol %g", LIST[[rope[missing.first]]]]; dont ¬ TRUE; } ELSE { moduleName ¬ UXStrings.ToRope[modulenameU]; Append[FALSE, "Loading library module %g.", LIST[[rope[moduleName]]]]; fileName ¬ moduleName.Substr[len: moduleName.SkipTo[skip: "("]]; IF TestErr[ ile: IL.IncrementalLoadFile[ fName: UXStrings.Create[fileName], fOffset: liboffset, patchSizeProc: PatchSizeCProc[], patchSizeClientData: PatchSizeClientData[byteSize: patchByteSize]], from: IO.PutFR1["LibLoad[%g]", [rope[moduleName]] ]] THEN GOTO Abort; }; missing ¬ missing.rest; ENDLOOP; commitPulses ¬ BasicTime.GetClockPulses[]; <> ENDLOOP; libPulses ¬ (tmpPulses ¬ BasicTime.GetClockPulses[]) - libPulses; commitPulses ¬ tmpPulses - commitPulses; END; IF dont THEN { Append[TRUE, "%g (s=%g m=%g) not run becaue of unbound UNIX-level symbols", LIST[[rope[PFS.RopeFromPath[torun]]], [cardinal[thisSize]], [time[thisTime]]]]; GOTO Abort; }; install ¬ LookupText["_XR_install_", moduleName]; IF loadOnly THEN start ¬ NIL ELSE { start ¬ LookupText["_XR_run_", moduleName]; IF start=NIL THEN start ¬ LookupText["_XR_run", NIL]; }; EXITS Abort => { ilPulses ¬ commitPulses ¬ 0; [] ¬ TestErr[IL.AbortIncrementalLoad[], "Abort"]; }; }; <> LibSearch.Crock1[]; IF torun=NIL THEN { Append[TRUE, "Hint \"%q\" and patterns %g don't lead to any existing non-empty file", LIST[[rope[given]], [rope[FmtHacks[searchResult.hacks]]]]]; RETURN[error: TRUE]; }; Process.CheckForAbort[]; IF TestErr[IL.LockIncrementalLoadState[TRUE], "Lock"] THEN RETURN[error: TRUE]; Inner[ ! UNWIND => [] ¬ TestErr[IL.UnlockIncrementalLoadState[], "UNWIND Unlock"]]; [] ¬ TestErr[IL.UnlockIncrementalLoadState[], "Unlock"]; IF error OR dont THEN RETURN; hasInstall ¬ install#NIL AND thisFile.seqNum = install.fe.seqNum; hasStart ¬ start#NIL AND thisFile.seqNum = start.fe.seqNum; IF hasInstall THEN { ENABLE UNWIND => MesaLoadState.AbortInstallation[]; installFn: InstallFunc ~ CProcToCedar[install.value]; problems: LIST OF MesaLoadState.InstallationProblem ¬ NIL; abort: BOOL ¬ FALSE; Report: MesaLoadState.ReportProc ~ CHECKED { WITH problem SELECT FROM ui: MesaLoadState.InstallationProblem.unboundImport => { ifName: ROPE ~ MesaLoadState.InterfaceName[ui.interface]; IF unboundOK.Fetch[ifName].found THEN RETURN; }; re: MesaLoadState.InstallationProblem.reExport => { IF runEvenIfAlreadyRun THEN RETURN; }; tc: MesaLoadState.InstallationProblem.typeClash => { <> abort ¬ TRUE; }; ENDCASE => NULL; problems ¬ CONS[problem, problems]; }; installPulses ¬ BasicTime.GetClockPulses[]; MesaLoadState.BeginInstallation[]; -- will raise RuntimeError.UnboundProcedureFault if new installation support is not present. installFn[ ! RegisterRefLiteral.UnknownType => CHECKED { abort ¬ TRUE; IO.PutRope[cmd.err, "Unable to load "]; IO.PutRope[cmd.err, name]; IO.PutRope[cmd.err, ", probably because of a version mismatch with Rope\n"]; CONTINUE; }]; IF NOT abort THEN MesaLoadState.CheckInstallation[Report]; IF problems#NIL THEN { InstallationComforts.PutProblems[cmd.err, problems]; IO.PutChar[cmd.err, '\n]; }; IF abort THEN { MesaLoadState.AbortInstallation[]; RETURN [error: TRUE] } ELSE { MesaLoadState.CommitInstallation[] }; installPulses ¬ BasicTime.GetClockPulses[] - installPulses; hasInstall ¬ hasInstall }; IF hasStart THEN { runFn: InstallFunc ~ CProcToCedar[start.value]; runPulses ¬ BasicTime.GetClockPulses[]; [] ¬ SymTab.Store[workingDirectories, moduleName, PFS.GetWDir[]]; -- remember working directories of things that get started. runFn[ ! ABORTED => {wasAborted ¬ TRUE; CONTINUE}]; -- catch ABORTED so that if there are messages from loading they'll get printed even if starting gets an error (e.g., an unbound procedure fault). runPulses ¬ BasicTime.GetClockPulses[] - runPulses; hasStart ¬ hasStart; }; [] ¬ SymTab.Store[runInfoTab, unixName, NEW[RunInfo ¬ [unixName: unixName, torun: torun, moduleName: moduleName, hasInstall: hasInstall, hasStart: hasStart]]]; SELECT TRUE FROM hasInstall AND hasStart AND ~loadOnly => Bitch["Ran %g (s=%g m=%g)"]; hasInstall AND ~hasStart AND ~loadOnly => Bitch["Loaded and installed %g (s=%g m=%g) (it has no start proc)"]; hasInstall AND loadOnly => Bitch["Loaded and installed %g (s=%g m=%g)"]; ~hasInstall AND hasStart AND ~loadOnly => Bitch["Loaded and started %g (s=%g m=%g) (it has no install proc)"]; ~hasInstall AND ~hasStart AND ~loadOnly => Bitch["Loaded %g (s=%g m=%g) (it has no install or start proc)"]; ~hasInstall AND loadOnly => Bitch["Loaded %g (s=%g m=%g) (it has no install proc)"]; ENDCASE => ERROR --the above covers all cases--; IF printTimings THEN Append[FALSE, "\t(find=%5.2f il=%5.2f lib=%5.2f c=%5.2f inst=%5.2f run=%5.2f)", LIST[ [real[Seconds[findPulses]]], [real[Seconds[ilPulses]]], [real[Seconds[libPulses]]], [real[Seconds[commitPulses]]], [real[Seconds[installPulses]]], [real[Seconds[runPulses]]] ]]; IF wasAborted THEN ERROR ABORTED; -- propagate abort RETURN; }; globalUndefineds: LIST OF ROPE ¬ NIL; EachUndefinedSymbol: IL.UndefinedSymbolProc ~ TRUSTED { globalUndefineds ¬ CONS[ UXStrings.ToRope[se.name], globalUndefineds ]; RETURN[TRUE] }; LookupText: PROC [prefix, name: ROPE] RETURNS [se: IL.SymEntry] ~ TRUSTED { FOR se ¬ IL.LookupSymEntry[UXStrings.Create[Rope.Concat[prefix, name]], FALSE], IL.GetPrevSymEntry[se, FALSE] UNTIL se=NIL DO masked: CARD32 ~ Basics.BITAND[se.type, IL.SETypeMask]; IF masked = IL.SETypeTEXT THEN RETURN; ENDLOOP; se ¬ se; }; centerPat: ROPE ~ "Foo"; optimizedSearch: RopeList ¬ LIST["sun4/Foo.c2c.o", "sun4/Foo", "Foo.sx.o", "Foo"]; plainSearch: RopeList ¬ LIST["sun4-debug/Foo.c2c.o", "sun4-debug/Foo", "Foo.sx.o", "Foo", "sun4/Foo.c2c.o", "sun4/Foo"]; FindWithHacks: PROC [given: ROPE, quote, preferOptimized: BOOL, baseStart, afterBase: INT, Msg: PROC [err: BOOL, fmt: ROPE, v: LIST OF IO.Value ¬ NIL] ] RETURNS [SearchResult] ~ { all: RopeList ~ IF quote THEN LIST["Foo"] ELSE WITH ProcessProps.GetProp[$RunPatterns] SELECT FROM x: RopeList => x, x: ROPE => LIST[x], ENDCASE => IF preferOptimized THEN optimizedSearch ELSE plainSearch; ctrLen: INT ~ Rope.Length[centerPat]; FOR hackRules: RopeList ¬ all, hackRules.rest WHILE hackRules#NIL DO hack: ROPE ~ hackRules.first; ctrStart: INT ~ hack.Index[s2: centerPat]; hackLen: INT ~ hack.Length[]; IF ctrStart >= hackLen THEN { Msg[FALSE, "Hack \"%q\" doesn't contain \"Foo\" as a substring", LIST[[rope[hack]]]]; LOOP}; {hacked: ROPE ~ given.Replace[start: afterBase, len: 0, with: hack.Substr[start: ctrStart+ctrLen]].Replace[start: baseStart, len: 0, with: hack.Substr[len: ctrStart]]; hackedPath: PATH ¬ PFS.PathFromRope[hacked]; bytes: INT ¬ 0; [fullFName: hackedPath, bytes: bytes] ¬ PFS.FileInfo[hackedPath !PFS.Error => LOOP]; IF bytes>0 THEN RETURN [[hackedPath, all]]; }; ENDLOOP; RETURN [[NIL, all]]; }; FmtHacks: PROC [hacks: RopeList] RETURNS [ROPE] ~ { buf: IO.STREAM ~ IO.ROS[]; buf.PutRope["["]; FOR hacks ¬ hacks, hacks.rest WHILE hacks#NIL DO buf.PutRope[" "]; buf.PutRope[hacks.first]; ENDLOOP; buf.PutRope[" ]"]; RETURN [buf.RopeFromROS[]]; }; RunCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ¬ NIL, msg: ROPE ¬ NIL] --Commander.CommandProc-- = TRUSTED { ENABLE QuotedStringError => {msg ¬ "Mismatched quotes"; GO TO Failure}; dontStartIfUnbound, runAgain, loadOnly, excepting, quote, printTimings: BOOL ¬ FALSE; preferOptimized: BOOL ¬ TRUE; unboundOK: SymTab.Ref ~ SymTab.Create[case: TRUE]; -- never used! something: BOOL ¬ FALSE; patchByteSize: CARD ¬ 0; cmds: IO.STREAM ¬ NIL; defaultSwitches: ROPE ¬ GlobalRunDefaults.GetGlobalRunDefaults[]; WITH ProcessProps.GetProp[$RunDefaultSwitches] SELECT FROM rope: ROPE => IF Rope.Size[rope] > 0 AND Rope.Fetch[rope, 0] = '- THEN defaultSwitches ¬ rope; ENDCASE => NULL; cmds ¬ IO.RIS[Rope.Concat[defaultSwitches, cmd.commandLine]]; FOR arg: ROPE ¬ GetCmdToken[cmds], GetCmdToken[cmds] UNTIL arg = NIL DO error: BOOL ¬ FALSE; IF Rope.Size[arg] > 0 AND Rope.Fetch[arg, 0] = '- THEN { newsense: BOOL ¬ TRUE; FOR j: INT IN [1..Rope.Length[arg]) DO sense: BOOL ~ newsense; newsense ¬ TRUE; SELECT Rope.Fetch[arg, j] FROM 'd => dontStartIfUnbound ¬ sense; 'a => runAgain ¬ sense; 'l => loadOnly ¬ sense; 'p => { FollowingCARD: PROCEDURE [stream: IO.STREAM] RETURNS [CARD] ~ TRUSTED { arg: Rope.ROPE ~ GetCmdToken[stream]; card: CARD ¬ 0; { try: CARD ~ Convert.CardFromRope[r: arg ! Convert.Error => GO TO error]; card ¬ try; EXITS error => cmd.out.PutF1["Invalid Run switch: -p %g\n", [rope[arg]]]; }; RETURN [card]; }; patchByteSize ¬ FollowingCARD[stream: cmds]; }; 'q => quote ¬ sense; 't => printTimings ¬ sense; 'u => excepting ¬ sense; 'x => excepting ¬ NOT sense; 'o => preferOptimized ¬ sense; '~ => newsense ¬ NOT sense; ENDCASE => cmd.out.PutF1["Invalid Run switch: %g\n", [character[Rope.Fetch[arg, j]]]]; ENDLOOP; LOOP; }; IF excepting AND Rope.SkipTo[s: arg, skip: "[]<>/."] < Rope.Length[arg] THEN excepting ¬ FALSE; IF excepting THEN { [] ¬ SymTab.Store[unboundOK, arg, $T]; LOOP }; [error: error] ¬ RunInternal[cmd: cmd, name: arg, unboundOK: unboundOK, runEvenIfAlreadyRun: runAgain, runEvenIfUnbound: NOT dontStartIfUnbound, loadOnly: loadOnly, quote: quote, preferOptimized: preferOptimized, printTimings: printTimings, patchByteSize: patchByteSize]; IF error THEN GOTO Failure; something ¬ TRUE; IF NOT Rope.IsEmpty[msg] THEN { IO.PutRope[cmd.err, msg]; msg ¬ NIL }; ENDLOOP; IF excepting THEN { msg ¬ "Looks like you forgot your -x"; GOTO Failure }; IF NOT something THEN { msg ¬ runUsage; GOTO Failure }; EXITS Failure => result ¬ $Failure; }; RunDefaultsCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ¬ NIL, msg: ROPE ¬ NIL] --Commander.CommandProc-- = { cmds: IO.STREAM ~ IO.RIS[cmd.commandLine]; switches: ROPE ~ GetCmdToken[cmds]; IF switches # NIL AND (Rope.Size[switches] = 0 OR Rope.Fetch[switches, 0] = '-) THEN { [] ¬ List.PutAssoc[key: $RunDefaultSwitches, val: switches, aList: ProcessProps.GetPropList[]]; }; msg ¬ "no local default switches are set for Run"; WITH ProcessProps.GetProp[$RunDefaultSwitches] SELECT FROM rope: ROPE => IF Rope.Size[rope] > 0 AND Rope.Fetch[rope, 0] = '- THEN msg ¬ Rope.Concat["Local default switches for Run are ", rope]; ENDCASE => NULL; }; UXNameCommand: PROC [cmd: Commander.Handle] RETURNS [result: REF ¬ NIL, msg: ROPE ¬ NIL] --Commander.CommandProc-- = { ENABLE PFS.Error => {msg ¬ error.explanation; GOTO Failure}; cmds: IO.STREAM ~ IO.RIS[cmd.commandLine]; path: PATH ~ PFS.FileInfo[PFS.PathFromRope[GetCmdToken[cmds]]].fullFName; IO.PutRope[cmd.out, PFS.PFSNameToUnixName[path]]; IO.PutChar[cmd.out, '\n]; EXITS Failure => result ¬ $Failure; }; LoadedVersionCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ¬ NIL, msg: ROPE ¬ NIL] --Commander.CommandProc-- = TRUSTED { ENABLE QuotedStringError => {msg ¬ "Mismatched quotes"; GO TO Failure}; cmds: IO.STREAM ~ IO.RIS[cmd.commandLine]; FOR target: ROPE ¬ GetCmdToken[cmds], GetCmdToken[cmds] UNTIL target = NIL DO pattern: BOOL ~ target.Find["*"] >= 0; fe: IL.FileEntry ¬ NIL; sep: ROPE ¬ NIL; cmd.out.PutF1["Versions of %g:\n", [rope[target]]]; DO fe ¬ IL.GetPrevFileEntry[fe]; IF fe=NIL THEN EXIT; {thisName: ROPE ~ UXStrings.ToRope[fe.fName]; IF (IF pattern THEN Rope.Match[target, thisName, FALSE] ELSE Rope.Equal[target, thisName, FALSE]) THEN { cmd.out.PutFL["%g\n%g (s=%g m=%g)", LIST[[rope[sep]], [rope[thisName]], [cardinal[fe.fSize]], [time[LOOPHOLE[fe.fMTime + unixLag]]]]]; sep ¬ ","}; }ENDLOOP; cmd.out.PutRope[".\n"]; ENDLOOP; RETURN; EXITS Failure => result ¬ $Failure; }; PathFromUnixName: PROC [name: ROPE] RETURNS [path: PATH] = { EachName: PROC [name: PATH] RETURNS [continue: BOOL ¬ FALSE] = { path ¬ name }; IF Rope.Match["*.~*~", name] THEN { dot: INT ~ Rope.FindBackward[name, ".~"]; version: ROPE ~ Rope.Substr[name, dot+2, Rope.Size[name]-1-(dot+2)]; name ¬ Rope.Cat["/vux", Rope.Substr[name, 0, dot], "!", version]; } ELSE { name ¬ Rope.Concat["/ux", name]; }; WITH SymTab.Fetch[runInfoTab, name].val SELECT FROM r: REF RunInfo => { RETURN [r.torun] }; ENDCASE; path ¬ PFS.PathFromRope[name]; PFS.EnumerateForNames[pattern: path, proc: EachName]; }; CasedBase: PROC [name: ROPE] RETURNS [ROPE] = { path: PATH ~ PathFromUnixName[name]; short: PFSNames.Component ~ PFSNames.ShortName[path]; dot: INT ~ Rope.Index[short.name.base, short.name.start, "."]; RETURN [Rope.Substr[short.name.base, short.name.start, MIN[short.name.len, dot-short.name.start]]] }; GetModuleName: PROC [unixName: ROPE] RETURNS [ROPE] ~ { WITH SymTab.Fetch[runInfoTab, unixName].val SELECT FROM r: REF RunInfo => { <> RETURN [r.moduleName]; }; ENDCASE => { <> IF Rope.Match["*.o", unixName] OR Rope.Match["*.o.~*~", unixName] THEN RETURN [CasedBase[unixName]] ELSE RETURN [NIL] }; }; loadedFilesUsage: ROPE ~ "Usage: LoadedFiles [-pcr | -command | -names | -ccode | -libs] [-first ] [-after ] [-before ] [-last ]"; LoadedFilesCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ¬ NIL, msg: ROPE ¬ NIL] --Commander.CommandProc-- = { ENABLE { QuotedStringError => {msg ¬ "Mismatched quotes"; GO TO Failure}; PFS.Error => IF error.group = user THEN {msg ¬ error.explanation; GO TO Failure}; }; cmds: IO.STREAM ~ IO.RIS[cmd.commandLine]; GetFilePattern: PROC RETURNS [ROPE] ~ { RETURN [Rope.Cat["*/", GetCmdToken[cmds], "*"]] }; exceptions: LIST OF ROPE ¬ NIL; Exception: PROC [rope: ROPE] RETURNS [BOOL] ~ { FOR tail: LIST OF ROPE ¬ exceptions, tail.rest UNTIL tail = NIL DO IF Rope.Match[tail.first, rope, FALSE] THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE]; }; format: { pcr, command, names, ccode, libs } ¬ command; first: ROPE ¬ NIL; after: ROPE ¬ NIL; before: ROPE ¬ NIL; last: ROPE ¬ NIL; list: LIST OF ROPE ¬ NIL; something: BOOL ¬ FALSE; libTab: SymTab.Ref ¬ NIL; FOR target: ROPE ¬ GetCmdToken[cmds], GetCmdToken[cmds] UNTIL target = NIL DO Match: PROC [x: ROPE] RETURNS [BOOL] = { RETURN [Rope.Match[x, target, FALSE]] }; SELECT TRUE FROM Match["-pcr"] => format ¬ pcr; Match["-command"] => format ¬ command; Match["-names"] => format ¬ names; Match["-ccode"] => format ¬ ccode; Match["-libs"] => format ¬ libs; Match["-first"] => first ¬ GetFilePattern[]; Match["-after"] => after ¬ GetFilePattern[]; Match["-before"] => before ¬ GetFilePattern[]; Match["-last"] => last ¬ GetFilePattern[]; Match["-except"] => exceptions ¬ CONS[GetFilePattern[], exceptions]; ENDCASE => {msg ¬ loadedFilesUsage; GO TO Failure}; something ¬ TRUE; ENDLOOP; IF NOT something THEN {msg ¬ loadedFilesUsage; GO TO Failure}; IF first = NIL AND after = NIL THEN first ¬ "*"; IF before = NIL AND last = NIL THEN last ¬ " "; TRUSTED { FOR fe: IL.FileEntry ¬ IL.GetPrevFileEntry[NIL], IL.GetPrevFileEntry[fe] UNTIL fe = NIL DO rope: ROPE ~ UXStrings.ToRope[fe.fName]; IF Rope.Size[rope] # 0 THEN list ¬ CONS[rope, list]; ENDLOOP; }; UNTIL list = NIL OR (first # NIL AND Rope.Match[first, list.first, FALSE]) DO this: ROPE ¬ list.first; list ¬ list.rest; IF after # NIL AND Rope.Match[after, this, FALSE] THEN EXIT; ENDLOOP; IF NOT (before = NIL AND last = NIL) THEN { FOR tail: LIST OF ROPE ¬ list, tail.rest UNTIL tail = NIL DO SELECT TRUE FROM (last # NIL AND Rope.Match[last, tail.first, FALSE]) => {tail.rest ¬ NIL}; (tail.rest#NIL AND before#NIL AND Rope.Match[before, tail.rest.first, FALSE]) => {tail.rest ¬ NIL}; ENDCASE => NULL; ENDLOOP; }; FOR tail: LIST OF ROPE ¬ list, tail.rest UNTIL tail = NIL DO IF NOT Exception[tail.first] THEN SELECT format FROM pcr => { moduleName: ROPE ~ GetModuleName[tail.first]; SELECT TRUE FROM (moduleName # NIL) => { IO.PutRope[cmd.out, "LoadAndRun "]; IO.PutRope[cmd.out, tail.first]; IO.PutRope[cmd.out, " "]; IO.PutRope[cmd.out, moduleName]; IO.PutRope[cmd.out, "\l"]; }; Rope.Match["*.a*", tail.first, TRUE] => {}; ENDCASE => { IO.PutRope[cmd.out, "UnixLoad "]; IO.PutRope[cmd.out, tail.first]; IO.PutRope[cmd.out, "\l"]; }; }; command => { IO.PutRope[cmd.out, "Run -q "]; IO.PutRope[cmd.out, PFS.RopeFromPath[PathFromUnixName[tail.first]]]; IO.PutRope[cmd.out, "\n"]; }; names => { SELECT TRUE FROM Rope.Match["*.a*", tail.first, TRUE] => {}; ENDCASE => { IO.PutRope[cmd.out, tail.first]; IO.PutRope[cmd.out, " "]; }; }; libs => { IF Rope.Match["*.a*", tail.first, TRUE] THEN { IF libTab = NIL THEN libTab ¬ SymTab.Create[]; IF SymTab.Insert[libTab, tail.first, tail.first] THEN { IO.PutRope[cmd.out, tail.first]; IO.PutRope[cmd.out, " "]; }; }; }; ccode => { moduleName: ROPE ~ GetModuleName[tail.first]; IF moduleName # NIL THEN { val: REF ~ SymTab.Fetch[workingDirectories, moduleName].val; IF LookupText["_XR_install_", moduleName] # NIL THEN { IO.PutF1[cmd.out, " XR_install_%g();\l", [rope[moduleName]]]; IO.PutRope[cmd.out, " XR_CommitInstallation();\l"]; }; IF LookupText["_XR_run_", moduleName] # NIL THEN { WITH val SELECT FROM path: PATH => { IO.PutF[cmd.out, " {extern void XR_run_%g(); XR_CallWithPFSWorkingDirectory(XR_run_%g, \"%g\");}\l", [rope[moduleName]], [rope[moduleName]], [rope[PFS.RopeFromPath[path]]]]; }; ENDCASE => { IO.PutF1[cmd.out, " XR_run_%g();\l", [rope[moduleName]]]; }; }; }; }; ENDCASE => ERROR; ENDLOOP; EXITS Failure => result ¬ $Failure; }; CProcToCedar: PROC [pcStart, staticLink: CARD32 ¬ 0] RETURNS [PROC] ~ { rep: REF ProcRep ~ NEW [ProcRep ¬ [[pcStart], staticLink]]; RETURN [LOOPHOLE[rep]]}; <> QuotedStringError: ERROR = CODE; CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = { IF char = '" THEN RETURN [break]; IF char = ' OR char = '\t OR char = ', OR char = '\l OR char = '\r THEN RETURN [sepr]; RETURN [other]; }; GetCmdToken: PROC [stream: IO.STREAM] RETURNS [token: ROPE ¬ NIL] = { token ¬ IO.GetTokenRope[stream, CmdTokenBreak ! IO.EndOfStream => CONTINUE].token; IF Rope.Equal[token, "\""] THEN { ref: REF; IO.Backup[self: stream, char: '"]; ref ¬ IO.GetRefAny[stream ! IO.Error, IO.EndOfStream => ERROR QuotedStringError]; WITH ref SELECT FROM rope: ROPE => token ¬ rope; ENDCASE => ERROR QuotedStringError; }; }; <> runUsage: ROPE ~ "Run (-d | -a | -l | -p number | -q | -s | -t | -u InterfaceName* -x | ModuleOrFileName)* -d don't start if unbound -a run again even if already run -l load only -o prefer optimized code -p number allocate that number of bytes for patch space -q quote (don't use file searching hacks) -t print load timing info -u start unbound exception list -x end unbound exception list"; Start: PROC ~ { Commander.Register["Run", RunCmd, runUsage]; Commander.Register["RunDefaultSwitches", RunDefaultsCmd, "Set local default switches for the Run command"]; Commander.Register["LoadedVersionOf", LoadedVersionCmd, "LoadedVersionOf FileNamePattern*"]; Commander.Register["LoadedFiles", LoadedFilesCmd, Rope.Concat["Format load state for restart\n", loadedFilesUsage]]; Commander.Register["UXName", UXNameCommand, "For debug of PFSNameToUnixName"]; }; CallWithPFSWorkingDirectory: UNSAFE PROC [cproc: CARD32, wd: UnixString] ~ UNCHECKED { proc: SAFE PROC ~ CProcToCedar[cproc]; path: PATH ~ PFS.PathFromRope[UXStrings.ToRope[wd]]; PFS.DoInWDir[path, proc]; }; ExternalNames: PROC = TRUSTED MACHINE CODE { "^ExternalNames\n"; "CallWithPFSWorkingDirectory XR_CallWithPFSWorkingDirectory\n"; }; <> Start[]; ExternalNames[]; END.