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 <glenn.s.fowler@gmail.com> *
18 * David Korn <dgkorn@gmail.com> *
19 * *
20 ***********************************************************************/
21 #pragma prototyped
22 /*
23 * Glenn Fowler
24 * AT&T Research
25 *
26 * what
27 * my what is faster than yours.
28 * your who is what?
29 * no, they're different.
30 */
31
32 static const char usage[] =
33 "[-?\n@(#)$Id: what (AT&T Research) 2012-02-11 $\n]"
34 USAGE_LICENSE
35 "[+NAME?what - display binary identification strings]"
36 "[+DESCRIPTION?\bwhat\b searches the given files for all occurrences of"
37 " the identification pattern \b@(#)\b or \b$Id:\b and writes a line to"
38 " the standard output containing the text that follows until the first"
39 " occurrence of one of the following: \b\" < > \\ $ newline NUL\b. If no"
40 " \bfile\b is given or if a \bfile\b is \b-\b then the standard input is"
41 " read. The name of each input file, followed by a \b:\b, is also"
42 " written as a separate line to the standard output.]"
43
44 "[m:matched?Only list the names of files that match the identification"
45 " pattern.]"
46 "[s:first|single?Find only the first occurrence of the pattern in each file.]"
47
48 "\n"
49 "\n[ file ... ]\n"
50 "\n"
51
52 "[+EXIT STATUS]{"
53 " [+0?Some matches were found.]"
54 " [+1?Otherwise.]"
55 " [+2?Option error.]"
56 "}"
57 "[+SEE ALSO?\bident\b(1), \bgrep\b(1), \bstrings\b(1)]"
58 ;
59
60 #include <cmd.h>
61 #include <ctype.h>
62
63 #define HIT SSIZE_MAX
64
65 static struct
66 {
67 int hit;
68 int match;
69 int single;
70 size_t skip[UCHAR_MAX+1];
71 unsigned char prev[3];
72 } state;
73
74 static void
what(const char * file,Sfio_t * ip,Sfio_t * op)75 what(const char* file, Sfio_t* ip, Sfio_t* op)
76 {
77 register unsigned char* buf;
78 register size_t* skip;
79 register unsigned char* s;
80 register unsigned char* e;
81 register size_t index;
82 register size_t mid;
83 int intro;
84 unsigned char* b;
85 char* t;
86
87 if (intro = !state.match)
88 sfprintf(op, "%s:\n", file);
89 if (buf = (unsigned char*)sfreserve(ip, SF_UNBOUND, 0))
90 {
91 skip = state.skip;
92 if ((mid = sfvalue(ip)) <= (index = 3))
93 goto next;
94 e = buf + mid;
95 for (;;)
96 {
97 while ((index += skip[buf[index]]) < mid);
98 if (index < HIT)
99 {
100 next:
101 s = state.prev;
102 s[0] = s[1] = s[2] = 0;
103 switch (mid)
104 {
105 default:
106 s[0] = buf[mid - 3];
107 /*FALLTHROUGH*/
108 case 2:
109 s[1] = buf[mid - 2];
110 /*FALLTHROUGH*/
111 case 1:
112 s[2] = buf[mid - 1];
113 /*FALLTHROUGH*/
114 case 0:
115 break;
116 }
117 if (!(buf = (unsigned char*)sfreserve(ip, SF_UNBOUND, 0)))
118 goto done;
119 if ((mid = sfvalue(ip)) <= (index = 3))
120 goto next;
121 e = buf + mid;
122 switch (skip[buf[0]])
123 {
124 case HIT:
125 if (buf[0] == ')' && s[2] == '#' && s[1] == '(' && s[0] == '@' || buf[0] == ':' && s[2] == 'd' && s[1] == 'I' && s[0] == '$')
126 {
127 index = 0;
128 s = buf + 1;
129 goto hit;
130 }
131 break;
132 case 1:
133 if (buf[1] == ')' && buf[0] == '#' && s[2] == '(' && s[1] == '@' || buf[1] == ':' && buf[0] == 'd' && s[2] == 'I' && s[1] == '$')
134 {
135 index = 1;
136 s = buf + 2;
137 goto hit;
138 }
139 break;
140 case 2:
141 if (buf[2] == ')' && buf[1] == '#' && buf[0] == '(' && s[2] == '@' || buf[2] == ':' && buf[1] == 'd' && buf[0] == 'I' && s[2] == '$')
142 {
143 index = 2;
144 s = buf + 3;
145 goto hit;
146 }
147 break;
148 }
149 }
150 else
151 {
152 index -= HIT;
153 s = buf + index;
154 if (s[0] == ')' && s[-1] == '#' && s[-2] == '(' && s[-3] == '@' || s[0] == ':' && s[-1] == 'd' && s[-2] == 'I' && s[-3] == '$')
155 {
156 s++;
157 hit:
158 while (s < e)
159 {
160 while (s < e && (*s == ' ' || *s == '\t'))
161 s++;
162 if ((e - s) < 4)
163 break;
164 else if (s[0] == '@' && s[1] == '(' && s[2] == '#' && s[3] == ')')
165 s += 4;
166 else if (s[0] == '$' && s[1] == 'I' && s[2] == 'd' && s[3] == ':')
167 s += 4;
168 else
169 break;
170 }
171 b = s;
172 t = "\t";
173 if (!intro)
174 {
175 intro = 1;
176 sfprintf(op, "%s:\n", file);
177 }
178 for (;;)
179 {
180 if (s >= e)
181 {
182 sfprintf(op, "%s%-.*s", t, s - b, b);
183 t = "";
184 if (!(buf = (unsigned char*)sfreserve(ip, SF_UNBOUND, 0)))
185 goto list;
186 e = (s = b = buf) + (mid = sfvalue(ip));
187 }
188 else
189 {
190 switch (*s)
191 {
192 case 0:
193 case '<':
194 case '>':
195 case '"':
196 case '\\':
197 case '\n':
198 list:
199 if ((s - b) > 2 && *(s - 1) == '$' && *(s - 2) == ' ')
200 s -= 2;
201 if (s > b || !*t)
202 {
203 sfprintf(op, "%s%-.*s\n", t, s - b, b);
204 state.hit = 1;
205 if (state.single)
206 return;
207 if (!buf)
208 goto done;
209 }
210 break;
211 default:
212 s++;
213 continue;
214 }
215 break;
216 }
217 }
218 index = s - buf;
219 }
220 if ((index += 4) >= mid)
221 goto next;
222 }
223 }
224 }
225 done:
226 if (sfvalue(ip))
227 error(ERROR_system(0), "%s: read error", file);
228 }
229
230 int
b_what(int argc,char ** argv,Shbltin_t * context)231 b_what(int argc, char** argv, Shbltin_t* context)
232 {
233 register int n;
234 register char* s;
235 register Sfio_t* sp;
236
237 cmdinit(argc, argv, context, ERROR_CATALOG, 0);
238 state.hit = state.single = 0;
239 for (n = 0; n <= UCHAR_MAX; n++)
240 state.skip[n] = 4;
241 state.skip['@'] = state.skip['$'] = 3;
242 state.skip['('] = state.skip['I'] = 2;
243 state.skip['#'] = state.skip['d'] = 1;
244 state.skip[')'] = state.skip[':'] = HIT;
245 for (;;)
246 {
247 switch (optget(argv, usage))
248 {
249 case 'm':
250 state.match = 1;
251 continue;
252 case 's':
253 state.single = 1;
254 continue;
255 case ':':
256 error(2, "%s", opt_info.arg);
257 continue;
258 case '?':
259 error(ERROR_usage(2), "%s", opt_info.arg);
260 continue;
261 }
262 break;
263 }
264 argv += opt_info.index;
265 if (error_info.errors)
266 error(ERROR_usage(2), "%s", optusage(NiL));
267 if (s = *argv)
268 argv++;
269 do
270 {
271 if (!s || streq(s, "-"))
272 {
273 s = "/dev/stdin";
274 sp = sfstdin;
275 }
276 else if (!(sp = sfopen(NiL, s, "r")))
277 {
278 error(ERROR_system(0), "%s: cannot open", s);
279 continue;
280 }
281 what(s, sp, sfstdout);
282 if (sp != sfstdin)
283 sfclose(sp);
284 } while (s = *argv++);
285 return error_info.errors != 0 && state.hit;
286 }
287