Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/builtin/look.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1992-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
/*
23
* look for lines beginning with <prefix> in sorted a sorted file
24
*
25
* David Korn
26
*/
27
28
#ifndef DICT_FILE
29
# define DICT_FILE "/usr/dict/words"
30
#endif
31
32
static const char usage[] =
33
"[-?@(#)$Id: look (AT&T Research) 2008-02-14 $\n]"
34
USAGE_LICENSE
35
"[+NAME?look - displays lines beginning with a given prefix]"
36
"[+DESCRIPTION?\blook\b displays all lines in the sorted \afile\a arguments"
37
" that begin with the given prefix \aprefix\a onto the standard output."
38
" The results are unspecified if any \afile\a is not sorted. If"
39
" \amax-prefix\a is specified then then records matching prefixes"
40
" in the inclusive range \aprefix\a..\amax-prefix\a are displayed.]"
41
" [+?If \afile\a is not specified, \blook\b uses the file \b"DICT_FILE"\b"
42
" and enables \b--dictionary\b and \b--ignorecase\b.]"
43
"[d:dictionary?`Phone dictionary order': only letters, digits, and"
44
" white space characters are significant in string comparisons.]"
45
"[f:fold|ignorecase?The search is case insensitive.]"
46
"[h:header?Skip flat file header (all lines up to first blank line.)]"
47
"\n"
48
"\nprefix [- max-prefix] [file ...]\n"
49
"\n"
50
"[+EXIT STATUS?]{"
51
" [+0?The specified \aprefix\a was found in the file.]"
52
" [+1?The specified \aprefix\a was not found in the file.]"
53
" [+>1?An error occurred.]"
54
"}"
55
"[+SEE ALSO?\bgrep\b(1), \bsort\b(1)]"
56
;
57
58
59
#include <cmd.h>
60
#include <ctype.h>
61
62
#define D_FLAG 0x01
63
#define F_FLAG 0x02
64
#define H_FLAG 0x04
65
66
#define CLOSE 256
67
68
#define EXTRACT(f,p,b,n) (((b)&&((f)&D_FLAG))?extract(p,b,n):(p))
69
70
static char*
71
extract(register const char* cp, char* buff, int len)
72
{
73
register char* bp = buff;
74
register char* ep = bp + len;
75
register int n;
76
77
while (n = *cp++)
78
{
79
if (n == '\n')
80
{
81
*bp = 0;
82
break;
83
}
84
if (isalnum(n) || isspace(n))
85
{
86
*bp++ = n;
87
if (bp >= ep)
88
break;
89
}
90
}
91
return buff;
92
}
93
94
static int
95
look(Sfio_t* fp, char* prefix, char* maxprefix, int flags)
96
{
97
Sfoff_t low;
98
Sfoff_t mid;
99
Sfoff_t high;
100
int n;
101
int len;
102
int found;
103
register char* cp;
104
register char* dp;
105
register char* buff = 0;
106
int (*compare)(const char*, const char*, size_t);
107
108
compare = (flags & F_FLAG) ? strncasecmp : strncmp;
109
if (flags & D_FLAG)
110
{
111
cp = dp = prefix;
112
while (n = *cp++)
113
if (isalnum(n) || isspace(n))
114
*dp++ = n;
115
*dp = 0;
116
len = strlen(prefix);
117
if (maxprefix)
118
{
119
cp = dp = maxprefix;
120
while (n = *cp++)
121
if (isalnum(n) || isspace(n))
122
*dp++ = n;
123
*dp = 0;
124
if ((n = strlen(maxprefix)) < len)
125
n = len;
126
}
127
else
128
n = len;
129
buff = (void*)malloc(n + 1);
130
}
131
else
132
n = len = strlen(prefix);
133
if (maxprefix && (*compare)(prefix, maxprefix, n) > 0)
134
return 1;
135
if (flags & H_FLAG)
136
while (sfgetr(fp, '\n', 0) && sfvalue(fp) > 1);
137
if ((low = sfseek(fp, (Sfoff_t)0, SEEK_CUR)) < 0 || (high = sfseek(fp, (Sfoff_t)0, SEEK_END)) <= 0)
138
{
139
found = 0;
140
n = 0;
141
while (cp = sfgetr(fp, '\n', 0))
142
{
143
n = (*compare)(prefix, EXTRACT(flags, cp, buff, len), len);
144
if (n <= 0)
145
break;
146
}
147
if (!cp)
148
return 1;
149
if (maxprefix)
150
{
151
prefix = maxprefix;
152
len = strlen(prefix);
153
if (n && (*compare)(prefix, EXTRACT(flags, cp, buff, len), len) >= 0)
154
n = 0;
155
}
156
found = !n;
157
while (!n)
158
{
159
sfprintf(sfstdout, "%.*s", sfvalue(fp), cp);
160
if (!(cp = sfgetr(fp, '\n', 0)))
161
break;
162
n = (*compare)(prefix, EXTRACT(flags, cp, buff, len), len);
163
if (maxprefix && n > 0)
164
n = 0;
165
}
166
}
167
else
168
{
169
while ((high - low) > (len + CLOSE))
170
{
171
mid = (low + high) / 2;
172
sfseek(fp, mid, SEEK_SET);
173
sfgetr(fp, '\n', 0);
174
mid = sftell(fp);
175
if (mid > high)
176
break;
177
if (!(cp = sfgetr(fp, '\n', 0)))
178
low = mid;
179
else
180
{
181
n = (*compare)(prefix, EXTRACT(flags, cp, buff, len), len);
182
if (n < 0)
183
high = mid - len;
184
else if (n > 0)
185
low = mid;
186
else
187
{
188
if((mid+=sfvalue(fp)) >= high)
189
break;
190
high = mid;
191
}
192
}
193
}
194
sfseek(fp, low, SEEK_SET);
195
while (low <= high)
196
{
197
if (!(cp = sfgetr(fp, '\n', 0)))
198
return 1;
199
n = (*compare)(prefix, EXTRACT(flags, cp, buff, len), len);
200
if (n <= 0)
201
break;
202
low += sfvalue(fp);
203
}
204
if (maxprefix)
205
{
206
prefix = maxprefix;
207
len = strlen(prefix);
208
if (n && (*compare)(prefix, EXTRACT(flags, cp, buff, len), len) >= 0)
209
n = 0;
210
}
211
found = !n;
212
while (!n)
213
{
214
sfprintf(sfstdout, "%.*s", sfvalue(fp), cp);
215
if (!(cp = sfgetr(fp, '\n', 0)))
216
break;
217
n = (*compare)(prefix, EXTRACT(flags, cp, buff, len), len);
218
if (maxprefix && n > 0)
219
n = 0;
220
}
221
if (buff)
222
free((void*)buff);
223
}
224
return !found;
225
}
226
227
int
228
b_look(int argc, char** argv, Shbltin_t* context)
229
{
230
register Sfio_t* fp;
231
register int n;
232
register int flags = 0;
233
char* ep = 0;
234
char* bp;
235
char* file;
236
237
static const char* dict[] = { DICT_FILE, "/usr/share/dict/words", "/usr/lib/dict/words" };
238
239
cmdinit(argc, argv, context, ERROR_CATALOG, 0);
240
for (;;)
241
{
242
switch (optget(argv, usage))
243
{
244
case 'd':
245
flags |= D_FLAG;
246
continue;
247
case 'f':
248
flags |= F_FLAG;
249
continue;
250
case 'h':
251
flags |= H_FLAG;
252
continue;
253
case ':':
254
error(2, "%s", opt_info.arg);
255
break;
256
case '?':
257
error(ERROR_usage(2), "%s", opt_info.arg);
258
break;
259
}
260
break;
261
}
262
argv += opt_info.index;
263
if (error_info.errors || !(bp = *argv++))
264
error(ERROR_usage(2), "%s", optusage(NiL));
265
if (file = *argv)
266
{
267
argv++;
268
if (streq(file, "-") && (ep = *argv))
269
{
270
argv++;
271
if (streq(ep, "-"))
272
{
273
file = ep;
274
ep = 0;
275
}
276
else if (file = *argv)
277
argv++;
278
}
279
}
280
if (!file)
281
{
282
for (n = 0; n < elementsof(dict); n++)
283
if (!eaccess(dict[n], R_OK))
284
{
285
file = (char*)dict[n];
286
break;
287
}
288
if (!file)
289
error(ERROR_system(1), "%s: not found", dict[0]);
290
flags |= (D_FLAG|F_FLAG);
291
}
292
n = 0;
293
do
294
{
295
if (streq(file, "-") || streq(file, "/dev/stdin") || streq(file, "/dev/fd/0"))
296
fp = sfstdin;
297
else if (!(fp = sfopen(NiL, file, "r")))
298
{
299
error(ERROR_system(0), "%s: cannot open", file);
300
continue;
301
}
302
if (look(fp, bp, ep, flags))
303
n = 1;
304
if (fp != sfstdin)
305
sfclose(fp);
306
} while (file = *argv++);
307
return n || error_info.errors;
308
}
309
310