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