xref: /dragonfly/usr.bin/rpcgen/rpc_scan.c (revision ef3ac1d1)
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  *
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  *
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  *
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  *
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  *
29  * @(#)rpc_scan.c	1.13	93/07/05 SMI; 1.11 89/02/22 (C) 1987 SMI
30  * $FreeBSD: src/usr.bin/rpcgen/rpc_scan.c,v 1.10 2005/11/13 21:17:24 dwmalone Exp $
31  * $DragonFly: src/usr.bin/rpcgen/rpc_scan.c,v 1.5 2008/10/16 01:52:33 swildner Exp $
32  */
33 
34 /*
35  * rpc_scan.c, Scanner for the RPC protocol compiler
36  * Copyright (C) 1987, Sun Microsystems, Inc.
37  */
38 
39 #include <sys/types.h>
40 
41 #include <sys/wait.h>
42 #include <stdio.h>
43 #include <ctype.h>
44 #include <string.h>
45 #include "rpc_parse.h"
46 #include "rpc_scan.h"
47 #include "rpc_util.h"
48 
49 #define startcomment(where) (where[0] == '/' && where[1] == '*')
50 #define endcomment(where) (where[-1] == '*' && where[0] == '/')
51 
52 static int pushed = 0;	/* is a token pushed */
53 static token lasttok;	/* last token, if pushed */
54 
55 static void	unget_token(token *);
56 static void	findstrconst(char **, const char **);
57 static void	findchrconst(char **, const char **);
58 static void	findconst(char **, const char **);
59 static void	findkind(char **, token *);
60 static int	cppline(char *);
61 static int	directive(char *);
62 static void	printdirective(char *);
63 static void	docppline(char *, int *, const char **);
64 
65 /*
66  * scan expecting 1 given token
67  */
68 void
69 scan(tok_kind expect, token *tokp)
70 {
71 	get_token(tokp);
72 	if (tokp->kind != expect)
73 		expected1(expect);
74 }
75 
76 /*
77  * scan expecting any of the 2 given tokens
78  */
79 void
80 scan2(tok_kind expect1, tok_kind expect2, token *tokp)
81 {
82 	get_token(tokp);
83 	if (tokp->kind != expect1 && tokp->kind != expect2)
84 		expected2(expect1, expect2);
85 }
86 
87 /*
88  * scan expecting any of the 3 given token
89  */
90 void
91 scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp)
92 {
93 	get_token(tokp);
94 	if (tokp->kind != expect1 && tokp->kind != expect2 &&
95 	    tokp->kind != expect3)
96 		expected3(expect1, expect2, expect3);
97 }
98 
99 /*
100  * scan expecting a constant, possibly symbolic
101  */
102 void
103 scan_num(token *tokp)
104 {
105 	get_token(tokp);
106 	switch (tokp->kind) {
107 	case TOK_IDENT:
108 		break;
109 	default:
110 		error("constant or identifier expected");
111 	}
112 }
113 
114 /*
115  * Peek at the next token
116  */
117 void
118 peek(token *tokp)
119 {
120 	get_token(tokp);
121 	unget_token(tokp);
122 }
123 
124 /*
125  * Peek at the next token and scan it if it matches what you expect
126  */
127 int
128 peekscan(tok_kind expect, token *tokp)
129 {
130 	peek(tokp);
131 	if (tokp->kind == expect) {
132 		get_token(tokp);
133 		return(1);
134 	}
135 	return(0);
136 }
137 
138 /*
139  * Get the next token, printing out any directive that are encountered.
140  */
141 void
142 get_token(token *tokp)
143 {
144 	int commenting;
145 	int stat = 0;
146 
147 	if (pushed) {
148 		pushed = 0;
149 		*tokp = lasttok;
150 		return;
151 	}
152 	commenting = 0;
153 	for (;;) {
154 		if (*where == 0) {
155 			for (;;) {
156 				if (!fgets(curline, MAXLINESIZE, fin)) {
157 					tokp->kind = TOK_EOF;
158 					/*
159 					 * now check if cpp returned
160 					 * non NULL value
161 					 */
162 					waitpid(childpid, &stat, WUNTRACED);
163 					if (stat > 0) {
164 						/*
165 						 * Set return value from rpcgen
166 						 */
167 						nonfatalerrors = stat >> 8;
168 					}
169 					*where = 0;
170 					return;
171 				}
172 				linenum++;
173 				if (commenting)
174 					break;
175 				else if (cppline(curline))
176 					docppline(curline, &linenum,
177 						  &infilename);
178 				else if (directive(curline))
179 					printdirective(curline);
180 				else
181 					break;
182 			}
183 			where = curline;
184 		} else if (isspace(*where)) {
185 			while (isspace(*where))
186 				where++;	/* eat */
187 		} else if (commenting) {
188 			for (where++; *where; where++) {
189 				if (endcomment(where)) {
190 					where++;
191 					commenting--;
192 					break;
193 				}
194 			}
195 		} else if (startcomment(where)) {
196 			where += 2;
197 			commenting++;
198 		} else {
199 			break;
200 		}
201 	}
202 
203 	/*
204 	 * 'where' is not whitespace, comment or directive Must be a token!
205 	 */
206 	switch (*where) {
207 	case ':':
208 		tokp->kind = TOK_COLON;
209 		where++;
210 		break;
211 	case ';':
212 		tokp->kind = TOK_SEMICOLON;
213 		where++;
214 		break;
215 	case ',':
216 		tokp->kind = TOK_COMMA;
217 		where++;
218 		break;
219 	case '=':
220 		tokp->kind = TOK_EQUAL;
221 		where++;
222 		break;
223 	case '*':
224 		tokp->kind = TOK_STAR;
225 		where++;
226 		break;
227 	case '[':
228 		tokp->kind = TOK_LBRACKET;
229 		where++;
230 		break;
231 	case ']':
232 		tokp->kind = TOK_RBRACKET;
233 		where++;
234 		break;
235 	case '{':
236 		tokp->kind = TOK_LBRACE;
237 		where++;
238 		break;
239 	case '}':
240 		tokp->kind = TOK_RBRACE;
241 		where++;
242 		break;
243 	case '(':
244 		tokp->kind = TOK_LPAREN;
245 		where++;
246 		break;
247 	case ')':
248 		tokp->kind = TOK_RPAREN;
249 		where++;
250 		break;
251 	case '<':
252 		tokp->kind = TOK_LANGLE;
253 		where++;
254 		break;
255 	case '>':
256 		tokp->kind = TOK_RANGLE;
257 		where++;
258 		break;
259 
260 	case '"':
261 		tokp->kind = TOK_STRCONST;
262 		findstrconst(&where, &tokp->str);
263 		break;
264 	case '\'':
265 		tokp->kind = TOK_CHARCONST;
266 		findchrconst(&where, &tokp->str);
267 		break;
268 
269 	case '-':
270 	case '0':
271 	case '1':
272 	case '2':
273 	case '3':
274 	case '4':
275 	case '5':
276 	case '6':
277 	case '7':
278 	case '8':
279 	case '9':
280 		tokp->kind = TOK_IDENT;
281 		findconst(&where, &tokp->str);
282 		break;
283 
284 	default:
285 		if (!(isalpha(*where) || *where == '_')) {
286 			char buf[100];
287 			char *p;
288 
289 			s_print(buf, "illegal character in file: ");
290 			p = buf + strlen(buf);
291 			if (isprint(*where)) {
292 				s_print(p, "%c", *where);
293 			} else {
294 				s_print(p, "%d", *where);
295 			}
296 			error(buf);
297 		}
298 		findkind(&where, tokp);
299 		break;
300 	}
301 }
302 
303 static void
304 unget_token(token *tokp)
305 {
306 	lasttok = *tokp;
307 	pushed = 1;
308 }
309 
310 static void
311 findstrconst(char **str, const char **val)
312 {
313 	char *p;
314 	char *tmp;
315 	int size;
316 
317 	p = *str;
318 	do {
319 		p++;
320 	} while (*p && *p != '"');
321 	if (*p == 0)
322 		error("unterminated string constant");
323 	p++;
324 	size = p - *str;
325 	tmp = xmalloc(size + 1);
326 	strncpy(tmp, *str, size);
327 	tmp[size] = 0;
328 	*val = tmp;
329 	*str = p;
330 }
331 
332 static void
333 findchrconst(char **str, const char **val)
334 {
335 	char *p;
336 	char *tmp;
337 	int size;
338 
339 	p = *str;
340 	do {
341 		p++;
342 	} while (*p && *p != '\'');
343 	if (*p == 0)
344 		error("unterminated string constant");
345 	p++;
346 	size = p - *str;
347 	if (size != 3)
348 		error("empty char string");
349 	tmp = xmalloc(size + 1);
350 	strncpy(tmp, *str, size);
351 	tmp[size] = 0;
352 	*val = tmp;
353 	*str = p;
354 }
355 
356 static void
357 findconst(char **str, const char **val)
358 {
359 	char *p;
360 	char *tmp;
361 	int size;
362 
363 	p = *str;
364 	if (*p == '0' && *(p + 1) == 'x') {
365 		p++;
366 		do {
367 			p++;
368 		} while (isxdigit(*p));
369 	} else {
370 		do {
371 			p++;
372 		} while (isdigit(*p));
373 	}
374 	size = p - *str;
375 	tmp = xmalloc(size + 1);
376 	strncpy(tmp, *str, size);
377 	tmp[size] = 0;
378 	*val = tmp;
379 	*str = p;
380 }
381 
382 static token symbols[] = {
383 			  {TOK_CONST, "const"},
384 			  {TOK_UNION, "union"},
385 			  {TOK_SWITCH, "switch"},
386 			  {TOK_CASE, "case"},
387 			  {TOK_DEFAULT, "default"},
388 			  {TOK_STRUCT, "struct"},
389 			  {TOK_TYPEDEF, "typedef"},
390 			  {TOK_ENUM, "enum"},
391 			  {TOK_OPAQUE, "opaque"},
392 			  {TOK_BOOL, "bool"},
393 			  {TOK_VOID, "void"},
394 			  {TOK_CHAR, "char"},
395 			  {TOK_INT, "int"},
396 			  {TOK_UNSIGNED, "unsigned"},
397 			  {TOK_SHORT, "short"},
398 			  {TOK_LONG, "long"},
399 			  {TOK_HYPER, "hyper"},
400 			  {TOK_FLOAT, "float"},
401 			  {TOK_DOUBLE, "double"},
402 			  {TOK_QUAD, "quadruple"},
403 			  {TOK_STRING, "string"},
404 			  {TOK_PROGRAM, "program"},
405 			  {TOK_VERSION, "version"},
406 			  {TOK_EOF, "??????"},
407 };
408 
409 static void
410 findkind(char **mark, token *tokp)
411 {
412 	int len;
413 	token *s;
414 	char *str, *tmp;
415 
416 	str = *mark;
417 	for (s = symbols; s->kind != TOK_EOF; s++) {
418 		len = strlen(s->str);
419 		if (strncmp(str, s->str, len) == 0) {
420 			if (!isalnum(str[len]) && str[len] != '_') {
421 				tokp->kind = s->kind;
422 				tokp->str = s->str;
423 				*mark = str + len;
424 				return;
425 			}
426 		}
427 	}
428 	tokp->kind = TOK_IDENT;
429 	for (len = 0; isalnum(str[len]) || str[len] == '_'; len++);
430 	tmp = xmalloc(len + 1);
431 	strncpy(tmp, str, len);
432 	tmp[len] = 0;
433 	tokp->str = tmp;
434 	*mark = str + len;
435 }
436 
437 static int
438 cppline(char *line)
439 {
440 	return(line == curline && *line == '#');
441 }
442 
443 static int
444 directive(char *line)
445 {
446 	return(line == curline && *line == '%');
447 }
448 
449 static void
450 printdirective(char *line)
451 {
452 	f_print(fout, "%s", line + 1);
453 }
454 
455 static void
456 docppline(char *line, int *lineno, const char **fname)
457 {
458 	char *file;
459 	int num;
460 	char *p;
461 
462 	line++;
463 	while (isspace(*line))
464 		line++;
465 	num = atoi(line);
466 	while (isdigit(*line))
467 		line++;
468 	while (isspace(*line))
469 		line++;
470 	if (*line != '"')
471 		error("preprocessor error");
472 	line++;
473 	p = file = xmalloc(strlen(line) + 1);
474 	while (*line && *line != '"')
475 		*p++ = *line++;
476 	if (*line == 0)
477 		error("preprocessor error");
478 	*p = 0;
479 	if (*file == 0)
480 		*fname = NULL;
481 	else
482 		*fname = file;
483 	*lineno = num - 1;
484 }
485