Initial import of binutils 2.22 on the new vendor branch
[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  * @(#)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 }