DIRECTORY Buttons USING [ButtonProc, Create], Commander USING [CommandProc, Register], FS USING [StreamOpen, Error, NameProc, EnumerateForNames], IO USING [STREAM, PutF, rope, Close, int, GetChar, EndOfStream, RIS, PutFR], List USING [DReverse], MessageWindow USING [Append], Rope USING [ROPE], CommandTool USING [Parse, ArgumentVector], ViewerTools USING [GetSelectionContents]; WordCountImpl: CEDAR MONITOR IMPORTS Buttons, Commander, FS, IO, List, MessageWindow, CommandTool, ViewerTools = BEGIN ROPE: TYPE = Rope.ROPE; countWordLengths: BOOL _ FALSE; includeApostrophes: BOOL _ TRUE; maxWordLength: NAT = 100; countWordLens: REF ARRAY [1..maxWordLength] OF INT _ NEW[ARRAY [1..maxWordLength] OF INT]; WordCount: ENTRY Commander.CommandProc -- [cmd: Commander.Handle] -- = { stdout: IO.STREAM _ cmd.out; cmdLine: CommandTool.ArgumentVector _ CommandTool.Parse[cmd]; fileCount: INT _ 0; totalWordCount: INT _ 0; totalLineCount: INT _ 0; headerWritten: BOOL _ FALSE; verbose: BOOL _ TRUE; countWordLens^ _ ALL[0]; FOR argCount: INT IN [1..cmdLine.argc) DO fileNames: LIST OF ROPE _ FileList[cmdLine.s[argCount]]; IF verbose AND fileNames = NIL THEN IO.PutF[stdout, "No files matched \"%g\"\n", IO.rope[cmdLine.s[argCount]]]; FOR fileName: LIST OF ROPE _ fileNames, fileName.rest UNTIL fileName = NIL DO in: IO.STREAM _ FS.StreamOpen[fileName.first ! FS.Error => GOTO openFailed ]; charCount, wordCount, newLineCount: INT; fileCount _ fileCount + 1; [charCount, wordCount, newLineCount] _ CountFile[in, countWordLens]; totalWordCount _ totalWordCount + wordCount; totalLineCount _ totalLineCount + newLineCount; in.Close[]; IF verbose AND ~headerWritten THEN { headerWritten _ TRUE; IO.PutF[stdout, "Lines\tWords\t\tFile\n"]; }; IO.PutF[stdout, "%6d\t%6d\t\t%g\n", IO.int[newLineCount], IO.int[wordCount], IO.rope[fileName.first]]; REPEAT openFailed => IO.PutF[stdout, "Could not open \"%g\"\n", IO.rope[fileName.first]]; ENDLOOP; ENDLOOP; IF fileCount > 1 AND verbose THEN { IO.PutF[stdout,"%6d\t%6d\t\t\tTotal for %g files.\n", IO.int[totalLineCount], IO.int[totalWordCount], IO.int[fileCount]]; }; IF countWordLengths THEN FOR i: NAT IN [1..100] DO IF countWordLens[i] > 0 THEN IO.PutF[stdout,"Words of length %6d:\t%6d.\n", IO.int[i], IO.int[countWordLens[i]]]; ENDLOOP; }; CountFile: INTERNAL PROC[file: IO.STREAM, countWordLens: REF ARRAY [1..100] OF INT] RETURNS [ charCount: INT _ 0, wordCount: INT _ 0, newLineCount: INT _ 0 ] = { State: TYPE = { inWord, inJunk, oneNull }; state: State _ inJunk; wordLen: NAT _ 0; DO c: CHAR _ IO.GetChar[file ! IO.EndOfStream => GOTO eof]; SELECT c FROM IN ['0..'9], IN ['A..'Z], IN ['a..'z] => { IF state ~= inWord THEN { state _ inWord; wordCount _ wordCount + 1; wordLen _ 0; }; wordLen _ wordLen + 1; }; = 0C => IF state = oneNull THEN EXIT ELSE state _ oneNull; ENDCASE => { IF c = '\' AND includeApostrophes AND state = inWord THEN { wordLen _ wordLen + 1; } ELSE { IF state = inWord THEN IF wordLen > maxWordLength THEN countWordLens[maxWordLength] _ countWordLens[maxWordLength]+1 ELSE countWordLens[wordLen] _ countWordLens[wordLen]+1; state _ inJunk; IF c = '\n THEN newLineCount _ newLineCount + 1; }; }; charCount _ charCount + 1; REPEAT eof => NULL; ENDLOOP; }; WordCountButton: ENTRY Buttons.ButtonProc = { chars, words, lines: INT; countWordLens^ _ ALL[0]; [chars, words, lines] _ CountFile[IO.RIS[ViewerTools.GetSelectionContents[]], countWordLens]; MessageWindow.Append[IO.PutFR["Selection contains %d chars, %d words, and %d lines.", IO.int[chars], IO.int[words], IO.int[lines]], TRUE]; }; FileList: PROC [pattern: ROPE] RETURNS [fileNames: LIST OF ROPE _ NIL] = { GetNames: FS.NameProc = { fileNames _ CONS[fullFName, fileNames]; continue _ TRUE; }; FS.EnumerateForNames[pattern, GetNames]; TRUSTED {fileNames _ LOOPHOLE[List.DReverse[LOOPHOLE[fileNames]]]}; }; Commander.Register[ key: "WordCount", proc: WordCount, doc: "Counts the words in a group of files."]; [] _ Buttons.Create[ info: [ name: "WC", parent: NIL], proc: WordCountButton, documentation: "Counts the words in the current selection."]; END. CHANGE LOG Created by Nix on September 8, 1983 11:17 am DFile: WordCountImpl.mesa Last Edited by: Nix, February 6, 1984 1:32:54 pm PST Last Edited by: Beach, September 16, 1983 9:29 am Callable from the command interpreter. Expects a list of file names as arguments, and counts the number of words in the indicated files. Counts the number of words in the indicated stream. Κ1˜– "Cedar" stylešœ™J™4J™1—unitšΟk ˜ Icodešœœ˜#Lšœ œ˜(Lšœœ2˜:Lšœœœ<˜LLšœœ ˜Lšœœ ˜Lšœœœ˜Lšœ œ˜*Lšœ œ˜)—šΟb œœ˜Lšœœœ2˜T—Lš˜Lšœœœ˜Lšœœœ˜Lšœœœ˜ Lšœœ˜š œœœœœ˜5Lšœœœœ˜%—L˜•StartOfExpansion -- [cmd: Commander.Handle] -- šž œœΠckœ˜ILšΟc‰™‰Lšœœœ ˜Lšœ=˜=Lšœ œ˜Lšœœ˜Lšœœ˜Lšœœœ˜Lšœ œœ˜Lšœœ˜šœ œœ˜)Jšœ œœœ!˜8šœ œ œœ˜$Jšœ+œ˜K—š œ œœœœ œ˜MLš œœœœœ œ˜MLšœ$œ˜(L˜LšœD˜DL˜,L˜/L˜ šœ œœ˜$Lšœœ˜Lšœ(˜*L˜—Lšœ"œœœ˜fš˜˜Lšœ)œ˜D——Lšœ˜—Lšœ˜—šœœ œ˜#Lšœ4œœœ˜yLšœ˜—šœœ˜šœœœ ˜šœ˜Lšœ-œ œ˜T—Lšœ˜——Jšœ˜—J˜šΟn œœœœœœœ œœœœœœ ˜¦Jšœ3™3Jšœœ˜*J˜Jšœ œ˜š˜Jš œœœœœ˜8šœ˜ šœ œ œ˜*šœœ˜J˜Jšœ˜J˜ J˜—J˜J˜—šœ˜šœœ˜Jšœ˜—šœ˜Jšœ˜——šœ˜ šœ œœœ˜;J˜J˜—šœ˜šœ˜šœ˜Jšœ=˜=—šœ˜J˜2——Jšœ˜šœ ˜J˜ —J˜—J˜——Jšœ˜—š˜Jšœœ˜ —Jšœ˜J˜—J˜šΟaœœ˜-Jšœœ˜Lšœœ˜šœ˜Jšœ œœ5˜E—Jš œœ?œ œ œœ˜ŠJ˜J˜—š‘œœ œœ œœœœ˜Jšœ œ ˜Jšœ œ˜'Jšœ œ˜J˜—Jšœ&˜(Jšœœœ˜CJ˜J˜—˜J˜—Jšœf˜fproc˜˜Mšœ ˜ Mšœœ˜ —M˜Mšœ=˜=—Mšœ˜Kšœ˜ Kšœ,˜,—…—:―