DIRECTORY BasicTime USING [Period], Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse], CopyFromVersionMap, FS USING [Copy, Error, ExpandName], FSBackdoor USING [Entry, EntryPtr, Enumerate, highestVersion, TextRep], IO USING [PutF, PutF1, PutRope, STREAM], Process USING [CheckForAbort], RefText USING [TrustTextAsRope], Rope USING [AppendChars, Concat, Fetch, Flatten, FromRefText, Length, ROPE], UserProfile USING [Token], VersionMap USING [FetchName, GetPrefix, Map, MapEntry, RestoreMapFromFile]; CopyFromVersionMapImpl: CEDAR PROGRAM IMPORTS BasicTime, Commander, CommandTool, FS, FSBackdoor, IO, Process, RefText, Rope, UserProfile, VersionMap EXPORTS CopyFromVersionMap SHARES VersionMap = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Switches: TYPE = PACKED ARRAY CHAR['a..'z] OF BOOL; cedarPrefix: PUBLIC ROPE _ "[Cedar]VersionMap>Cedar"; cedarChestPrefix: PUBLIC ROPE _ "[Cedar]VersionMap>CedarChest"; daToolsPrefix: PUBLIC ROPE _ "[DATools]DAWorldAdministration>DAWorldMap"; CopyCommandProc: Commander.CommandProc = { out: STREAM = cmd.out; switches: Switches _ ALL[FALSE]; ProcessSwitches: PROC [arg: ROPE] = { sense: BOOL _ TRUE; FOR index: INT IN [0..Rope.Length[arg]) DO char: CHAR _ Rope.Fetch[arg, index]; SELECT char FROM '- => LOOP; '~ => {sense _ NOT sense; LOOP}; IN ['a..'z] => switches[char] _ sense; IN ['A..'Z] => switches[char + ('a-'A)] _ sense; ENDCASE; sense _ TRUE; ENDLOOP; }; ProcessArgument: PROC [arg: ROPE] = { mapPrefix: ROPE _ arg; Process.CheckForAbort[]; IF mapPrefix = NIL THEN SELECT TRUE FROM switches['c] => mapPrefix _ UserProfile.Token["CopyFromVersionMap.CedarChestPrefix", cedarChestPrefix]; switches['d] => mapPrefix _ UserProfile.Token["CopyFromVersionMap.DAToolsPrefix", daToolsPrefix]; switches['r] => mapPrefix _ UserProfile.Token["CopyFromVersionMap.CedarPrefix", cedarPrefix]; switches['u] => mapPrefix _ UserProfile.Token["CopyFromVersionMap.DefaultPrefix"]; ENDCASE; IF mapPrefix = NIL THEN {msg _ "No map prefix seen."; RETURN}; argsProcessed _ argsProcessed + 1; IF switches['w] THEN IO.PutRope[cmd.out, "-- Warnings only, no files to be attached.\n"]; Copy[log: cmd.out, mapPrefix: mapPrefix, verbose: switches['v], doit: NOT switches['w], zapOlder: switches['z]]; }; argsProcessed: NAT _ 0; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd, starExpand: FALSE ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; ProcessSwitches[UserProfile.Token["CopyFromVersionMap.DefaultSwitches"]]; FOR i: NAT IN [1..argv.argc) DO arg: ROPE = argv[i]; Process.CheckForAbort[]; IF Rope.Length[arg] = 0 THEN LOOP; IF Rope.Fetch[arg, 0] = '- THEN { ProcessSwitches[arg]; LOOP; }; ProcessArgument[arg ! FS.Error => {msg _ error.explanation; GO TO failed}]; ENDLOOP; IF argsProcessed = 0 THEN ProcessArgument[NIL ! FS.Error => {msg _ error.explanation; GO TO failed}]; IF argsProcessed = 0 THEN GO TO failed; EXITS failed => {result _ $Failure}; }; Copy: PUBLIC PROC [log: IO.STREAM, mapPrefix: ROPE, verbose: BOOL _ FALSE, doit: BOOL _ TRUE, zapOlder: BOOL _ FALSE] = { EnumerateVersionMap[Rope.Concat[mapPrefix, "Source.VersionMap"], log, verbose, doit, zapOlder]; EnumerateVersionMap[Rope.Concat[mapPrefix, "Symbols.VersionMap"], log, verbose, doit, zapOlder]; }; EnumerateVersionMap: PROC [mapName: ROPE, st: STREAM _ NIL, verbose, doit, zapOlder: BOOL] = { foundFiles: INT _ 0; attachedFiles: INT _ 0; map: VersionMap.Map _ NIL; maxNameLen: NAT = 128; nameText: REF TEXT _ NEW[TEXT[maxNameLen]]; fullNameText: REF TEXT _ NEW[TEXT[maxNameLen]]; mapPrefix: ROPE _ NIL; prefix: ROPE _ FS.ExpandName["$"].fullFName; dstInit: NAT = Rope.Length[prefix]-5; nameText.length _ 0; fullNameText.length _ 0; [] _ Rope.AppendChars[nameText, prefix, 4, dstInit]; IO.PutF1[st, "Working on %g ", [rope[mapName]] ]; map _ VersionMap.RestoreMapFromFile[mapName]; IO.PutF1[st, " (files: %g)\n", [integer[map.len]] ]; mapPrefix _ VersionMap.GetPrefix[map]; FOR mapIndex: NAT IN [0..map.len) DO mapEntry: VersionMap.MapEntry = map[mapIndex]; mapVersion: NAT _ 0; inVersion: BOOL _ FALSE; dst: NAT _ dstInit; FOR pos: INT _ mapEntry.index, pos+1 DO c: CHAR _ Rope.Fetch[map.names, pos]; SELECT c FROM '/, '> => {dst _ dstInit; LOOP}; '! => {inVersion _ TRUE; LOOP}; '\n => EXIT; ENDCASE; SELECT TRUE FROM inVersion => IF c IN ['0..'9] AND mapVersion <= (LAST[NAT]-9)/10 THEN { mapVersion _ mapVersion*10 + (c-'0); LOOP; }; dst < maxNameLen => {nameText[dst] _ c; dst _ dst + 1}; ENDCASE; ENDLOOP; nameText.length _ dst; IF dst # dstInit THEN { matchProc: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept: BOOL _ FALSE, stop: BOOL _ TRUE] = TRUSTED { WITH entry SELECT FROM attached: LONG POINTER TO attached FSBackdoor.Entry => { IF attached.created = mapEntry.created THEN { attachedText: LONG POINTER TO FSBackdoor.TextRep = @entry[attached.attachedTo]; fDst: NAT _ 0; IF NOT zapOlder THEN IF BasicTime.Period[from: attached.created, to: mapEntry.created] < 0 THEN { found _ dateWarning _ TRUE; RETURN; }; fullNameText.length _ 0; IF Rope.Fetch[map.names, mapEntry.index] # '[ THEN { [] _ Rope.AppendChars[fullNameText, mapPrefix]; fDst _ fullNameText.length; }; FOR pos: INT _ mapEntry.index, pos+1 DO c: CHAR _ Rope.Fetch[map.names, pos]; SELECT c FROM '! => IF mapVersion = 0 THEN EXIT; '\n => EXIT; ENDCASE; IF fDst < maxNameLen THEN {fullNameText[fDst] _ c; fDst _ fDst+1}; ENDLOOP; fullNameText.length _ fDst; FOR i: NAT IN [0..fDst) DO IF attachedText[i] # fullNameText[i] THEN RETURN; ENDLOOP; found _ TRUE; }; RETURN; }; ENDCASE; IF NOT zapOlder THEN { found _ localWarning _ TRUE; RETURN; }; }; found: BOOL _ FALSE; dateWarning: BOOL _ FALSE; localWarning: BOOL _ FALSE; Process.CheckForAbort[]; FSBackdoor.Enumerate[volName: NIL, nameBodyPattern: RefText.TrustTextAsRope[nameText], localOnly: TRUE, allVersions: FALSE, version: FSBackdoor.highestVersion, matchProc: matchProc, acceptProc: NIL]; SELECT TRUE FROM dateWarning => { IO.PutF1[st, "File not attached, local version more recent.\n %g\n", [rope[VersionMap.FetchName[map, mapIndex]]]]; }; localWarning => IO.PutF1[st, "File not attached, unattached local version exists.\n %g\n", [rope[VersionMap.FetchName[map, mapIndex]]]]; found => foundFiles _ foundFiles + 1; (NOT doit) AND NOT verbose => { }; ENDCASE => { fullName: ROPE _ VersionMap.FetchName[map, mapIndex]; shortName: ROPE _ Rope.Flatten[Rope.FromRefText[nameText], dstInit]; IF verbose THEN { IO.PutF1[st, "%g\n", [rope[fullName]] ]; }; IF doit THEN { [] _ FS.Copy[from: fullName, to: shortName, wantedCreatedTime: mapEntry.created, remoteCheck: FALSE, attach: TRUE]; attachedFiles _ attachedFiles + 1; }; }; }; ENDLOOP; IO.PutF[st, " foundFiles: %g, attachedFiles: %g\n", [integer[foundFiles]], [integer[attachedFiles]] ]; }; doc: ROPE = "copy files from version maps -c: CedarChest prefix default -d: DATools prefix default -n: NCP prefix default -r: Cedar release prefix default -v: verbose (list files to be attached) -w: warning only (no files attached) -z: zap files regardless of date "; Commander.Register[ key: "///Commands/CopyFromVersionMap", proc: CopyCommandProc, doc: doc, clientData: NIL, interpreted: TRUE ]; END. œCopyFromVersionMapImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) June 9, 1986 12:01:37 pm PDT Spreitzer, April 24, 1986 12:05:36 pm PST [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...] Try for some well-known prefixes # of arguments processed When parsing the command line, be prepared for failure. The error is reported to the user Allows the user to specify personal defaults for the switches via the user's profile. Each argument can either be a switch specification or a genuine argument to be processed. The first argument (argv[0]) is not examined, because by convention it is the name of the command as given by the user. It is a good idea to periodically check for a process abort request. Ignore null arguments (it is not easy to generate them, even). This argument sets switches for the remaining patterns. By convention, switches are normally "sticky", in that they stay set until explicitly changed. Perform whatever processing is necessary for a normal argument. The prefix must default (don't count the "[]<>" or the "$") Just to be careful Just to be careful transfer the working directory into the start of the name buffer We have a valid short name, so look it up Probably have found the appropriate entry, but we should look at the full names to make sure of the proper attachment. we should not zap if attached to a later file indicate that we will not attach this one Just to be careful At this point we have a local name match we should not zap if attached to a local file Short cut when warning and not verbose Output the name & info ส ˜codešœ™Kšœ ฯmœ1™Kšœ"˜"KšžœžœžœB˜YKšœFžœ'˜pK˜—šœžœ˜Kšœ™—•StartOfExpansionI[cmd: Commander.Handle, starExpand: BOOL _ FALSE, switchChar: CHAR]šœKž˜PKšœ)žœžœ ˜8KšœZ™ZK˜—šœI˜IKšœU™U—K˜šžœžœžœž˜Kšœา™าKšœžœ ˜˜KšœD™D—šžœžœžœ˜"Kšœ>™>—šžœžœ˜!Kšœ—™—Kšœ˜Kšžœ˜Kšœ˜—šœžœ$žœžœ ˜KKšœ?™?—Kšžœ˜—šžœž˜Kšœ™Kš œžœžœ$žœžœ ˜K—Kšžœžœžœžœ˜'šž˜Kšœ˜—K˜K˜—šŸœžœžœžœžœ žœ žœžœžœžœ žœžœ˜yKšœ_˜_Kšœ`˜`K˜K˜—š Ÿœžœ žœžœžœžœ˜^Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kš œ žœžœžœžœ˜+Kš œžœžœžœžœ˜/Kšœ žœžœ˜Kšœžœžœ˜,šœ žœ˜%Kšœ#™#—šœ˜Kšœ™—šœ˜Kšœ™—šœ4˜4K™@—K˜Kšžœ0˜2Kšœ-˜-Kšžœ3˜5K˜Kšœ&˜&K˜šžœ žœžœž˜$Kšœ.˜.Kšœ žœ˜Kšœ žœžœ˜Kšœžœ ˜šžœžœž˜'Kšœžœ˜%šžœž˜ Kšœžœ˜ Kšœžœžœ˜Kšœžœ˜ Kšžœ˜—šžœžœž˜š œ žœžœ žœžœžœžœ˜GKšœ$˜$Kšžœ˜K˜—Kšœ7˜7Kšžœ˜—Kšžœ˜—Kšœ˜šžœžœ˜K™)šœ žœžœžœ žœžœžœžœžœ˜qšžœžœž˜šœ žœžœžœ˜8šžœ%žœ˜-Kšœv™vKšœžœžœžœ2˜OKšœžœ˜šžœžœ ž˜K™-šžœDžœ˜LKšœ)™)Kšœžœ˜Kšžœ˜K˜——šœ˜Kšœ™—šžœ,žœ˜4Kšœ/˜/Kšœ˜K˜—šžœžœž˜'Kšœžœ˜%šžœž˜ Kšœžœžœžœ˜"Kšœžœ˜ Kšžœ˜—Kšžœžœ)˜BKšžœ˜—Kšœ˜šžœžœžœ ž˜Kšžœ#žœžœ˜1Kšžœ˜—Kšœžœ˜ K˜—Kšžœ˜K˜—Kšžœ˜—Kšœ(™(šžœžœ žœ˜K™-Kšœžœ˜Kšžœ˜K˜—K˜—Kšœžœžœ˜Kšœ žœžœ˜Kšœžœžœ˜K˜Kš œžœAžœžœHžœ˜วšžœžœž˜šœ˜Kšžœq˜sK˜—šœ˜Kšžœw˜y—šœ˜Kšœ˜—šœžœžœžœ ˜Kšœ&™&Kšœ˜—šžœ˜ Kšœ žœ'˜5Kšœ žœ5˜Dšžœ žœ˜Kšœ™Kšžœ&˜(K˜—šžœžœ˜KšœžœWžœ žœ˜sK˜"K˜—K˜——K˜—Kšžœ˜—Kšžœe˜gK˜K˜—Kšœžœ’˜›K˜–x[key: ROPE, proc: Commander.CommandProc, doc: ROPE _ NIL, clientData: REF ANY _ NIL, interpreted: BOOL _ TRUE]šœ˜Kšœ&˜&Kšœ˜Kšœ ˜ Kšœ žœ˜Kšœ ž˜Kšœ˜—K˜Kšžœ˜K˜šœ˜K™——…—H-๓