DIRECTORY Ascii USING [Lower], Commander USING [CommandProc, Register, Handle], CommanderOps, DFCachingOperations USING [BringOver, BringOverAction, BringOverCache, CreateCache, TranslateFilter], DFInternal USING [DefaultInteractionProc], DFOperations USING [AbortInteraction, BringOverFilter, InteractionProc, SModel, SModelAction, --Verify,-- YesNoInteraction, YesNoResponse], DFPrivate USING [FatalError], DFUtilities, FS, GiveAndTake, List, IO, PFS, PFSPrefixMap, ProcessProps, Rope; DFCommandsImpl: CEDAR PROGRAM IMPORTS Ascii, Commander, CommanderOps, DFCachingOperations, DFInternal, DFOperations, DFPrivate, DFUtilities, FS, GiveAndTake, List, IO, PFS, PFSPrefixMap, ProcessProps, Rope = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Confirmation: TYPE = REF ConfirmationPrivate; ConfirmationPrivate: TYPE = RECORD [ cmd: Commander.Handle, style: ARRAY --default--BOOL OF Response ¬ [FALSE: no, TRUE: yes]]; Response: TYPE ~ {yes, no, ask}; ArgPhase: TYPE ~ { normal, lookingForPrefix, lookingForTrans }; defaultAction: DFCachingOperations.BringOverAction ¬ [enter: TRUE, confirmEarlier: TRUE, dfsToo: FALSE]; 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; }; }; GetCmdTokens: PROC [stream: IO.STREAM] RETURNS [LIST OF ROPE] = { head: LIST OF ROPE ~ LIST[NIL]; last: LIST OF ROPE ¬ head; DO token: ROPE ~ GetCmdToken[stream]; IF token = NIL THEN RETURN [head.rest]; last ¬ last.rest ¬ LIST[token]; ENDLOOP; }; ShortName: PROC [dfName: ROPE] RETURNS [ROPE] ~ { fullFName: ROPE; cp: FS.ComponentPositions; [fullFName: fullFName, cp: cp] ¬ FS.ExpandName[dfName]; RETURN [Rope.Substr[fullFName, cp.base.start, cp.ext.start+cp.ext.length-cp.base.start]]; }; PackageAndWorldFor: PROC [dfName: ROPE] RETURNS [packageName, worldName: ROPE ¬ NIL] ~ { ENABLE FS.Error => CONTINUE; stream: IO.STREAM ~ FS.StreamOpen[dfName]; shortName: ROPE ~ ShortName[dfName]; EachItem: PROC [item: REF ANY] RETURNS [stop: BOOL ¬ FALSE] ~ { WITH item SELECT FROM directory: REF DFUtilities.DirectoryItem => { IF Rope.Match["[*]", directory.path1, FALSE] THEN { worldName ¬ Rope.Substr[directory.path1, 1, Rope.Size[directory.path1]-7]; } ELSE { worldName ¬ NIL }; }; file: REF DFUtilities.FileItem => { IF worldName # NIL AND Rope.Equal[file.name, shortName, FALSE] THEN { packageName ¬ Rope.Substr[file.name, 0, Rope.SkipTo[file.name, 0, ".-"]]; stop ¬ TRUE; }; }; ENDCASE; }; DFUtilities.ParseFromStream[in: stream, proc: EachItem]; IO.Close[stream]; }; DFPackageNameCommand: Commander.CommandProc = { packageName, worldName: ROPE; [packageName, worldName] ¬ PackageAndWorldFor[CommanderOps.NextArgument[cmd]]; IF packageName = NIL THEN CommanderOps.Failed["could not figure out a package name"]; IO.PutFL[cmd.out, "-w %g %g", LIST[[rope[worldName]], [rope[packageName]]]]; }; CheckTorch: PROC [cmd: Commander.Handle, dfName: ROPE] RETURNS [warnCount: NAT ¬ 0] ~ { ENABLE { GiveAndTake.NoSuchPackage => CONTINUE; GiveAndTake.MalformedTorch => { cmd.err.PutFL["Warning: Malformed Torch for %g on %g\n", LIST[[rope[packageName]], [rope[worldName]]]]; warnCount ¬ warnCount + 1; CONTINUE; }; }; packageName, worldName: ROPE; [packageName, worldName] ¬ PackageAndWorldFor[dfName]; IF packageName = NIL THEN RETURN; IF NOT GiveAndTake.PackageMine[packageName, worldName] THEN { cmd.err.PutFL["Warning: You don't have the %g torch for %g\n", LIST[[rope[worldName]], [rope[packageName]]]]; warnCount ¬ warnCount + 1; }; }; DoBringover: Commander.CommandProc = { errors, warnings, tWarnings, filesActedUpon: INT ¬ 0; conf: Confirmation = NEW [ConfirmationPrivate ¬ [cmd]]; tryMap: BOOL ¬ FALSE; iSwitch, oSwitch: BOOL ¬ FALSE; justTrustMe: BOOL ¬ FALSE; touchy: BOOL ¬ FALSE; out: STREAM = cmd.out; cache: DFCachingOperations.BringOverCache ~ DFCachingOperations.CreateCache[]; useCache: BOOL ~ TRUE; -- always true now; re-used q switch for quiet quiet: BOOL ¬ FALSE; filter: DFOperations.BringOverFilter ¬ [filterA: $all, filterB: $all, filterC: $all, list: NIL]; action: DFCachingOperations.BringOverAction ¬ defaultAction; dfDir, workingDir: ROPE ¬ NIL; pTable: PFSPrefixMap.PrefixTableList ¬ NIL; argPhase: ArgPhase ¬ normal; argPrefix: ROPE; argl: LIST OF ROPE ~ GetCmdTokens[IO.RIS[cmd.commandLine] ! QuotedStringError => {msg ¬ "Mismatched quotes"; GO TO fail}; ]; IF argl = NIL THEN { msg ¬ bringoverHelpText; GO TO fail}; FOR tail: LIST OF ROPE ¬ argl, tail.rest UNTIL tail = NIL DO arg: ROPE ¬ tail.first; sense: BOOL ¬ TRUE; IF argPhase = lookingForPrefix THEN { argPrefix ¬ arg; argPhase ¬ lookingForTrans; LOOP; }; IF argPhase = lookingForTrans THEN { IF pTable = NIL THEN pTable ¬ PFSPrefixMap.InsertIntoNewPTable[ PFS.PathFromRope[argPrefix], PFS.PathFromRope[arg] ] ELSE pTable ¬ PFSPrefixMap.Insert[ PFS.PathFromRope[argPrefix], PFS.PathFromRope[arg], pTable]; argPhase ¬ normal; LOOP; }; IF Rope.Match["-*", arg] THEN { IF Rope.Equal["-prefixmap", arg, FALSE] THEN { argPhase ¬ lookingForPrefix; LOOP; }; FOR j: INT IN [1..Rope.Length[arg]) DO c: CHAR ¬ Ascii.Lower[Rope.Fetch[arg, j]]; SELECT c FROM 'a => conf.style ¬ [ask, yes]; 'b => filter.filterA ¬ IF sense THEN $derived ELSE $all; 'c => action.suspicious ¬ sense; 'd => action.confirmEarlier ¬ sense; 'e => action.enter ¬ sense; 'f => {action.fetch ¬ sense; action.enter ¬ NOT sense}; 'h => conf.style ¬ [ask, ask]; 'i => iSwitch ¬ sense; 'j => justTrustMe ¬ sense; 'm => tryMap ¬ sense; 'o => {oSwitch ¬ sense; filter.list ¬ NIL}; 'p => filter.filterB ¬ IF sense THEN $public ELSE $all; 'q => quiet ¬ sense; 'r => filter.filterC ¬ IF sense THEN $imported ELSE $all; 's => filter.filterA ¬ IF sense THEN $source ELSE $all; 't => touchy ¬ sense; 'u => { filter ¬ [filterA: $all, filterB: $all, filterC: $all, list: NIL]; action ¬ defaultAction; touchy ¬ tryMap ¬ FALSE; conf­ ¬ [cmd]; }; 'v => action.dontDoit ¬ sense; 'w => filter.filterC ¬ IF sense THEN $defining ELSE $all; 'x => oSwitch ¬ sense; 'y => conf.style ¬ [yes, yes]; 'z => action.dfsToo ¬ sense; '~ => {sense ¬ NOT sense; LOOP}; ENDCASE; sense ¬ TRUE; ENDLOOP; LOOP; }; IF iSwitch THEN { workingDir ¬ arg; iSwitch ¬ FALSE; LOOP; }; IF oSwitch AND tail.rest # NIL THEN { filter.list ¬ CONS[arg, filter.list]; LOOP; }; SELECT TRUE FROM Rope.Match["*/", arg], Rope.Match["*>", arg] => { dfDir ¬ arg; LOOP; }; ENDCASE; IF (arg ¬ CompleteDFFileName[arg, out, dfDir, tryMap]) = NIL THEN GO TO fail; IF NOT justTrustMe AND filter = [filterA: $all, filterB: $all, filterC: $all, list: NIL] THEN tWarnings ¬ CheckTorch[cmd, arg]; { DoBringOverWithPrefixTable: PROC ~ { [errors, warnings, filesActedUpon] ¬ DFCachingOperations.BringOver[ dfFile: arg, filter: DFCachingOperations.TranslateFilter[filter], action: action,interact: InteractionProc, clientData: conf, log: IF quiet THEN NIL ELSE out, errlog: cmd.err, workingDir: workingDir, cache: IF useCache THEN cache ELSE NIL]; }; IF pTable # NIL THEN { propList: List.AList ¬ MakeFullPrefixTableAList[pTable]; ProcessProps.AddPropList[propList, DoBringOverWithPrefixTable]; } ELSE [errors, warnings, filesActedUpon] ¬ DFCachingOperations.BringOver[ dfFile: arg, filter: DFCachingOperations.TranslateFilter[filter], action: action,interact: InteractionProc, clientData: conf, log: IF quiet THEN NIL ELSE out, errlog: cmd.err, workingDir: workingDir, cache: IF useCache THEN cache ELSE NIL]; }; filter.list ¬ NIL; oSwitch ¬ FALSE; warnings ¬ warnings + tWarnings; IF errors + warnings # 0 THEN IO.PutF[cmd.err, "%g errors, %g warnings, %g files acted upon\n", [integer[errors]], [integer[warnings]], [integer[filesActedUpon]]] ELSE IO.PutF1[cmd.err, "%g files acted upon\n", [integer[filesActedUpon]]]; IF errors # 0 OR touchy AND warnings # 0 THEN { msg ¬ "Command terminated."; GO TO fail}; ENDLOOP; EXITS fail => result ¬ $Failure; }; InteractionProc: DFOperations.InteractionProc = { conf: Confirmation = NARROW[clientData]; WITH interaction SELECT FROM a: REF DFOperations.AbortInteraction => RETURN[abort: a.fromABORTED]; yn: REF DFOperations.YesNoInteraction => { DO SELECT conf.style[yn.default] FROM yes, no => RETURN [response: NEW [DFOperations.YesNoResponse ¬ [conf.style[yn.default]=yes]]]; ask => { conf.cmd.out.PutFL["%l%g [%g]%l ", LIST[ [rope[IF yn.blunder THEN "b" ELSE "e"]], [rope[yn.message]], [rope[IF yn.default THEN "yes" ELSE "no"]], [rope[IF yn.blunder THEN "B" ELSE "E"]] ]]; conf.cmd.out.Flush[]; {ansRope: ROPE = conf.cmd.in.GetLineRope[!ABORTED => GOTO Abort]; ansLength: INT = ansRope.Length[]; SELECT TRUE FROM ansLength=0 => RETURN []; ansLength=Rope.Run[s1: ansRope, s2: "yes", case: FALSE] => RETURN [response: NEW [DFOperations.YesNoResponse ¬ [TRUE]]]; ansLength=Rope.Run[s1: ansRope, s2: "no", case: FALSE] => RETURN [response: NEW [DFOperations.YesNoResponse ¬ [FALSE]]]; ansLength=Rope.Run[s1: ansRope, s2: "manual", case: FALSE] => conf.style ¬ [ask, ask]; ansLength=Rope.Run[s1: ansRope, s2: "auto", case: FALSE] AND ansLength>1 => conf.style ¬ [ask, yes]; ansLength=Rope.Run[s1: ansRope, s2: "default", case: FALSE] => conf.style ¬ [no, yes]; ansLength=Rope.Run[s1: ansRope, s2: "always yes", case: FALSE] AND ansLength>1 => conf.style ¬ [yes, yes]; ansLength=Rope.Run[s1: ansRope, s2: "quit", case: FALSE] => RETURN [abort: TRUE, abortMessageForLog: "user said to quit"]; ENDCASE => conf.cmd.out.PutRope["Please respond with a unique prefix of one of: yes, no, manual, auto, default, always yes, quit.\n"]; EXITS Abort => ERROR ABORTED; }}; ENDCASE => ERROR; ENDLOOP; }; ENDCASE; }; MakeFullPrefixTableAList: PROC[pTable: PFSPrefixMap.PrefixTableList] RETURNS[propList: List.AList] ~ { list: PFSPrefixMap.EntryList ~ PFSPrefixMap.GetMap[]; FOR l: PFSPrefixMap.EntryList ¬ list, l.rest UNTIL l=NIL DO IF PFSPrefixMap.Lookup[l.first.prefix, pTable] # NIL THEN LOOP; pTable ¬ PFSPrefixMap.Insert[l.first.prefix, l.first.translation, pTable]; ENDLOOP; propList ¬ List.PutAssoc[$PrefixTableList, pTable, NIL]; }; DoSModel: Commander.CommandProc = { errors, warnings, tWarnings, filesActedUpon: INT ¬ 0; oSwitch: BOOL ¬ FALSE; touchy: BOOL ¬ FALSE; justTrustMe: BOOL ¬ FALSE; out: STREAM = cmd.out; makeAttachment: BOOL ¬ TRUE; clientData: REF BOOL ¬ NEW[BOOL ¬ TRUE]; action: DFOperations.SModelAction ¬ [remoteCheck: TRUE, storeChanged: TRUE]; pTable: PFSPrefixMap.PrefixTableList ¬ NIL; argPhase: ArgPhase ¬ normal; argPrefix: ROPE; argl: LIST OF ROPE ~ GetCmdTokens[IO.RIS[cmd.commandLine] ! QuotedStringError => {msg ¬ "Mismatched quotes"; GO TO fail}; ]; IF argl = NIL THEN { msg ¬ smodelHelpText; GO TO fail}; FOR tail: LIST OF ROPE ¬ argl, tail.rest UNTIL tail = NIL DO arg: ROPE ¬ tail.first; sense: BOOL ¬ TRUE; IF argPhase = lookingForPrefix THEN { argPrefix ¬ arg; argPhase ¬ lookingForTrans; LOOP; }; IF argPhase = lookingForTrans THEN { IF pTable = NIL THEN pTable ¬ PFSPrefixMap.InsertIntoNewPTable[ PFS.PathFromRope[argPrefix], PFS.PathFromRope[arg] ] ELSE pTable ¬ PFSPrefixMap.Insert[ PFS.PathFromRope[argPrefix], PFS.PathFromRope[arg], pTable]; argPhase ¬ normal; LOOP; }; IF Rope.Match["-*", arg] THEN { IF Rope.Equal["-prefixmap", arg, FALSE] THEN { argPhase ¬ lookingForPrefix; LOOP; }; FOR j: INT IN [1..Rope.Length[arg]) DO c: CHAR ¬ Ascii.Lower[Rope.Fetch[arg, j]]; SELECT c FROM 'a => makeAttachment ¬ sense; 'c => action.remoteCheck ¬ sense; 'j => justTrustMe ¬ sense; 'n => action.storeChanged ¬ NOT sense; 'u => action.storeChanged ¬ action.remoteCheck ¬ makeAttachment ¬ TRUE; 't => touchy ¬ TRUE; '~ => {sense ¬ NOT sense; LOOP}; ENDCASE; sense ¬ TRUE; ENDLOOP; LOOP; }; IF (arg ¬ CompleteDFFileName[arg, out]) = NIL THEN GO TO fail; IF NOT justTrustMe THEN tWarnings ¬ CheckTorch[cmd, arg]; IF tWarnings # 0 THEN CommanderOps.Failed["Command terminated."]; clientData­ ¬ makeAttachment; { ENABLE { DFPrivate.FatalError => { msg ¬ message; ERROR } }; DoSModelWithPrefixMap: PROC ~ { [errors, warnings, filesActedUpon] ¬ DFOperations.SModel[ dfFile: arg, action: action, interact: DFInternal.DefaultInteractionProc, clientData: clientData, log: out]; }; IF pTable # NIL THEN { propList: List.AList ¬ MakeFullPrefixTableAList[pTable]; ProcessProps.AddPropList[propList, DoSModelWithPrefixMap]; } ELSE [errors, warnings, filesActedUpon] ¬ DFOperations.SModel[ dfFile: arg, action: action, interact: DFInternal.DefaultInteractionProc, clientData: clientData, log: out]; }; warnings ¬ warnings + tWarnings; IF errors + warnings # 0 THEN IO.PutF[cmd.err, "%g errors, %g warnings, %g files acted upon\n", [integer[errors]], [integer[warnings]], [integer[filesActedUpon]]] ELSE IO.PutF1[cmd.err, "%g files acted upon\n", [integer[filesActedUpon]]]; IF errors # 0 OR touchy AND warnings # 0 THEN {msg ¬ "Command terminated.\n"; GO TO fail}; ENDLOOP; EXITS fail => result ¬ $Failure; }; < {msg ¬ "Mismatched quotes"; GO TO fail}; ]; IF argl = NIL THEN { msg ¬ verifydfHelpText; GO TO fail}; FOR tail: LIST OF ROPE ¬ argl, tail.rest UNTIL tail = NIL DO arg: ROPE ¬ tail.first; sense: BOOL ¬ TRUE; IF Rope.Match["-*", arg] THEN { FOR j: INT IN [1..Rope.Length[arg]) DO c: CHAR ¬ Ascii.Lower[Rope.Fetch[arg, j]]; SELECT c FROM 't => touchy ¬ sense; 'u => touchy ¬ FALSE; '~ => {sense ¬ NOT sense; LOOP}; ENDCASE; ENDLOOP; LOOP; }; IF (arg ¬ CompleteDFFileName[arg, out]) = NIL THEN GO TO fail; [errors, warnings, filesActedUpon] ¬ DFOperations.Verify[ dfFile: arg, interact: DFInternal.DefaultInteractionProc, clientData: NIL, log: out]; IF errors + warnings # 0 THEN IO.PutF[out, "%g errors, %g warnings, %g files acted upon\n", [integer[errors]], [integer[warnings]], [integer[filesActedUpon]]] ELSE IO.PutF[out, "%g files acted upon\n", [integer[filesActedUpon]]]; IF errors # 0 OR touchy AND warnings # 0 THEN { msg ¬ "Command terminated.\n"; GO TO fail; }; ENDLOOP; EXITS fail => result ¬ $Failure; };>> CompleteDFFileName: PROC [dfFileName: ROPE, out: STREAM, dir: ROPE ¬ NIL, tryMap: BOOL ¬ FALSE] RETURNS [ROPE] = { length: INT = dfFileName.Length[]; msg: ROPE ¬ NIL; SELECT TRUE FROM Rope.Match["*.df", dfFileName, FALSE], Rope.Find[dfFileName, "!"] # -1 => {}; ENDCASE => dfFileName ¬ Rope.Concat[dfFileName, ".df"]; { <