DIRECTORY Ascii USING [Upper], Commander USING [CommandProc, Register], CommandTool USING [ParseToList], FS USING [defaultStreamOptions, EnumerateForNames, Error, NameProc, StreamOpen, StreamOptions], Grep, IO USING [Close, EndOfStream, GetLine, PutBlock, PutChar, PutF, PutF1, PutRope, PutText, STREAM], RefText USING [TrustTextAsRope], Rope USING [Concat, Equal, Fetch, Length, ROPE], RegularExpression USING [CreateFromRope, Finder, MalformedPattern, SearchRope], RuntimeError USING [BoundsFault]; GrepImpl: CEDAR PROGRAM IMPORTS Ascii, Commander, CommandTool, FS, IO, RefText, Rope, RegularExpression, RuntimeError EXPORTS Grep = { ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; binaryFileExtensions: LIST OF ROPE _ LIST[".bcd", ".press", ".ip", ".interpress", ".symbols", ".tipc", ".boot", ".versionmap", ".bittable"]; GrepCmd: Commander.CommandProc = { stdout: STREAM _ cmd.out; stdin: STREAM _ cmd.in; stderr: STREAM _ cmd.err; cmdLine: LIST OF ROPE; fileCount: INT _ 0; totalNumberOfHits, totalFileHits, totalFilesExamined: INT _ 0; pattern: RegularExpression.Finder; interrupt: REF BOOL _ NEW[BOOL _ FALSE]; openOptions: FS.StreamOptions _ FS.defaultStreamOptions; stopOnFirstError: BOOL; ignoreTiogaFormatting: BOOL _ FALSE; binaryFilesToo: BOOL; literal, word, ignoreCase: BOOL; switches: Grep.SwitchSettings; regularOutput: BOOL; UsageMessage: PROC [] = { IO.PutRope[stderr, "Usage: GREP [switches] \n"]; }; GrepFile: FS.NameProc = { file: STREAM; hits: INT; continue _ TRUE; IF ~binaryFilesToo THEN FOR l: LIST OF ROPE _ binaryFileExtensions, l.rest UNTIL l = NIL DO IF Rope.Equal[fullFName, l.first, FALSE] THEN RETURN; ENDLOOP; file _ FS.StreamOpen[fullFName, read, openOptions ! FS.Error => IF error.group # bug THEN { IO.PutF1[stderr, "** %g\n", [rope[error.explanation]]]; GOTO openFailed; }]; IF switches[verbose] THEN IO.PutF1[stderr, "Searching \"%g\"...", [rope[fullFName]]]; hits _ GrepStream[pattern: pattern, inStream: file, fileName: fullFName, outStream: stdout, switches: switches, interrupt: interrupt]; totalNumberOfHits _ totalNumberOfHits + hits; totalFileHits _ totalFileHits + (IF hits > 0 THEN 1 ELSE 0); totalFilesExamined _ totalFilesExamined+1; IO.Close[file]; continue _ ~interrupt^; EXITS openFailed => { interrupt^ _ interrupt^ OR stopOnFirstError; continue _ ~interrupt^; }; }; cmdLine _ CommandTool.ParseToList[cmd].list; [literal, cmdLine] _ GetSwitch["-pattern", cmdLine]; literal _ ~literal; [ignoreCase, cmdLine] _ GetSwitch["-caseSensitive", cmdLine]; ignoreCase _ ~ignoreCase; [word, cmdLine] _ GetSwitch["-word", cmdLine]; [stopOnFirstError, cmdLine] _ GetSwitch["-stopOnFirstError", cmdLine]; [binaryFilesToo, cmdLine] _ GetSwitch["-binaryFilesToo", cmdLine]; [ignoreTiogaFormatting, cmdLine] _ GetSwitch["-ignoreTiogaFormatting", cmdLine]; [switches, cmdLine] _ GetSwitches[cmdLine]; IF SwitchesLeft[cmdLine, stderr] THEN GOTO prematureExit; IF cmdLine = NIL THEN { UsageMessage[]; GOTO prematureExit; }; regularOutput _ RegularOutput[switches]; pattern _ RegularExpression.CreateFromRope[pattern: cmdLine.first, literal: literal, word: word, ignoreCase: ignoreCase ! RegularExpression.MalformedPattern => { IO.PutF1[stderr, "Syntax error in pattern \"%g\"\n", [rope[cmdLine.first]]]; GOTO prematureExit}]; cmdLine _ cmdLine.rest; -- Get rid of the pattern. openOptions _ FS.defaultStreamOptions; openOptions[tiogaRead] _ ignoreTiogaFormatting; IF cmdLine = NIL THEN totalNumberOfHits _ GrepStream[pattern: pattern, inStream: stdin, fileName: "Standard input", outStream: stdout, interrupt: interrupt, switches: switches] ELSE FOR l: LIST OF ROPE _ cmdLine, l.rest UNTIL l = NIL DO currentFiles: INT _ totalFilesExamined; pattern: ROPE _ DefaultToHighestGeneration[l.first]; FS.EnumerateForNames[pattern, GrepFile ! FS.Error => IF error.group # bug THEN { IO.PutF1[stderr, "** %g\n", [rope[error.explanation]] ]; LOOP}; ]; IF interrupt^ THEN GOTO prematureExit; IF currentFiles = totalFilesExamined THEN IO.PutF1[stderr, "** No files examined for '%g'\n", [rope[pattern]] ]; ENDLOOP; IF regularOutput OR switches[verbose] THEN IO.PutF[stderr, "Files examined: %g, files matched: %g, number of matches: %g\n", [integer[totalFilesExamined]], [integer[totalFileHits]], [integer[totalNumberOfHits]]]; EXITS prematureExit => NULL; }; GetSwitches: PUBLIC PROC[cmdLine: LIST OF Rope.ROPE, prefixLen: INT _ 2] RETURNS[ switches: Grep.SwitchSettings, remainder: LIST OF Rope.ROPE ] = { [switches[oncePerLine], remainder] _ GetSwitch["-oncePerLine", cmdLine, prefixLen]; [switches[fileNamesOnly], remainder] _ GetSwitch["-fileNamesOnly", remainder, prefixLen]; [switches[textOnly], remainder] _ GetSwitch["-textOnly", remainder, prefixLen]; [switches[positionsOnly], remainder] _ GetSwitch["-positionsOnly", remainder, prefixLen]; [switches[verbose], remainder] _ GetSwitch["-verbose", remainder, prefixLen] }; GetSwitch: PROC [switch: ROPE, cmdLine: LIST OF ROPE, prefixLen: INT _ 2] RETURNS [present: BOOL _ FALSE, remainder: LIST OF ROPE] = { IF cmdLine = NIL THEN RETURN; IF Prefix[switch, cmdLine.first, prefixLen] THEN { present _ TRUE; remainder _ cmdLine.rest; } ELSE { remainder _ cmdLine; FOR l: LIST OF ROPE _ cmdLine, l.rest UNTIL l.rest = NIL DO IF Prefix[switch, l.rest.first, prefixLen] THEN { l.rest _ l.rest.rest; present _ TRUE; RETURN }; ENDLOOP; }; }; SwitchesLeft: PROC [cmdLine: LIST OF ROPE, stderr: STREAM, switchChar: CHAR _ '-] RETURNS [switchesLeft: BOOL _ FALSE] = { FOR l: LIST OF ROPE _ cmdLine, l.rest UNTIL l = NIL DO IF Rope.Length[l.first] >= 1 THEN IF Rope.Fetch[l.first] = switchChar THEN { IO.PutF1[stderr, "Invalid switch: \"%g\"\n", [rope[l.first]]]; switchesLeft _ TRUE; }; ENDLOOP; }; Prefix: PROC [r1, r2: ROPE, length: INT, ignoreCase: BOOL _ TRUE] RETURNS [BOOL] = { r2Len: INT _ r2.Length[]; r1Len: INT _ r1.Length[]; IF r1Len < length THEN ERROR; IF r2Len > r1Len OR r2Len < length THEN RETURN[FALSE]; IF ~ignoreCase THEN FOR i: INT IN [0..r2Len) DO IF r1.Fetch[i] # r2.Fetch[i] THEN RETURN[FALSE]; ENDLOOP ELSE FOR i: INT IN [0..r2Len) DO IF Ascii.Upper[r1.Fetch[i]] # Ascii.Upper[r2.Fetch[i]] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; DefaultToHighestGeneration: PROC [filePattern: ROPE] RETURNS [ROPE] = { len: INT _ Rope.Length[filePattern]; bang: INT _ len; star: INT _ len; dot: INT _ len; pos: INT _ len; WHILE pos > 0 DO c: CHAR _ Rope.Fetch[filePattern, pos _ pos - 1]; SELECT c FROM '! => bang _ pos; '. => {dot _ pos; EXIT}; '* => IF star = len THEN star _ pos; '>, '] => EXIT; ENDCASE; ENDLOOP; SELECT TRUE FROM dot = len AND star = len AND bang = len => filePattern _ Rope.Concat[filePattern, ".mesa!h"]; bang = len => filePattern _ Rope.Concat[filePattern, "!h"]; ENDCASE; RETURN[filePattern]; }; RegularOutput: PUBLIC PROC[switches: Grep.SwitchSettings] RETURNS[ yes: BOOL ] = { yes _ ~(switches[fileNamesOnly] OR switches[textOnly] OR switches[positionsOnly] OR switches[verbose]) }; GrepStream: PUBLIC PROC [pattern: RegularExpression.Finder, inStream, outStream: IO.STREAM, switches: Grep.SwitchSettings, fileName: Rope.ROPE, interrupt: REF BOOL] RETURNS [numberOfHits: INT] = { found: BOOL; lineTooLongError: BOOL _ FALSE; at, atEnd, before, after: INT; regularOutput: BOOL = RegularOutput[switches]; position: INT _ 0; start: INT; line: REF TEXT _ NEW[TEXT[200]]; numberOfHits _ 0; DO line _ IO.GetLine[inStream, line ! IO.EndOfStream => EXIT; RuntimeError.BoundsFault => { IF ~lineTooLongError THEN IO.PutF[outStream, "Line too long in %g (%g). Line skipped.\n", [rope[fileName]], [integer[position]]]; lineTooLongError _ TRUE; LOOP; }; ]; start _ 0; DO [found, at, atEnd, before, after] _ RegularExpression.SearchRope[pattern, RefText.TrustTextAsRope[line], start, line.length, interrupt]; IF ~found THEN EXIT; IF switches[verbose] AND numberOfHits = 0 THEN IO.PutRope[outStream, "\n"]; numberOfHits _ numberOfHits + 1; SELECT TRUE FROM switches[fileNamesOnly] => { IO.PutF1[outStream, "%g\n", [rope[fileName]]]; GOTO prematureExit; }; switches[textOnly] => IO.PutF1[outStream, "%g\n", [text[line]]]; switches[positionsOnly] => IO.PutF[outStream, "%g (%g)\n", [rope[fileName]], [integer[position+at]]]; regularOutput => { IF numberOfHits = 1 THEN IO.PutF1[outStream, "%g\n", [rope[fileName]]]; IO.PutF1[outStream, " (%g): ", [integer[position+at]]]; IF line.length > 50 THEN { start: INT _ MAX[0, at-20]; end: INT _ MIN[line.length, start+50]; len: INT _ end-start; dots: BOOL _ end < line.length; IF start > 0 THEN IO.PutRope[outStream, "..."]; IO.PutBlock[self: outStream, block: line, startIndex: start, count: len]; IF dots THEN IO.PutRope[outStream, "..."]; } ELSE IO.PutText[outStream, line]; IO.PutChar[outStream, '\n]; }; switches[verbose] => IO.PutF[outStream, "%g (%g): %g\n", [rope[fileName]], [integer[position+at]], [text[line]]]; ENDCASE => ERROR; start _ atEnd; IF switches[oncePerLine] THEN EXIT; ENDLOOP; position _ position + line.length + 1; REPEAT prematureExit => NULL; ENDLOOP; IF switches[verbose] THEN IF numberOfHits = 0 THEN IO.PutRope[outStream, "no matches found.\n"] ELSE IO.PutF1[outStream, "Matched %g times.\n", [integer[numberOfHits]]] }; Commander.Register[ key: "Grep", proc: GrepCmd, doc: "Searches files for lines that match a pattern (uninterpreted)", interpreted: FALSE]; Commander.Register[ key: "GrepI", proc: GrepCmd, doc: "Searches files for lines that match a pattern (interpreted)", interpreted: TRUE]; }.  GrepImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) June 1, 1985 10:03:13 am PDT Donahue, July 16, 1985 8:29:50 am PDT John Larson, September 22, 1985 9:57:21 pm PDT Peter Kessler November 7, 1985 11:35:09 am PST Tim Diebert: December 31, 1985 8:59:11 am PST Bob Hagmann February 6, 1986 2:16:28 pm PST Callable from the command interpreter. Expects a list of file names as arguments, and counts the number of words in the indicated files. Interesting pattern options Display options. Match the pattern against the next line Keep matching the pattern until it fails. Bob Hagmann February 6, 1986 2:16:28 pm PST Added check in GrepStream to avoid bounds errors for very long lines changes to: GrepStream, DIRECTORY, GrepImpl Κ t˜codešœ ™ Kšœ Οmœ1™Kšœ"˜"Kš œ žœžœžœžœžœ˜(Kšœ žœžœ˜8Kšœžœ˜Kšœžœžœ˜$Kšœžœ˜šœžœ˜ Kšœ™—Kšœ˜šœžœ˜Kšœ™—šΟn œžœ˜KšžœC˜EK˜—šŸœžœ ˜Kšœžœ˜ Kšœžœ˜ Kšœ žœ˜šžœž˜š žœžœžœžœ žœžœž˜CKšžœ žœžœžœ˜5Kšžœ˜——šœžœ(˜1šœžœ žœžœ˜)Kšžœ5˜7Kšžœ ˜K˜——Kšžœžœžœ9˜UKšœ†˜†Kšœ-˜-Kšœ!žœ žœžœ˜Kšœžœ˜K˜——Kšžœ˜—K˜K˜—š’œžœ žœ žœžœžœžœžœ˜TKšœžœ˜Kšœžœ˜Kšžœžœžœ˜Kš žœžœžœžœžœ˜6šžœ ˜šžœ˜šžœžœžœ ž˜Kšžœžœžœžœ˜0Kšž˜——šž˜šžœžœžœ ž˜Kšžœ5žœžœžœ˜JKšžœ˜———Kšžœžœ˜ K˜K˜—š ’œžœžœžœžœ˜GKšœžœ˜$Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜šžœ ž˜Kšœžœ*˜1šžœž˜ Kšœ˜Kšœžœ˜Kšœžœ žœ ˜$Kšœ žœ˜Kšžœ˜—Kšžœ˜—šžœžœž˜šœ žœ žœ˜*Kšœ2˜2—šœ ˜ Kšœ-˜-—Kšžœ˜—Kšžœ˜K˜K˜—š ’ œžœžœ žœžœ˜RKšœ žœžœžœ˜fKšœ˜—K˜šΠbn œžœžœ:žœžœ0žœ žœžœžœžœ˜ΔKšœžœ˜ Kšœžœžœ˜Kšœžœ˜Kšœžœ˜.Kšœ žœ˜Kšœžœ˜ Kš œžœžœžœžœ˜ Kšœ˜šž˜Kšœ'™'šœžœ˜"Kšžœž˜šœ˜Kšžœžœžœf˜‚Kšœžœ˜Kšžœ˜K˜——Kšœ˜K˜ šž˜Kšœ)™)šœ$˜$Kšœd˜d—Kšžœžœžœ˜šžœžœž˜.Kšžœ˜—Kšœ ˜ šžœžœž˜šœ˜Kšžœ,˜.Kšžœ˜K˜—šœ˜Kšžœ(˜*—šœ˜KšžœH˜J—˜šžœž˜Kšžœ,˜.—Kšžœ6˜8šžœ˜šžœ˜Kšœžœžœ ˜Kšœžœžœ˜&Kšœžœ ˜Kšœžœ˜Kšžœ žœžœ˜/KšžœG˜IKšžœžœžœ˜*K˜—šž˜Kšžœ˜——Kšžœ˜K˜—KšœžœZ˜qKšžœžœ˜—K˜Kšžœžœžœ˜#Kšžœ˜—K˜&šž˜Kšœžœ˜—Kšžœ˜—šžœž˜Kšžœžœžœ*˜EKšžœžœD˜K——K˜šœ˜Kšœ ˜ Kšœ˜KšœE˜EKšœ žœ˜K˜—šœ˜Kšœ ˜ Kšœ˜KšœC˜CKšœ žœ˜—K˜K˜K˜K˜™+KšœD™DKšœ Οr™+—K™K™K™—…—$Δ4B