Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / rpcgen / rpc_scan.c
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  * $FreeBSD: src/usr.bin/rpcgen/rpc_scan.c,v 1.4.8.1 2001/03/04 08:59:50 kris Exp $
30  */
31
32 #ident  "@(#)rpc_scan.c 1.13    93/07/05 SMI"
33
34 #ifndef lint
35 static char sccsid[] = "@(#)rpc_scan.c 1.11 89/02/22 (C) 1987 SMI";
36 #endif
37
38 /*
39  * rpc_scan.c, Scanner for the RPC protocol compiler 
40  * Copyright (C) 1987, Sun Microsystems, Inc. 
41  */
42
43 #include <sys/types.h>
44
45 #include <sys/wait.h>
46 #include <stdio.h>
47 #include <ctype.h>
48 #include <string.h>
49 #include "rpc_scan.h"
50 #include "rpc_parse.h"
51 #include "rpc_util.h"
52
53 #define startcomment(where) (where[0] == '/' && where[1] == '*')
54 #define endcomment(where) (where[-1] == '*' && where[0] == '/')
55
56 static int pushed = 0;  /* is a token pushed */
57 static token lasttok;   /* last token, if pushed */
58
59 static void unget_token __P(( token * ));
60 static void findstrconst __P(( char **, char **));
61 static void findchrconst __P(( char **, char **));
62 static void findconst __P(( char **, char **));
63 static void findkind __P(( char **, token * ));
64 static int cppline __P(( char * ));
65 static int directive __P(( char * ));
66 static void printdirective __P(( char * ));
67 static void docppline __P(( char *, int *, char ** ));
68
69 /*
70  * scan expecting 1 given token 
71  */
72 void
73 scan(expect, tokp)
74         tok_kind expect;
75         token *tokp;
76 {
77         get_token(tokp);
78         if (tokp->kind != expect) {
79                 expected1(expect);
80         }
81 }
82
83 /*
84  * scan expecting any of the 2 given tokens 
85  */
86 void
87 scan2(expect1, expect2, tokp)
88         tok_kind expect1;
89         tok_kind expect2;
90         token *tokp;
91 {
92         get_token(tokp);
93         if (tokp->kind != expect1 && tokp->kind != expect2) {
94                 expected2(expect1, expect2);
95         }
96 }
97
98 /*
99  * scan expecting any of the 3 given token 
100  */
101 void
102 scan3(expect1, expect2, expect3, tokp)
103         tok_kind expect1;
104         tok_kind expect2;
105         tok_kind expect3;
106         token *tokp;
107 {
108         get_token(tokp);
109         if (tokp->kind != expect1 && tokp->kind != expect2
110             && tokp->kind != expect3) {
111                 expected3(expect1, expect2, expect3);
112         }
113 }
114
115 /*
116  * scan expecting a constant, possibly symbolic 
117  */
118 void
119 scan_num(tokp)
120         token *tokp;
121 {
122         get_token(tokp);
123         switch (tokp->kind) {
124         case TOK_IDENT:
125                 break;
126         default:
127                 error("constant or identifier expected");
128         }
129 }
130
131 /*
132  * Peek at the next token 
133  */
134 void
135 peek(tokp)
136         token *tokp;
137 {
138         get_token(tokp);
139         unget_token(tokp);
140 }
141
142 /*
143  * Peek at the next token and scan it if it matches what you expect 
144  */
145 int
146 peekscan(expect, tokp)
147         tok_kind expect;
148         token *tokp;
149 {
150         peek(tokp);
151         if (tokp->kind == expect) {
152                 get_token(tokp);
153                 return (1);
154         }
155         return (0);
156 }
157
158 /*
159  * Get the next token, printing out any directive that are encountered. 
160  */
161 void
162 get_token(tokp)
163         token *tokp;
164 {
165         int commenting;
166         int stat = 0;
167         
168         
169         if (pushed) {
170                 pushed = 0;
171                 *tokp = lasttok;
172                 return;
173         }
174         commenting = 0;
175         for (;;) {
176                 if (*where == 0) {
177                         for (;;) {
178                                 if (!fgets(curline, MAXLINESIZE, fin)) {
179                                         tokp->kind = TOK_EOF;
180                                         /* now check if cpp returned non NULL value */
181                                         waitpid(childpid, &stat, WUNTRACED);
182                                         if (stat > 0) {
183                                         /* Set return value from rpcgen */
184                                                 nonfatalerrors = stat >> 8;
185                                         }
186                                         *where = 0;
187                                         return;
188                                 }
189                                 linenum++;
190                                 if (commenting) {
191                                         break;
192                                 } else if (cppline(curline)) {
193                                         docppline(curline, &linenum, 
194                                                   &infilename);
195                                 } else if (directive(curline)) {
196                                         printdirective(curline);
197                                 } else {
198                                         break;
199                                 }
200                         }
201                         where = curline;
202                 } else if (isspace(*where)) {
203                         while (isspace(*where)) {
204                                 where++;        /* eat */
205                         }
206                 } else if (commenting) {
207                         for (where++; *where; where++) {
208                                 if (endcomment(where)) {
209                                         where++;
210                                         commenting--;
211                                         break;
212                                 }
213                         }
214                 } else if (startcomment(where)) {
215                         where += 2;
216                         commenting++;
217                 } else {
218                         break;
219                 }
220         }
221
222         /*
223          * 'where' is not whitespace, comment or directive Must be a token! 
224          */
225         switch (*where) {
226         case ':':
227                 tokp->kind = TOK_COLON;
228                 where++;
229                 break;
230         case ';':
231                 tokp->kind = TOK_SEMICOLON;
232                 where++;
233                 break;
234         case ',':
235                 tokp->kind = TOK_COMMA;
236                 where++;
237                 break;
238         case '=':
239                 tokp->kind = TOK_EQUAL;
240                 where++;
241                 break;
242         case '*':
243                 tokp->kind = TOK_STAR;
244                 where++;
245                 break;
246         case '[':
247                 tokp->kind = TOK_LBRACKET;
248                 where++;
249                 break;
250         case ']':
251                 tokp->kind = TOK_RBRACKET;
252                 where++;
253                 break;
254         case '{':
255                 tokp->kind = TOK_LBRACE;
256                 where++;
257                 break;
258         case '}':
259                 tokp->kind = TOK_RBRACE;
260                 where++;
261                 break;
262         case '(':
263                 tokp->kind = TOK_LPAREN;
264                 where++;
265                 break;
266         case ')':
267                 tokp->kind = TOK_RPAREN;
268                 where++;
269                 break;
270         case '<':
271                 tokp->kind = TOK_LANGLE;
272                 where++;
273                 break;
274         case '>':
275                 tokp->kind = TOK_RANGLE;
276                 where++;
277                 break;
278
279         case '"':
280                 tokp->kind = TOK_STRCONST;
281                 findstrconst(&where, &tokp->str);
282                 break;
283         case '\'':
284                 tokp->kind = TOK_CHARCONST;
285                 findchrconst(&where, &tokp->str);
286                 break;
287
288         case '-':
289         case '0':
290         case '1':
291         case '2':
292         case '3':
293         case '4':
294         case '5':
295         case '6':
296         case '7':
297         case '8':
298         case '9':
299                 tokp->kind = TOK_IDENT;
300                 findconst(&where, &tokp->str);
301                 break;
302
303         default:
304                 if (!(isalpha(*where) || *where == '_')) {
305                         char buf[100];
306                         char *p;
307
308                         s_print(buf, "illegal character in file: ");
309                         p = buf + strlen(buf);
310                         if (isprint(*where)) {
311                                 s_print(p, "%c", *where);
312                         } else {
313                                 s_print(p, "%d", *where);
314                         }
315                         error(buf);
316                 }
317                 findkind(&where, tokp);
318                 break;
319         }
320 }
321
322 static void
323 unget_token(tokp)
324         token *tokp;
325 {
326         lasttok = *tokp;
327         pushed = 1;
328 }
329
330 static void
331 findstrconst(str, val)
332         char **str;
333         char **val;
334 {
335         char *p;
336         int size;
337
338         p = *str;
339         do {
340                 p++;
341         } while (*p && *p != '"');
342         if (*p == 0) {
343                 error("unterminated string constant");
344         }
345         p++;
346         size = p - *str;
347         *val = alloc(size + 1);
348         (void) strncpy(*val, *str, size);
349         (*val)[size] = 0;
350         *str = p;
351 }
352
353 static void
354 findchrconst(str, val)
355         char **str;
356         char **val;
357 {
358         char *p;
359         int size;
360
361         p = *str;
362         do {
363                 p++;
364         } while (*p && *p != '\'');
365         if (*p == 0) {
366                 error("unterminated string constant");
367         }
368         p++;
369         size = p - *str;
370         if (size != 3) {
371                 error("empty char string");
372         }
373         *val = alloc(size + 1);
374         (void) strncpy(*val, *str, size);
375         (*val)[size] = 0;
376         *str = p;
377 }
378
379 static void
380 findconst(str, val)
381         char **str;
382         char **val;
383 {
384         char *p;
385         int size;
386
387         p = *str;
388         if (*p == '0' && *(p + 1) == 'x') {
389                 p++;
390                 do {
391                         p++;
392                 } while (isxdigit(*p));
393         } else {
394                 do {
395                         p++;
396                 } while (isdigit(*p));
397         }
398         size = p - *str;
399         *val = alloc(size + 1);
400         (void) strncpy(*val, *str, size);
401         (*val)[size] = 0;
402         *str = p;
403 }
404
405 static token symbols[] = {
406                           {TOK_CONST, "const"},
407                           {TOK_UNION, "union"},
408                           {TOK_SWITCH, "switch"},
409                           {TOK_CASE, "case"},
410                           {TOK_DEFAULT, "default"},
411                           {TOK_STRUCT, "struct"},
412                           {TOK_TYPEDEF, "typedef"},
413                           {TOK_ENUM, "enum"},
414                           {TOK_OPAQUE, "opaque"},
415                           {TOK_BOOL, "bool"},
416                           {TOK_VOID, "void"},
417                           {TOK_CHAR, "char"},
418                           {TOK_INT, "int"},
419                           {TOK_UNSIGNED, "unsigned"},
420                           {TOK_SHORT, "short"},
421                           {TOK_LONG, "long"},
422                           {TOK_HYPER, "hyper"},
423                           {TOK_FLOAT, "float"},
424                           {TOK_DOUBLE, "double"},
425                           {TOK_QUAD, "quadruple"},
426                           {TOK_STRING, "string"},
427                           {TOK_PROGRAM, "program"},
428                           {TOK_VERSION, "version"},
429                           {TOK_EOF, "??????"},
430 };
431
432 static void
433 findkind(mark, tokp)
434         char **mark;
435         token *tokp;
436 {
437         int len;
438         token *s;
439         char *str;
440
441         str = *mark;
442         for (s = symbols; s->kind != TOK_EOF; s++) {
443                 len = strlen(s->str);
444                 if (strncmp(str, s->str, len) == 0) {
445                         if (!isalnum(str[len]) && str[len] != '_') {
446                                 tokp->kind = s->kind;
447                                 tokp->str = s->str;
448                                 *mark = str + len;
449                                 return;
450                         }
451                 }
452         }
453         tokp->kind = TOK_IDENT;
454         for (len = 0; isalnum(str[len]) || str[len] == '_'; len++);
455         tokp->str = alloc(len + 1);
456         (void) strncpy(tokp->str, str, len);
457         tokp->str[len] = 0;
458         *mark = str + len;
459 }
460
461 static int
462 cppline(line)
463         char *line;
464 {
465         return (line == curline && *line == '#');
466 }
467
468 static int
469 directive(line)
470         char *line;
471 {
472         return (line == curline && *line == '%');
473 }
474
475 static void
476 printdirective(line)
477         char *line;
478 {
479         f_print(fout, "%s", line + 1);
480 }
481
482 static void
483 docppline(line, lineno, fname)
484         char *line;
485         int *lineno;
486         char **fname;
487 {
488         char *file;
489         int num;
490         char *p;
491
492         line++;
493         while (isspace(*line)) {
494                 line++;
495         }
496         num = atoi(line);
497         while (isdigit(*line)) {
498                 line++;
499         }
500         while (isspace(*line)) {
501                 line++;
502         }
503         if (*line != '"') {
504                 error("preprocessor error");
505         }
506         line++;
507         p = file = alloc(strlen(line) + 1);
508         while (*line && *line != '"') {
509                 *p++ = *line++;
510         }
511         if (*line == 0) {
512                 error("preprocessor error");
513         }
514         *p = 0;
515         if (*file == 0) {
516                 *fname = NULL;
517         } else {
518                 *fname = file;
519         }
520         *lineno = num - 1;
521 }