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