DIRECTORY Basics, Commander, CommandTool, CountedVM, FS, FSBackdoor, IO, MessageWindow USING [Append], Process, Rope, VersionMap; CountReleaseSize: CEDAR PROGRAM IMPORTS Basics, Commander, CommandTool, CountedVM, FS, FSBackdoor, IO, MessageWindow, Process, Rope, VersionMap = BEGIN CARD: TYPE = Basics.CARD; Map: TYPE = VersionMap.Map; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; CountCommand: Commander.CommandProc = { InnerCount: PROC [name: ROPE, match: ROPE _ NIL] = { files: INT _ 0; pages: INT _ 0; ifsPages: INT _ 0; totalBytes: INT _ 0; map: Map _ VersionMap.RestoreMapFromFile[name]; IF match = NIL THEN IO.PutF[cmd.out, " Processing: %g\n", [rope[name]]] ELSE IO.PutF[cmd.out, " Processing: %g (%g)\n", [rope[name]], [rope[match]] ]; FOR i: INT IN [0..VersionMap.Length[map]) DO eachName: ROPE _ VersionMap.FetchName[map, i]; IF match = NIL OR Rope.Match[match, eachName, FALSE] THEN { bytes: INT _ FS.FileInfo[name: eachName, remoteCheck: FALSE ! FS.Error => IF error.group # bug THEN { IO.PutF[cmd.out, "File not found: %g\n", [rope[eachName]]]; LOOP; }].bytes; totalBytes _ totalBytes + bytes; pages _ pages + (bytes+511) / 512; ifsPages _ ifsPages + (bytes+2047) / 2048; files _ files + 1; MessageWindow.Append[ msg _ IO.PutFR[ " files: %g, bytes: %g, pages: %g, ifsPages: %g", [integer[files]], [integer[totalBytes]], [integer[pages]], [integer[ifsPages]]], TRUE]; }; ENDLOOP; IO.PutF[cmd.out, " cmd.out: %g, bytes: %g, pages: %g, ifsPages: %g\n", [integer[files]], [integer[totalBytes]], [integer[pages]], [integer[ifsPages]] ]; }; InnerCount["CedarSource.VersionMap", "*.mesa*"]; InnerCount["CedarSource.VersionMap"]; InnerCount["CedarSymbols.VersionMap"]; }; CountLinesCommand: Commander.CommandProc = { out: STREAM = cmd.out; switches: PACKED ARRAY CHAR['a..'z] OF BOOL _ 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] = { bytes, pos, lines, empties, charsPerLine: CARD _ 0; Process.CheckForAbort[]; [bytes, pos, lines, empties] _ CountThingsInFile[arg]; argsProcessed _ argsProcessed + 1; totalChars _ totalChars + pos; totalLines _ totalLines + lines; IF lines # 0 THEN charsPerLine _ (pos + lines/2) / lines; IO.PutF1[cmd.out, "%g\n", [rope[arg]] ]; IO.PutF[cmd.out, " chars: %g, lines: %g, lineLen: %g", [integer[pos]], [integer[lines]], [integer[charsPerLine]] ]; IO.PutF[cmd.out, ", bytes: %g, empties: %g\n", [integer[bytes]], [integer[empties]] ]; }; totalChars: CARD _ 0; totalLines: CARD _ 0; argsProcessed: NAT _ 0; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd, starExpand: TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; FOR i: NAT IN [1..argv.argc) DO arg: ROPE = CommandTool.FileWithSearchRules[argv[i], ".mesa", cmd]; Process.CheckForAbort[]; IF Rope.Length[arg] = 0 THEN LOOP; IF Rope.Fetch[arg, 0] = '- THEN { ProcessSwitches[arg]; LOOP; }; ProcessArgument[arg]; ENDLOOP; IO.PutF[cmd.out, "Total - files: %g, chars: %g, lines: %g, lineLen: %g\n", [integer[argsProcessed]], [integer[totalChars]], [integer[totalLines]], [integer[(totalChars+totalLines/2) / totalLines]] ]; EXITS failed => {result _ $Failure}; }; CountReleaseLinesCommand: Commander.CommandProc = { out: STREAM = cmd.out; switches: PACKED ARRAY CHAR['a..'z] OF BOOL _ 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] = { bytes, pos, lines, empties, charsPerLine: CARD _ 0; Process.CheckForAbort[]; [bytes, pos, lines, empties] _ CountThingsInFile[arg]; argsProcessed _ argsProcessed + 1; totalChars _ totalChars + pos; totalLines _ totalLines + lines; IF lines # 0 THEN charsPerLine _ (pos + lines/2) / lines; IO.PutF1[cmd.out, "%g\n", [rope[arg]] ]; IO.PutF[cmd.out, " chars: %g, lines: %g, lineLen: %g", [integer[pos]], [integer[lines]], [integer[charsPerLine]] ]; IO.PutF[cmd.out, ", bytes: %g, empties: %g\n", [integer[bytes]], [integer[empties]] ]; }; totalChars: CARD _ 0; totalLines: CARD _ 0; argsProcessed: NAT _ 0; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd, starExpand: TRUE ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; FOR i: NAT IN [1..argv.argc) DO arg: ROPE = CommandTool.FileWithSearchRules[argv[i], ".mesa", cmd]; Process.CheckForAbort[]; IF Rope.Length[arg] = 0 THEN LOOP; IF Rope.Fetch[arg, 0] = '- THEN { ProcessSwitches[arg]; LOOP; }; ProcessArgument[arg]; ENDLOOP; IO.PutF[cmd.out, "Total - files: %g, chars: %g, lines: %g, lineLen: %g\n", [integer[argsProcessed]], [integer[totalChars]], [integer[totalLines]], [integer[(totalChars+totalLines/2) / totalLines]] ]; EXITS failed => {result _ $Failure}; }; CountThingsInFile: PROC [name: ROPE] RETURNS [bytes, pos, lines, empties: CARD _ 0] = TRUSTED { vm: CountedVM.Handle _ NIL; file: FS.OpenFile _ FS.Open[name: name, remoteCheck: FALSE ! FS.Error => GO TO fail]; tempName: ROPE _ NIL; noteFound: FSBackdoor.NameProc = TRUSTED { tempName _ fullGName; continue _ TRUE; }; FSBackdoor.EnumerateCacheForNames[noteFound, NIL, name]; IF tempName = NIL THEN { tempName _ FS.Copy[from: name, to: "///Temp/Count.temp$" ! FS.Error => CONTINUE; ]; }; file _ FS.Open[name: tempName, remoteCheck: FALSE ! FS.Error => GO TO fail]; { ENABLE UNWIND => { IF vm # NIL THEN CountedVM.Free[vm]; FS.Close[file]; }; Buffer: TYPE = PACKED ARRAY [0..charsPerBuffer) OF CHAR; charsPerBuffer: NAT = 16; ptr: LONG POINTER TO Buffer _ NIL; lag: CHAR _ '\n; GetChar: PROC [peek: BOOL _ FALSE] RETURNS [c: CHAR] = TRUSTED INLINE { mod: [0..charsPerBuffer) _ Basics.LowHalf[pos] MOD charsPerBuffer; IF pos >= bytes THEN RETURN [0C]; c _ ptr[mod]; IF peek THEN RETURN; pos _ pos + 1; IF mod = charsPerBuffer - 1 THEN { ptr _ ptr + SIZE[Buffer]; pos _ pos + 1; }; }; bytes _ FS.GetInfo[file].bytes; vm _ CountedVM.SimpleAllocate[(bytes + Basics.bytesPerWord-1)/Basics.bytesPerWord]; ptr _ vm.pointer; FS.Read[file, 0, vm.interval.count, ptr]; DO c: CHAR _ GetChar[]; SELECT c FROM '\n => IF lag = '\n THEN empties _ empties + 1 ELSE lines _ lines + 1; 0C => IF lag = 0C THEN EXIT; ENDCASE; lag _ c; ENDLOOP; CountedVM.Free[vm]; FS.Close[file]; }; EXITS fail => RETURN; }; Commander.Register["CountReleaseSize", CountCommand]; Commander.Register["CountLines", CountLinesCommand]; END. CountReleaseSize.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Russ Atkinson, April 25, 1985 3:52:56 am PST [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...] # of arguments processed When parsing the command line, be prepared for failure. The error is reported to the user 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. [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...] # of arguments processed When parsing the command line, be prepared for failure. The error is reported to the user 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. [fullGName: ROPE] RETURNS [continue: BOOLEAN] Ê ˜codešœ™Kšœ Ïmœ1™™>—šžœžœ˜!Kšœ—™—Kšœ˜Kšžœ˜Kšœ˜—šœ˜Kšœ?™?—Kšžœ˜—šžœH˜JKšœ|˜|—šž˜Kšœ˜—K˜K˜—šœ3˜3š œžœ žœžœžœžœ™:Kšœžœžœ™G—Kšœžœ ˜Kšœ žœžœžœ žœžœžœžœ˜9šŸœžœžœ˜%Kšœžœžœ˜šžœžœžœž˜*Kšœžœ˜$šžœž˜Kšœžœ˜ Kšœžœžœ˜ Kšžœ$˜&Kšžœ.˜0Kšžœ˜—Kšœžœ˜ Kšžœ˜—K˜—šŸœžœžœ˜%Kšœ*žœ˜3K˜Kšœ6˜6Kšœ"˜"Kšœ˜Kšœ ˜ Kšžœ žœ(˜9Kšžœ&˜(šžœ5˜7Kšœ<˜<—šžœ,˜.Kšœ'˜'—K˜—Kšœ žœ˜Kšœ žœ˜šœžœ˜Kšœ™—–I[cmd: Commander.Handle, starExpand: BOOL _ FALSE, switchChar: CHAR]šœKž˜OKšœ)žœžœ ˜8KšœZ™ZK˜—šžœžœžœž˜KšœÒ™ÒKšœžœ:˜C˜KšœD™D—šžœžœžœ˜"Kšœ>™>—šžœžœ˜!Kšœ—™—Kšœ˜Kšžœ˜Kšœ˜—šœ˜Kšœ?™?—Kšžœ˜—šžœH˜JKšœ|˜|—šž˜Kšœ˜—K˜K˜—š Ÿœžœžœžœžœžœ˜_Kšœžœ˜šœžœ žœž˜:Kšœžœ žœžœ˜—Kšœ žœžœ˜–1 -- [fullGName: ROPE] RETURNS [continue: BOOLEAN]šœ!žœ˜*KšÐck-™-Kšœ˜Kšœ žœ˜K˜—Kšœ-žœ˜8šžœ žœžœ˜–Æ[from: ROPE, to: ROPE, setKeep: BOOL _ FALSE, keep: CARDINAL _ 1B (1), wantedCreatedTime: GMT _ OPAQUE#17777777777B, remoteCheck: BOOL _ TRUE, attach: BOOL _ FALSE, wDir: ROPE _ NIL]šœ žœ+˜8Kšœžœ žœ˜Kšœ˜—K˜—šœžœ#ž˜1Kšœžœ žœžœ˜—˜šžœžœ˜Kšžœžœžœ˜$Kšžœ ˜K˜—š œžœžœžœžœžœ˜8Kšœžœ˜—Kš œžœžœžœ žœ˜"Kšœžœ˜šŸœžœžœžœžœžœžœžœ˜GKšœ/žœ˜BKšžœžœžœ˜!Kšœ ˜ Kšžœžœžœ˜K˜šžœžœ˜"Kšœ žœ ˜Kšœ˜K˜—K˜—Kšœžœ˜KšœS˜SKšœ˜Kšžœ'˜)šž˜Kšœžœ ˜šžœž˜ Kšœžœ žœžœ˜FKšœžœ žœžœ˜Kšžœ˜—K˜Kšžœ˜—Kšœ˜Kšžœ ˜K˜—Kšžœ žœ˜K˜K˜—K˜5K˜4K˜Kšžœ˜K˜—…—f-