xref: /netbsd/usr.bin/rpcgen/rpc_scan.c (revision fe2adb71)
1 /*	$NetBSD: rpc_scan.c,v 1.15 2015/05/09 23:28:43 dholland 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.15 2015/05/09 23:28:43 dholland 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
scan(tok_kind expect,token * tokp)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
scan2(tok_kind expect1,tok_kind expect2,token * tokp)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
scan3(tok_kind expect1,tok_kind expect2,tok_kind expect3,token * tokp)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
scan_num(token * tokp)111 scan_num(token *tokp)
112 {
113 	get_token(tokp);
114 	switch (tokp->kind) {
115 	case TOK_IDENT:
116 		break;
117 	default:
118 		error("Expected constant or identifier");
119 	}
120 }
121 /*
122  * Peek at the next token
123  */
124 void
peek(token * tokp)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
peekscan(tok_kind expect,token * tokp)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
get_token(token * tokp)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 			if (isprint((unsigned char)*where)) {
287 				error("Illegal character '%c' in file", *where);
288 			} else {
289 				error("Illegal character %d in file", *where);
290 			}
291 		}
292 		findkind(&where, tokp);
293 		break;
294 	}
295 }
296 
297 static void
unget_token(token * tokp)298 unget_token(token *tokp)
299 {
300 	lasttok = *tokp;
301 	pushed = 1;
302 }
303 
304 static void
findstrconst(char ** str,const char ** val)305 findstrconst(char **str, const char **val)
306 {
307 	char *p;
308 	int     size;
309 	char *tmp;
310 
311 	p = *str;
312 	do {
313 		p++;
314 	} while (*p && *p != '"');
315 	if (*p == 0) {
316 		error("Unterminated string constant");
317 	}
318 	p++;
319 	size = p - *str;
320 	tmp = alloc(size + 1);
321 	(void) strncpy(tmp, *str, size);
322 	tmp[size] = 0;
323 	*val = tmp;
324 	*str = p;
325 }
326 
327 static void
findchrconst(char ** str,const char ** val)328 findchrconst(char **str, const char **val)
329 {
330 	char *p;
331 	int     size;
332 	char *tmp;
333 
334 	p = *str;
335 	do {
336 		p++;
337 	} while (*p && *p != '\'');
338 	if (*p == 0) {
339 		error("Unterminated string constant");
340 	}
341 	p++;
342 	size = p - *str;
343 	if (size != 3) {
344 		error("Empty character");
345 	}
346 	tmp = alloc(size + 1);
347 	(void) strncpy(tmp, *str, size);
348 	tmp[size] = 0;
349 	*val = tmp;
350 	*str = p;
351 }
352 
353 static void
findconst(char ** str,const char ** val)354 findconst(char **str, const char **val)
355 {
356 	char *p;
357 	int     size;
358 	char *tmp;
359 
360 	p = *str;
361 	if (*p == '0' && *(p + 1) == 'x') {
362 		p++;
363 		do {
364 			p++;
365 		} while (isxdigit((unsigned char)*p));
366 	} else {
367 		do {
368 			p++;
369 		} while (isdigit((unsigned char)*p));
370 	}
371 	size = p - *str;
372 	tmp = alloc(size + 1);
373 	(void) strncpy(tmp, *str, size);
374 	tmp[size] = 0;
375 	*val = tmp;
376 	*str = p;
377 }
378 
379 static const token symbols[] = {
380 	{TOK_CONST, "const"},
381 	{TOK_UNION, "union"},
382 	{TOK_SWITCH, "switch"},
383 	{TOK_CASE, "case"},
384 	{TOK_DEFAULT, "default"},
385 	{TOK_STRUCT, "struct"},
386 	{TOK_TYPEDEF, "typedef"},
387 	{TOK_ENUM, "enum"},
388 	{TOK_OPAQUE, "opaque"},
389 	{TOK_BOOL, "bool"},
390 	{TOK_VOID, "void"},
391 	{TOK_CHAR, "char"},
392 	{TOK_INT, "int"},
393 	{TOK_UNSIGNED, "unsigned"},
394 	{TOK_SHORT, "short"},
395 	{TOK_LONG, "long"},
396 	{TOK_HYPER, "hyper"},
397 	{TOK_FLOAT, "float"},
398 	{TOK_DOUBLE, "double"},
399 	{TOK_QUAD, "quadruple"},
400 	{TOK_STRING, "string"},
401 	{TOK_PROGRAM, "program"},
402 	{TOK_VERSION, "version"},
403 	{TOK_EOF, "??????"},
404 };
405 
406 static void
findkind(char ** mark,token * tokp)407 findkind(char **mark, token *tokp)
408 {
409 	int     len;
410 	const token *s;
411 	char *str;
412 	char *tmp;
413 
414 	str = *mark;
415 	for (s = symbols; s->kind != TOK_EOF; s++) {
416 		len = strlen(s->str);
417 		if (strncmp(str, s->str, len) == 0) {
418 			if (!isalnum((unsigned char)str[len]) &&
419 			    str[len] != '_') {
420 				tokp->kind = s->kind;
421 				tokp->str = s->str;
422 				*mark = str + len;
423 				return;
424 			}
425 		}
426 	}
427 	tokp->kind = TOK_IDENT;
428 	for (len = 0; isalnum((unsigned char)str[len]) ||
429 	    str[len] == '_'; len++);
430 	tmp = alloc(len + 1);
431 	(void) strncpy(tmp, str, len);
432 	tmp[len] = 0;
433 	tokp->str = tmp;
434 	*mark = str + len;
435 }
436 
437 static int
cppline(const char * line)438 cppline(const char *line)
439 {
440 	return (line == curline && *line == '#');
441 }
442 
443 static int
directive(const char * line)444 directive(const char *line)
445 {
446 	return (line == curline && *line == '%');
447 }
448 
449 static void
printdirective(const char * line)450 printdirective(const char *line)
451 {
452 	f_print(fout, "%s", line + 1);
453 }
454 
455 static void
docppline(char * line,int * lineno,const char ** fname)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((unsigned char)*line)) {
464 		line++;
465 	}
466 	num = atoi(line);
467 	while (isdigit((unsigned char)*line)) {
468 		line++;
469 	}
470 	while (isspace((unsigned char)*line)) {
471 		line++;
472 	}
473 	if (*line != '"') {
474 		error("Preprocessor error");
475 	}
476 	line++;
477 	p = file = alloc(strlen(line) + 1);
478 	while (*line && *line != '"') {
479 		*p++ = *line++;
480 	}
481 	if (*line == 0) {
482 		error("Preprocessor error");
483 	}
484 	*p = 0;
485 	if (*file == 0) {
486 		*fname = NULL;
487 		free(file);
488 	} else {
489 		*fname = file;
490 	}
491 	*lineno = num - 1;
492 }
493