1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
############################################################################
#
# File: igrep.icn
#
# Subject: Program for string search similar to egrep
#
# Author: Robert J. Alexander
#
# Date: May 1, 1994
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# Program to emulate UNIX egrep, but using the enhanced regular
# expressions supported by regexp.icn. Options supported are nearly
# identical to those supported by egrep (no -b: print disk block
# number). There is one additional option, -E, to allow Icon-type
# (hence C-type) string escape sequences in the pattern string.
# BEWARE: when -E is used, backslashes that are meant to be processed
# in the regular expression context must be doubled. The following
# patterns are equivalent:
#
# without -E: '\bFred\b'
# with -E: '\\bFred\\b'
#
# To enable the -D option (intended mainly for debugging), the Icon
# Program Library file "ximage" must be linked with this program.
#
############################################################################
procedure Usage(n)
write(&errout,
"igrep -- emulates UNIX egrep\n_
Usage: igrep -Options [expression] filename..._
\n Options:_
\n c print count of matching lines rather than actual lines_
\n h don't display file names_
\n i ignore case of letters_
\n l list only the names of files containing matching lines_
\n n precede lines with line numbers_
\n s work silently -- display nothing_
\n v invert search to display only lines that don't match_
\n e expr useful if expressions starts with -_
\n E expr expresson containing Icon escape sequences_
\n f file take list of alternated expressions from \"file\""
# ,if \xdump then
# "\n D dump compiled pattern and quit" else ""
)
exit(n)
end
link options,regexp
procedure main(arg)
local compiledPattern
if *arg = 0 then Usage()
Options(arg)
compiledPattern := GetPattern(arg) |
{write(&errout,"Bad pattern ",image(Pattern)) ; exit(2)}
# if \Dump then (\xdump)(compiledPattern)
exit(ScanFiles(arg,compiledPattern))
end
global CountOnly,NoNames,NamesOnly,NumberLines,Out,Invert,Escapes,
Pattern,PatternFile,Dump,Re_LeftmostShortest
procedure Options(arg)
local opt
opt := options(arg,"chilnsve:E:f:DS")
CountOnly := opt["c"]
NoNames := opt["h"]
if \opt["i"] then Re_Filter := map
NamesOnly := opt["l"]
NumberLines := opt["n"]
Out := if \opt["s"] then &null else &output
Invert := opt["v"]
Pattern := \opt["e" | "E"]
Escapes := opt["E"]
PatternFile := opt["f"]
Dump := opt["D"]
Re_LeftmostShortest := (\opt["S"],&null) | 1
return opt
end
procedure GetPattern(arg)
local f,sep
if \PatternFile then {
f := open(PatternFile) |
stop("Can't open pattern file \"",PatternFile,"\"")
(/Pattern := "" & sep := "") | (sep := "|")
while Pattern ||:= sep || read(f) do sep := "|"
close(f)
}
/Pattern := get(arg)
if /Pattern then Usage(2)
return RePat(if \Escapes then istring(Pattern) else Pattern)
end
procedure ScanFiles(arg,pattern)
local errors,totalCount,fn,f,header,lineNbr,count,line,fLine,status,
lineNbrTag
totalCount := 0
if *arg = 0 then arg := ["-"]
every fn := !arg do {
f := if fn == "-" then &input else open(fn) |
{write(&errout,"Can't open \"",fn,"\" -- skipped") ; errors := 2 ;
next}
header := if \NoNames | *arg = 1 then &null else fn || ":"
lineNbr := count := 0
while line := read(f) do {
lineNbr +:= 1
fLine := (\Re_Filter)(line) | line
status := ReFind(pattern,fLine) | &null
status := if \Invert then (\status,&null) | 1
if \status then {
count +:= 1
if count = 1 & \NamesOnly then {write(\Out,fn) ; next}
lineNbrTag := if \NumberLines then lineNbr || ":" else &null
if not \(CountOnly | NamesOnly) then
write(\Out,header,lineNbrTag,line)
}
}
close(f)
if \CountOnly then write(header,count)
totalCount +:= count
}
## if \CountOnly & *arg > 1 then write(\Out,"** Total ** ",totalCount)
return \errors | if totalCount = 0 then 1 else 0
end
#
# istring() -- Procedure to convert a string containing special escape
# constructs, of the same format as Icon source language character
# strings, to their true string representation. Value returned is the
# string with special constructs converted to their respective
# characters.
#
procedure istring(s)
local r,c
r := ""
s ? {
while r ||:= tab(upto('\\')) do {
move(1)
r ||:= case c := map(move(1)) of {
"b": "\b" # backspace
"d": "\d" # delete (rubout)
"e": "\e" # escape (altmode)
"f": "\f" # formfeed
"l": "\l" # linefeed (newline)
"n": "\n" # newline (linefeed)
"r": "\r" # carriage return
"t": "\t" # horizontal tab
"v": "\v" # vertical tab
"x": istring_radix(16,2)# hexadecimal code
"^": char(ord(move(1)) % 32) | break # control code
default: { # either octal code or non-escaped character
if any('01234567',c) then { # if octal digit
move(-1)
istring_radix(8,3)
}
else c # else non-escaped character
} | break
}
}
r ||:= tab(0)
}
return r
end
procedure istring_radix(r,max)
local n,d,i,c
d := "0123456789abcdef"[1:r + 1]
n := 0
every 1 to max do {
c := move(1) | break
if not (i := find(map(c),d) - 1) then {
move(-1)
break
}
n := n * r + i
}
return char(n)
end
|