CountReleaseSize.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Russ Atkinson, April 25, 1985 3:52:56 am PST
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 = {
[cmd: Handle] RETURNS [result: REF ← NIL, msg: ROPE ← NIL]
CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...]
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;
# of arguments processed
argv: CommandTool.ArgumentVector ← CommandTool.Parse[cmd: cmd, starExpand:
TRUE
! CommandTool.Failed => {msg ← errorMsg; GO TO failed}];
When parsing the command line, be prepared for failure. The error is reported to the user
FOR i:
NAT
IN [1..argv.argc)
DO
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.
arg: ROPE = CommandTool.FileWithSearchRules[argv[i], ".mesa", cmd];
Process.CheckForAbort[];
It is a good idea to periodically check for a process abort request.
IF Rope.Length[arg] = 0
THEN
LOOP;
Ignore null arguments (it is not easy to generate them, even).
IF Rope.Fetch[arg, 0] = '-
THEN {
This argument sets switches for the remaining patterns. By convention, switches are normally "sticky", in that they stay set until explicitly changed.
ProcessSwitches[arg];
LOOP;
};
ProcessArgument[arg];
Perform whatever processing is necessary for a normal argument.
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 = {
[cmd: Handle] RETURNS [result: REF ← NIL, msg: ROPE ← NIL]
CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...]
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;
# of arguments processed
argv: CommandTool.ArgumentVector ← CommandTool.Parse[cmd: cmd, starExpand:
TRUE
! CommandTool.Failed => {msg ← errorMsg; GO TO failed}];
When parsing the command line, be prepared for failure. The error is reported to the user
FOR i:
NAT
IN [1..argv.argc)
DO
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.
arg: ROPE = CommandTool.FileWithSearchRules[argv[i], ".mesa", cmd];
Process.CheckForAbort[];
It is a good idea to periodically check for a process abort request.
IF Rope.Length[arg] = 0
THEN
LOOP;
Ignore null arguments (it is not easy to generate them, even).
IF Rope.Fetch[arg, 0] = '-
THEN {
This argument sets switches for the remaining patterns. By convention, switches are normally "sticky", in that they stay set until explicitly changed.
ProcessSwitches[arg];
LOOP;
};
ProcessArgument[arg];
Perform whatever processing is necessary for a normal argument.
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 {
[fullGName: ROPE] RETURNS [continue: BOOLEAN]
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;
};