<> <> <> <> <> <> DIRECTORY BasicTime USING [FromPupTime, GetClockPulses, GMT, Now, Period, Pulses, PulsesToMicroseconds, PulsesToSeconds], Booting USING [Boot, Checkpoint], Commander USING [CommandObject, CommandProc, CommandProcHandle, CommandProcObject, Enumerate, Handle, Lookup, Register], CommandExtras USING [MakeUninterpreted], CommandTool USING [AddProcToList, AddSearchRule, ArgumentVector, DoCommand, Failed, LookupCommand, LookupWithSearchRules, Parse, ParseToList, RemoveProcFromList, StarExpansion], Convert USING [AppendChar, Error, IntFromRope, RopeFromTime], EditedStream USING [Rubout], FileNames USING [ConvertToSlashFormat, CurrentWorkingDirectory, ResolveRelativePath, StripVersionNumber], FS USING [EnumerateForNames, Error, NameProc, StreamOpen], IO USING [Close, EndOf, EndOfStream, Error, GetBlock, GetLine, PutBlock, PutChar, PutF, PutFR, PutRope, STREAM], List USING [AList, Assoc, CompareProc, Memb, PutAssoc, Sort], Process USING [Abort, GetCurrent, Pause, SecondsToTicks], ProcessExtras USING [CheckForAbort], Real USING [Fix, RealException], Rope USING [Cat, Compare, Concat, Equal, Fetch, Find, IsEmpty, Length, Match, ROPE, Substr], RopeList USING [DReverse], SafeStorage USING [NWordsAllocated], SystemVersion USING [bootFileDate, release], TiogaMenuOps USING [Open], UserCredentials USING [Get], ViewerClasses USING [Viewer], VMStatistics USING [pageFaults]; InitialCommandsImpl: CEDAR MONITOR IMPORTS BasicTime, Booting, Commander, CommandExtras, CommandTool, Convert, EditedStream, FileNames, FS, IO, List, Process, ProcessExtras, Real, Rope, RopeList, SafeStorage, SystemVersion, TiogaMenuOps, UserCredentials, VMStatistics = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Date: Commander.CommandProc = { RETURN[NIL, Convert.RopeFromTime[from: BasicTime.Now[], includeDayOfWeek: TRUE]]; }; User: Commander.CommandProc = { user: ROPE _ UserCredentials.Get[].name; IF user.Length[] = 0 THEN user _ "??"; RETURN[NIL, user]; }; Version: Commander.CommandProc = TRUSTED { PutVersion[cmd.out]; }; PutVersion: PROC [out: STREAM] = { IO.PutF[out, "Cedar %g.%g", [integer[SystemVersion.release.major]], [integer[SystemVersion.release.minor]]]; IF SystemVersion.release.patch # 0 THEN IO.PutF[out, ".%g", [integer[SystemVersion.release.patch]]]; IO.PutF[out, " of %t\n", [time[BasicTime.FromPupTime[SystemVersion.bootFileDate]]]]; }; Fail: Commander.CommandProc = { RETURN[$Failure, "This Command Always Fails"]; }; ECell: TYPE = RECORD [name, doc: ROPE]; EnumerateCommands: Commander.CommandProc = { <<[cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL]>> el: LIST OF REF ANY; eCell: REF ECell; matchList: LIST OF ROPE _ NIL; lookupCmd: Commander.Handle _ NEW[Commander.CommandObject]; i: NAT _ 1; flag: BOOL _ FALSE; full: BOOL _ cmd.procData.clientData = $Full; EProc: PROC [key: ROPE, procData: Commander.CommandProcHandle] RETURNS [stop: BOOL] = { ProcessExtras.CheckForAbort[]; IF procData # NIL THEN { <> FOR list: LIST OF ROPE _ matchList, list.rest WHILE list # NIL DO IF list.first.Find["*"] = -1 THEN LOOP; -- handled elsewhere flag _ TRUE; IF list.first.Match[key, FALSE] THEN { <> el _ CONS[NEW[ECell _ [name: key, doc: procData.doc]], el]; ProcessExtras.CheckForAbort[]; EXIT; }; ENDLOOP; }; RETURN[FALSE]; }; FSProc: FS.NameProc = { <> commandName: ROPE _ Rope.Substr[base: FileNames.ConvertToSlashFormat[fullFName], start: 0, len: Rope.Find[s1: fullFName, pos1: 0, s2: ".load", case: FALSE]]; <> ProcessExtras.CheckForAbort[]; FOR list: LIST OF REF ANY _ el, list.rest WHILE list # NIL DO IF Rope.Equal[commandName, NARROW[list.first, REF ECell].name, FALSE] THEN RETURN[TRUE]; ENDLOOP; <> el _ CONS[NEW[ECell _ [name: commandName, doc: "not yet loaded"]], el]; RETURN[TRUE]; }; MyCompare: List.CompareProc = { a, b: REF ECell; a _ NARROW[ref1]; b _ NARROW[ref2]; RETURN[Rope.Compare[a.name, b.name, FALSE]]; }; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; <> DO match: ROPE _ NIL; ProcessExtras.CheckForAbort[]; IF i = argv.argc THEN EXIT; match _ argv[i]; i _ i + 1; IF match.IsEmpty[] OR match.Equal["\n"] THEN EXIT; <> IF match.Equal["*"] THEN { --exactly * matchList _ LIST["*"]; EXIT; } ELSE { match _ FileNames.ResolveRelativePath[match]; IF match.Fetch[0] # '/ AND match.Fetch[0] # '* AND match.Find["*"] # -1 THEN match _ Rope.Concat["*", match]; IF match.Fetch[match.Length[] - 1] = '/ THEN match _ Rope.Concat[match, "*"]; }; matchList _ CONS[match, matchList]; ENDLOOP; IF matchList = NIL THEN { <> cmd.out.PutRope["Usage: "]; cmd.out.PutRope[cmd.command]; cmd.out.PutRope[" list-of-patterns ...\n"]; RETURN; }; <> lookupCmd.err _ cmd.out; FOR list: LIST OF ROPE _ matchList, list.rest WHILE list # NIL DO IF list.first.Find["*"] = -1 THEN { <> ProcessExtras.CheckForAbort[]; lookupCmd.command _ list.first; lookupCmd.commandLine _ NIL; lookupCmd.procData _ NIL; lookupCmd.propertyList _ cmd.propertyList; CommandTool.LookupCommand[lookupCmd]; IF lookupCmd.procData # NIL THEN { IF lookupCmd.commandLine # NIL THEN cmd.out.PutRope["(Generic command) "]; cmd.out.PutF["%-20g %g %g\n", [rope[lookupCmd.command]], [rope[lookupCmd.commandLine]], [rope[lookupCmd.procData.doc]]]; } ELSE cmd.out.PutF["%-20g Not found\n", [rope[lookupCmd.command]]]; ProcessExtras.CheckForAbort[]; }; ENDLOOP; [] _ Commander.Enumerate[EProc]; IF full THEN <> FOR list: LIST OF ROPE _ matchList, list.rest WHILE list # NIL DO IF list.first.Find["*"] # -1 THEN { withStarExt: ROPE _ Rope.Concat[list.first, "*.load"]; FS.EnumerateForNames[pattern: withStarExt, proc: FSProc, wDir: NIL]; IF list.first.Fetch[0] # '/ AND list.first.Fetch[0] # '[ THEN { rules: LIST OF REF ANY _ NARROW[List.Assoc[key: $SearchRules, aList: cmd.propertyList]]; WHILE rules # NIL DO ProcessExtras.CheckForAbort[]; FS.EnumerateForNames[ pattern: withStarExt, proc: FSProc, wDir: NARROW[rules.first, ROPE]]; rules _ rules.rest; ENDLOOP; }; }; ENDLOOP; IF el = NIL AND flag = TRUE THEN { <> msg _ "No matching registered commands."; RETURN; }; <> IF el # NIL THEN { cmd.out.PutRope["Matching registered commands:\n"]; el _ List.Sort[list: el, compareProc: MyCompare]; WHILE el # NIL DO eCell _ NARROW[el.first]; cmd.out.PutF["%-20g %g\n", [rope[eCell.name]], [rope[eCell.doc]]]; el _ el.rest; ProcessExtras.CheckForAbort[]; ENDLOOP; }; EXITS oops => result _ $Failure; }; CopyCommand: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ ExpandAndParse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc # 4 OR NOT Rope.Equal[argv[2], "_"] THEN { msg _ "Usage: CopyCommand newname _ oldname"; GO TO oops; }; { cth: Commander.Handle _ NEW[Commander.CommandObject _ []]; lresult: REF ANY; lmsg: ROPE; newName: ROPE; cth.err _ cmd.out; cth.command _ argv[3]; -- oldname cth.propertyList _ cmd.propertyList; -- so the search rules are accessible [result: lresult, msg: lmsg] _ CommandTool.LookupWithSearchRules[cth]; IF lresult = $Failure OR lmsg # NIL THEN {msg _ lmsg; GO TO oops}; IF cth.commandLine # NIL THEN { msg _ Rope.Concat[argv[2], " uses a generic command, can't copy or rename it"]; GO TO oops}; IF cth.procData = NIL OR cth.procData.proc = NIL THEN { msg _ Rope.Concat["CopyCommand: Can't find ", argv[3]]; GO TO oops}; newName _ FileNames.ResolveRelativePath[argv[1]]; IF newName.Fetch[0] # '/ AND newName.Fetch[0] # '[ THEN { cwd: ROPE _ FileNames.CurrentWorkingDirectory[]; IF NOT cwd.Equal["///"] THEN newName _ Rope.Concat[cwd, newName]; }; IF Commander.Lookup[newName] # NIL THEN { msg _ Rope.Cat["CopyCommand: ", newName, " already exists"]; GO TO oops}; Commander.Register[ key: newName, proc: cth.procData.proc, doc: cth.procData.doc, clientData: cth.procData.clientData]; cmd.out.PutF["CopyCommand %g _ %g\n", [rope[newName]], [rope[cth.command]]]; }; EXITS oops => result _ $Failure; }; Unregister: Commander.CommandProc = { procData: Commander.CommandProcHandle; argv: CommandTool.ArgumentVector _ ExpandAndParse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc = 2 THEN { procData _ Commander.Lookup[argv[1]]; IF procData # NIL AND procData.proc # NIL THEN Commander.Register[key: argv[1], proc: NIL, doc: NIL] ELSE cmd.out.PutF["Unregister: %g not found\n", [rope[argv[1]]]]; } ELSE cmd.out.PutRope["Usage: Unregister commandname\n"]; EXITS oops => result _ $Failure; }; Open: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc < 2 THEN {OpenViewer[NIL, cmd.out]; RETURN}; FOR i: NAT IN [1..argv.argc) DO list: LIST OF ROPE _ ExpandStar[argv[i]]; WHILE list # NIL DO name: ROPE _ FileNames.ResolveRelativePath[list.first]; OpenViewer[name, cmd.out]; list _ list.rest; ENDLOOP; ENDLOOP; EXITS oops => result _ $Failure; }; ExpandStar: PROC [token: ROPE] RETURNS [LIST OF ROPE] = { IF Rope.Find[token, "*"] # -1 THEN { stripVersion: BOOL; listOfTokens: LIST OF ROPE _ NIL; ConsProc: FS.NameProc = { fullFName _ FileNames.ConvertToSlashFormat[fullFName]; IF stripVersion THEN fullFName _ FileNames.StripVersionNumber[fullFName]; listOfTokens _ CONS[fullFName, listOfTokens]; -- on front of list RETURN[TRUE]; }; IF token.Find["!"] = -1 THEN token _ Rope.Concat[token, "!H"]; stripVersion _ token.Find["!H", 0, FALSE] # -1; FS.EnumerateForNames[pattern: FileNames.ResolveRelativePath[token], proc: ConsProc]; RETURN[RopeList.DReverse[listOfTokens]]; } ELSE RETURN[LIST[token]]; }; New: Commander.CommandProc = { OpenViewer[NIL, cmd.out]; }; Comment: Commander.CommandProc = { }; OpenViewer: PROC [name: ROPE, out: STREAM] = { viewer: ViewerClasses.Viewer; IF Rope.IsEmpty[name] THEN name _ FileNames.CurrentWorkingDirectory[]; viewer _ TiogaMenuOps.Open[name]; IF viewer = NIL THEN out.PutF["\tViewer file not found: %g\n", [rope[name]]] ELSE out.PutF["\tCreated Viewer: %g\n", [rope[viewer.name]]]; }; statBeforeRef: Commander.CommandProcHandle _ NEW[Commander.CommandProcObject _ [StatBefore]]; statAfterRef: Commander.CommandProcHandle _ NEW[Commander.CommandProcObject _ [StatAfter]]; StatDataObject: TYPE = RECORD [ cmd: Commander.Handle _ NIL, startTime: BasicTime.GMT, startPulses: BasicTime.Pulses, startFaults: INT, startWords: INT ]; MaxStats: NAT = 10; StatArray: TYPE = RECORD [ a: SEQUENCE length: [0..MaxStats+1) OF StatDataObject ]; stats: REF StatArray _ NEW[StatArray[MaxStats]]; StatBefore: ENTRY Commander.CommandProc = { ENABLE UNWIND => NULL; FOR i: NAT IN [0..MaxStats) DO IF stats.a[i].cmd = NIL THEN { stats.a[i] _ [ cmd: cmd, startTime: BasicTime.Now[], startPulses: BasicTime.GetClockPulses[], startFaults: VMStatistics.pageFaults, startWords: SafeStorage.NWordsAllocated[] ]; EXIT; }; ENDLOOP; result _ $Preserve; }; StatAfter: ENTRY Commander.CommandProc = { ENABLE UNWIND => NULL; pulses: BasicTime.Pulses = BasicTime.GetClockPulses[]; now: BasicTime.GMT = BasicTime.Now[]; wordsNow: INT = SafeStorage.NWordsAllocated[]; faultsNow: INT = VMStatistics.pageFaults; FOR i: NAT IN [0..MaxStats) DO statObj: StatDataObject = stats.a[i]; IF statObj.cmd = cmd THEN { seconds: INT _ BasicTime.Period[statObj.startTime, now]; nw: INT = wordsNow - statObj.startWords; nf: INT = faultsNow - statObj.startFaults; stats.a[i].cmd _ NIL; cmd.out.PutF[" {"]; SELECT seconds FROM < 0 => cmd.out.PutRope["?? seconds"]; >= 60 => { <> cmd.out.PutF["%r seconds", [integer[seconds]]]; }; ENDCASE => { <> tt: REAL _ BasicTime.PulsesToSeconds[pulses - statObj.startPulses]; fraction: INT _ 0; seconds _ Real.Fix[tt ! Real.RealException => { seconds _ LAST[INT]; CONTINUE; }]; fraction _ Real.Fix[(tt - seconds) * 100.0 ! Real.RealException => { fraction _ 0; CONTINUE; }]; cmd.out.PutF["%d.%02d seconds", [integer[seconds]], [integer[fraction]]] }; IF nw > 0 AND nw < 10000000 THEN cmd.out.PutF[", %d words", [integer[nw]]]; IF nf > 0 AND nf < 10000000 THEN cmd.out.PutF[", %d page faults", [integer[nf]]]; cmd.out.PutRope["}\n"]; EXIT; }; ENDLOOP; <> result _ $Preserve; }; Statistics: Commander.CommandProc = { rb: REF ANY _ List.Assoc[key: $Before, aList: cmd.propertyList]; rbl: LIST OF REF ANY; exists: BOOL; IF rb # NIL AND ISTYPE[rb, LIST OF REF ANY] THEN rbl _ NARROW[rb]; exists _ rbl # NIL AND List.Memb[ref: statBeforeRef, list: rbl]; IF exists THEN { cmd.propertyList _ CommandTool.RemoveProcFromList[aList: cmd.propertyList, listKey: $Before, proc: statBeforeRef]; cmd.propertyList _ CommandTool.RemoveProcFromList[aList: cmd.propertyList, listKey: $After, proc: statAfterRef]; } ELSE { cmd.propertyList _ CommandTool.AddProcToList[aList: cmd.propertyList, listKey: $Before, proc: statBeforeRef]; cmd.propertyList _ CommandTool.AddProcToList[aList: cmd.propertyList, listKey: $After, proc: statAfterRef]; }; }; Echo: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ ExpandAndParse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; FOR i: NAT IN [1..argv.argc) DO cmd.out.PutRope[argv[i]]; cmd.out.PutChar[' ]; ProcessExtras.CheckForAbort[]; ENDLOOP; cmd.out.PutChar['\n]; EXITS oops => result _ $Failure; }; PrintSearchRules: Commander.CommandProc = { rules: LIST OF REF ANY _ NARROW[List.Assoc[key: $SearchRules, aList: cmd.propertyList]]; cmd.out.PutRope["( "]; IF rules = NIL THEN cmd.out.PutChar[' ]; WHILE rules # NIL DO cmd.out.PutRope[NARROW[rules.first, ROPE]]; rules _ rules.rest; cmd.out.PutChar[' ]; ProcessExtras.CheckForAbort[]; ENDLOOP; cmd.out.PutRope[")\n"]; }; SetSearchRules: Commander.CommandProc = { args: LIST OF ROPE; dir: ROPE; first: CHAR; CommandTool.StarExpansion[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; args _ CommandTool.ParseToList[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}].list; IF cmd.procData.clientData = $SetSearchRules THEN cmd.propertyList _ List.PutAssoc[key: $SearchRules, val: NIL, aList: cmd.propertyList]; WHILE args # NIL DO dir _ args.first; dir _ FileNames.ResolveRelativePath[dir]; IF dir.Length[] < 3 THEN { msg _ Rope.Concat["Directory name too short: ", dir]; GO TO oops}; first _ dir.Fetch[0]; IF first # '[ AND first # '/ THEN { msg _ Rope.Concat["Bad directory name: ", dir]; GO TO oops}; CommandTool.AddSearchRule[cmd: cmd, dir: dir, append: TRUE]; args _ args.rest; ProcessExtras.CheckForAbort[]; ENDLOOP; EXITS oops => result _ $Failure; }; Sleep: Commander.CommandProc = { seconds: INT; secondsCard: CARDINAL; argv: CommandTool.ArgumentVector _ ExpandAndParse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc # 2 THEN {msg _ "Usage: Sleep seconds"; GO TO oops}; seconds _ Convert.IntFromRope[argv[1] ! Convert.Error => {msg _ "Bad arg"; GO TO oops}]; IF seconds NOT IN [0..LAST[CARDINAL]] THEN {msg _ "Bad arg"; GO TO oops}; secondsCard _ seconds; Process.Pause[Process.SecondsToTicks[seconds]]; EXITS oops => result _ $Failure; }; Indent: Commander.CommandProc = { depth: INT; depthNAT: NAT; spaces: REF TEXT; line: REF TEXT _ NEW[TEXT[200]]; argv: CommandTool.ArgumentVector _ ExpandAndParse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc > 2 THEN {msg _ "Usage: Indent depth"; GO TO oops}; IF argv.argc < 2 THEN { depth _ 8; depthNAT _ 8; } ELSE { depth _ Convert.IntFromRope[argv[1] ! Convert.Error => {msg _ "Bad arg"; GO TO oops}]; IF depth NOT IN [0..80] THEN {msg _ "depth should be in [0..80]"; GO TO oops}; depthNAT _ depth; }; spaces _ NEW[TEXT[depthNAT]]; FOR i: NAT IN [0..depthNAT) DO spaces[i] _ ' ; ENDLOOP; spaces.length _ depthNAT; DO IF cmd.in.EndOf[ ! IO.Error => EXIT] THEN EXIT; line _ cmd.in.GetLine[buffer: line ! IO.EndOfStream => GOTO Finished; IO.Error => EXIT; EditedStream.Rubout => GOTO Finished; ]; cmd.out.PutBlock[block: spaces ! IO.Error => EXIT]; cmd.out.PutBlock[block: line ! IO.Error => EXIT]; cmd.out.PutChar['\n ! IO.Error => EXIT]; ENDLOOP; EXITS Finished => NULL; oops => result _ $Failure; }; Tee: Commander.CommandProc = { fileStream: STREAM _ NIL; block: REF TEXT _ NEW[TEXT[512]]; { ENABLE UNWIND => IF fileStream # NIL THEN fileStream.Close[]; argv: CommandTool.ArgumentVector _ ExpandAndParse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc > 2 THEN {msg _ "Usage: Tee filename"; GO TO oops}; IF argv.argc = 2 THEN fileStream _ FS.StreamOpen[fileName: argv[1], accessOptions: $create ! FS.Error => IF error.group # $bug THEN {msg _ error.explanation; GO TO oops}]; DO count: NAT; block.length _ 0; IF cmd.in.EndOf[] THEN EXIT; count _ cmd.in.GetBlock[block: block ! IO.EndOfStream => EXIT; IO.Error => EXIT; EditedStream.Rubout => EXIT; ]; IF count = 0 THEN EXIT; IF fileStream # NIL THEN fileStream.PutBlock[block: block ! IO.Error => EXIT]; cmd.out.PutBlock[block: block ! IO.Error => EXIT]; ProcessExtras.CheckForAbort[]; ENDLOOP; fileStream.Close[ ! IO.Error => CONTINUE]; }; EXITS oops => RETURN[$Failure, msg]; }; Abort: Commander.CommandProc = TRUSTED { Process.Abort[LOOPHOLE[Process.GetCurrent[], UNSPECIFIED]]; }; Shift: Commander.CommandProc = { result _ CommandTool.DoCommand[commandLine: cmd.commandLine, parent: cmd]; }; ShiftInterp: Commander.CommandProc = { result _ CommandTool.DoCommand[commandLine: cmd.commandLine, parent: cmd]; }; Time: Commander.CommandProc = { start: BasicTime.Pulses _ BasicTime.GetClockPulses[]; stop: BasicTime.Pulses; microseconds, seconds: LONG CARDINAL; digit: CARDINAL; any: BOOL _ FALSE; text: REF TEXT _ NEW[TEXT[8]]; result _ CommandTool.DoCommand[commandLine: cmd.commandLine, parent: cmd]; stop _ BasicTime.GetClockPulses[]; microseconds _ BasicTime.PulsesToMicroseconds[stop - start]; seconds _ microseconds / 1000000; microseconds _ microseconds MOD 1000000; THROUGH [0..6) DO microseconds _ microseconds * 10; digit _ microseconds / 1000000; microseconds _ microseconds MOD 1000000; IF NOT any THEN { text _ Convert.AppendChar[to: text, from: '., quote: FALSE]; any _ TRUE; }; text _ Convert.AppendChar[to: text, from: digit + '0, quote: FALSE]; IF microseconds = 0 THEN EXIT; ENDLOOP; RETURN [NIL, IO.PutFR["Running time: %r%g\n", [cardinal[seconds]], [text[text]]]]; }; Checkpoint: Commander.CommandProc = { errmsg: ROPE; out: STREAM = cmd.out; IO.PutF[out, "Creating checkpoint at %g\n", [time[BasicTime.Now[]]]]; IO.PutF[out, " made by %g\n", [rope[UserCredentials.Get[].name]]]; errmsg _ Booting.Checkpoint[]; IF errmsg.Length[] # 0 THEN RETURN[$Failure, errmsg]; IO.PutF[out, "Rollback at %g\n User: %g\n Version: ", [time[BasicTime.Now[]]], [rope[UserCredentials.Get[].name]]]; PutVersion[cmd.out]; }; Rollback: Commander.CommandProc = { RETURN[$Failure, Booting.Boot[[self[]], [r: TRUE]]]; }; ExpandAndParse: PROC [cmd: Commander.Handle] RETURNS [CommandTool.ArgumentVector] = { CommandTool.StarExpansion[cmd]; RETURN [CommandTool.Parse[cmd]]; }; Init: PROC = { Register: PROC [name: ROPE, proc: Commander.CommandProc, doc: ROPE, data: REF _ NIL, un: BOOL _ FALSE] = { name _ Rope.Concat["///Commands/", name]; Commander.Register[name, proc, doc, data]; IF un THEN CommandExtras.MakeUninterpreted[Commander.Lookup[name]]; }; Commander.Register["-", Comment, "Comment"]; CommandExtras.MakeUninterpreted[Commander.Lookup["-"]]; Commander.Register["--", Comment, "Comment"]; CommandExtras.MakeUninterpreted[Commander.Lookup["--"]]; Commander.Register["/", Comment, "Comment"]; CommandExtras.MakeUninterpreted[Commander.Lookup["/"]]; Commander.Register["//", Comment, "Comment"]; CommandExtras.MakeUninterpreted[Commander.Lookup["//"]]; Commander.Register["///", Comment, "Comment"]; CommandExtras.MakeUninterpreted[Commander.Lookup["///"]]; Register["?", EnumerateCommands, "List registered commands"]; Register["??", EnumerateCommands, "List registered commands (including those not yet loaded)", $Full]; Register["Help", EnumerateCommands, "List registered commands"]; Register["HelpFull", EnumerateCommands, "List registered commands (including those not yet loaded)", $Full]; Register["Abort", Abort, "Abort -- Raises ABORTED"]; Register["AddSearchRules", SetSearchRules, "Add command search rules: AddSearchRules list-of-directories"]; Register["CopyCommand", CopyCommand, "CopyCommand newName _ oldName - Attach a new name to an existing command"]; Register["Checkpoint", Checkpoint, "Create a checkpoint"]; Register["Date", Date, "Print date and time"]; Register["Echo", Echo, "Print command line"]; Register["Fail", Fail, "This command always fails"]; Register["Indent", Indent, "Indent n -- Indent n spaces"]; Register["New", New, "Open an empty viewer"]; Register["Open", Open, "Open fileName - open a viewer"]; Register["PrintSearchRules", PrintSearchRules, "Print command search rules"]; Register["Rollback", Rollback, "Roll back to previous checkpoint"]; Register["SetSearchRules", SetSearchRules, "Set command search rules: SetSearchRules directory*", $SetSearchRules]; Register["Shift", Shift, "Shift command-line (uninterpreted)", NIL, TRUE]; Register["ShiftInterp", ShiftInterp, "ShiftInterp command-line (interpreted)"]; Register["Sleep", Sleep, "Sleep n -- pause for n seconds"]; Register["Statistics", Statistics, "Turn statistics printing on or off"]; Register["Tee", Tee, "Tee file -- copy standard input to file"]; Register["Time", Time, "Time command-line (uninterpreted)", NIL, TRUE]; Register["Unregister", Unregister, "Unregister a command"]; Register["User", User, "Print name of logged in user"]; Register["Version", Version, "Print Cedar version number"]; }; Init[]; END. April 4, 1983 4:42 pm, Stewart, Created April 20, 1983 7:10 pm, Stewart, add commandfile arguments and auto commandfiles September 7, 1983 11:10 am, Stewart, Cedar 5 October 24, 1983 9:42 am, Stewart, New CommandTool November 3, 1983 9:37 am, Stewart, Bulletproofing November 3, 1983 9:37 am, Stewart, add Checkpoint and Rollback January 14, 1984 8:18 pm, Stewart, new Open