xref: /netbsd-src/usr.bin/rpcgen/rpc_scan.c (revision 6cf6fe02a981b55727c49c3d37b0d8191a98c0ee)
1 /*	$NetBSD: rpc_scan.c,v 1.13 2013/12/15 00:40:17 christos Exp $	*/
2 /*
3  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4  * unrestricted use provided that this legend is included on all tape
5  * media and as a part of the software program in whole or part.  Users
6  * may copy or modify Sun RPC without charge, but are not authorized
7  * to license or distribute it to anyone else except as part of a product or
8  * program developed by the user or with the express written consent of
9  * Sun Microsystems, Inc.
10  *
11  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14  *
15  * Sun RPC is provided with no support and without any obligation on the
16  * part of Sun Microsystems, Inc. to assist in its use, correction,
17  * modification or enhancement.
18  *
19  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21  * OR ANY PART THEREOF.
22  *
23  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24  * or profits or other special, indirect and consequential damages, even if
25  * Sun has been advised of the possibility of such damages.
26  *
27  * Sun Microsystems, Inc.
28  * 2550 Garcia Avenue
29  * Mountain View, California  94043
30  */
31 
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35 
36 #include <sys/cdefs.h>
37 #if defined(__RCSID) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)rpc_scan.c 1.11 89/02/22 (C) 1987 SMI";
40 #else
41 __RCSID("$NetBSD: rpc_scan.c,v 1.13 2013/12/15 00:40:17 christos Exp $");
42 #endif
43 #endif
44 
45 /*
46  * rpc_scan.c, Scanner for the RPC protocol compiler
47  * Copyright (C) 1987, Sun Microsystems, Inc.
48  */
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <ctype.h>
52 #include <string.h>
53 #include "rpc_scan.h"
54 #include "rpc_parse.h"
55 #include "rpc_util.h"
56 
57 #define startcomment(where) (where[0] == '/' && where[1] == '*')
58 #define endcomment(where) (where[-1] == '*' && where[0] == '/')
59 
60 static void unget_token(token *);
61 static void findstrconst(char **, const char **);
62 static void findchrconst(char **, const char **);
63 static void findconst(char **, const char **);
64 static void findkind(char **, token *);
65 static int cppline(const char *);
66 static int directive(const char *);
67 static void printdirective(const char *);
68 static void docppline(char *, int *, const char **);
69 
70 static int pushed = 0;		/* is a token pushed */
71 static token lasttok;		/* last token, if pushed */
72 
73 /*
74  * scan expecting 1 given token
75  */
76 void
77 scan(tok_kind expect, token *tokp)
78 {
79 	get_token(tokp);
80 	if (tokp->kind != expect) {
81 		expected1(expect);
82 	}
83 }
84 /*
85  * scan expecting any of the 2 given tokens
86  */
87 void
88 scan2(tok_kind expect1, tok_kind expect2, token *tokp)
89 {
90 	get_token(tokp);
91 	if (tokp->kind != expect1 && tokp->kind != expect2) {
92 		expected2(expect1, expect2);
93 	}
94 }
95 /*
96  * scan expecting any of the 3 given token
97  */
98 void
99 scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp)
100 {
101 	get_token(tokp);
102 	if (tokp->kind != expect1 && tokp->kind != expect2
103 	    && tokp->kind != expect3) {
104 		expected3(expect1, expect2, expect3);
105 	}
106 }
107 /*
108  * scan expecting a constant, possibly symbolic
109  */
110 void
111 scan_num(token *tokp)
112 {
113 	get_token(tokp);
114 	switch (tokp->kind) {
115 	case TOK_IDENT:
116 		break;
117 	default:
118 		error("constant or identifier expected");
119 	}
120 }
121 /*
122  * Peek at the next token
123  */
124 void
125 peek(token *tokp)
126 {
127 	get_token(tokp);
128 	unget_token(tokp);
129 }
130 /*
131  * Peek at the next token and scan it if it matches what you expect
132  */
133 int
134 peekscan(tok_kind expect, token *tokp)
135 {
136 	peek(tokp);
137 	if (tokp->kind == expect) {
138 		get_token(tokp);
139 		return (1);
140 	}
141 	return (0);
142 }
143 /*
144  * Get the next token, printing out any directive that are encountered.
145  */
146 void
147 get_token(token *tokp)
148 {
149 	int     commenting;
150 
151 	if (pushed) {
152 		pushed = 0;
153 		*tokp = lasttok;
154 		return;
155 	}
156 	commenting = 0;
157 	for (;;) {
158 		if (*where == 0) {
159 			for (;;) {
160 				if (!fgets(curline, MAXLINESIZE, fin)) {
161 					tokp->kind = TOK_EOF;
162 					*where = 0;
163 					return;
164 				}
165 				linenum++;
166 				if (commenting) {
167 					break;
168 				} else
169 					if (cppline(curline)) {
170 						docppline(curline, &linenum,
171 						    &infilename);
172 					} else
173 						if (directive(curline)) {
174 							printdirective(curline);
175 						} else {
176 							break;
177 						}
178 			}
179 			where = curline;
180 		} else
181 			if (isspace((unsigned char)*where)) {
182 				while (isspace((unsigned char)*where)) {
183 					where++;	/* eat */
184 				}
185 			} else
186 				if (commenting) {
187 					for (where++; *where; where++) {
188 						if (endcomment(where)) {
189 							where++;
190 							commenting--;
191 							break;
192 						}
193 					}
194 				} else
195 					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((unsigned char)*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((unsigned char)*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 	int     size;
315 	char *tmp;
316 
317 	p = *str;
318 	do {
319 		p++;
320 	} while (*p && *p != '"');
321 	if (*p == 0) {
322 		error("unterminated string constant");
323 	}
324 	p++;
325 	size = p - *str;
326 	tmp = alloc(size + 1);
327 	(void) strncpy(tmp, *str, size);
328 	tmp[size] = 0;
329 	*val = tmp;
330 	*str = p;
331 }
332 
333 static void
334 findchrconst(char **str, const char **val)
335 {
336 	char *p;
337 	int     size;
338 	char *tmp;
339 
340 	p = *str;
341 	do {
342 		p++;
343 	} while (*p && *p != '\'');
344 	if (*p == 0) {
345 		error("unterminated string constant");
346 	}
347 	p++;
348 	size = p - *str;
349 	if (size != 3) {
350 		error("empty char string");
351 	}
352 	tmp = alloc(size + 1);
353 	(void) strncpy(tmp, *str, size);
354 	tmp[size] = 0;
355 	*val = tmp;
356 	*str = p;
357 }
358 
359 static void
360 findconst(char **str, const char **val)
361 {
362 	char *p;
363 	int     size;
364 	char *tmp;
365 
366 	p = *str;
367 	if (*p == '0' && *(p + 1) == 'x') {
368 		p++;
369 		do {
370 			p++;
371 		} while (isxdigit((unsigned char)*p));
372 	} else {
373 		do {
374 			p++;
375 		} while (isdigit((unsigned char)*p));
376 	}
377 	size = p - *str;
378 	tmp = alloc(size + 1);
379 	(void) strncpy(tmp, *str, size);
380 	tmp[size] = 0;
381 	*val = tmp;
382 	*str = p;
383 }
384 
385 static const token symbols[] = {
386 	{TOK_CONST, "const"},
387 	{TOK_UNION, "union"},
388 	{TOK_SWITCH, "switch"},
389 	{TOK_CASE, "case"},
390 	{TOK_DEFAULT, "default"},
391 	{TOK_STRUCT, "struct"},
392 	{TOK_TYPEDEF, "typedef"},
393 	{TOK_ENUM, "enum"},
394 	{TOK_OPAQUE, "opaque"},
395 	{TOK_BOOL, "bool"},
396 	{TOK_VOID, "void"},
397 	{TOK_CHAR, "char"},
398 	{TOK_INT, "int"},
399 	{TOK_UNSIGNED, "unsigned"},
400 	{TOK_SHORT, "short"},
401 	{TOK_LONG, "long"},
402 	{TOK_HYPER, "hyper"},
403 	{TOK_FLOAT, "float"},
404 	{TOK_DOUBLE, "double"},
405 	{TOK_QUAD, "quadruple"},
406 	{TOK_STRING, "string"},
407 	{TOK_PROGRAM, "program"},
408 	{TOK_VERSION, "version"},
409 	{TOK_EOF, "??????"},
410 };
411 
412 static void
413 findkind(char **mark, token *tokp)
414 {
415 	int     len;
416 	const token *s;
417 	char *str;
418 	char *tmp;
419 
420 	str = *mark;
421 	for (s = symbols; s->kind != TOK_EOF; s++) {
422 		len = strlen(s->str);
423 		if (strncmp(str, s->str, len) == 0) {
424 			if (!isalnum((unsigned char)str[len]) &&
425 			    str[len] != '_') {
426 				tokp->kind = s->kind;
427 				tokp->str = s->str;
428 				*mark = str + len;
429 				return;
430 			}
431 		}
432 	}
433 	tokp->kind = TOK_IDENT;
434 	for (len = 0; isalnum((unsigned char)str[len]) ||
435 	    str[len] == '_'; len++);
436 	tmp = alloc(len + 1);
437 	(void) strncpy(tmp, str, len);
438 	tmp[len] = 0;
439 	tokp->str = tmp;
440 	*mark = str + len;
441 }
442 
443 static int
444 cppline(const char *line)
445 {
446 	return (line == curline && *line == '#');
447 }
448 
449 static int
450 directive(const char *line)
451 {
452 	return (line == curline && *line == '%');
453 }
454 
455 static void
456 printdirective(const char *line)
457 {
458 	f_print(fout, "%s", line + 1);
459 }
460 
461 static void
462 docppline(char *line, int *lineno, const char **fname)
463 {
464 	char   *file;
465 	int     num;
466 	char   *p;
467 
468 	line++;
469 	while (isspace((unsigned char)*line)) {
470 		line++;
471 	}
472 	num = atoi(line);
473 	while (isdigit((unsigned char)*line)) {
474 		line++;
475 	}
476 	while (isspace((unsigned char)*line)) {
477 		line++;
478 	}
479 	if (*line != '"') {
480 		error("preprocessor error");
481 	}
482 	line++;
483 	p = file = alloc(strlen(line) + 1);
484 	while (*line && *line != '"') {
485 		*p++ = *line++;
486 	}
487 	if (*line == 0) {
488 		error("preprocessor error");
489 	}
490 	*p = 0;
491 	if (*file == 0) {
492 		*fname = NULL;
493 		free(file);
494 	} else {
495 		*fname = file;
496 	}
497 	*lineno = num - 1;
498 }
499