1 /* -----------------------------------------------------------------------------
2 * This file is part of SWIG, which is licensed as a whole under version 3
3 * (or any later version) of the GNU General Public License. Some additional
4 * terms also apply to certain portions of SWIG. The full details of the SWIG
5 * license and copyrights can be found in the LICENSE and COPYRIGHT files
6 * included with the SWIG source code as distributed by the SWIG developers
7 * and at http://www.swig.org/legal.html.
8 *
9 * cpp.c
10 *
11 * An implementation of a C preprocessor plus some support for additional
12 * SWIG directives.
13 *
14 * - SWIG directives such as %include, %extern, and %import are handled
15 * - A new macro %define ... %enddef can be used for multiline macros
16 * - No preprocessing is performed in %{ ... %} blocks
17 * - Lines beginning with %# are stripped down to #... and passed through.
18 * ----------------------------------------------------------------------------- */
19
20 #include "swig.h"
21 #include "preprocessor.h"
22 #include <ctype.h>
23
24 static Hash *cpp = 0; /* C preprocessor data */
25 static int include_all = 0; /* Follow all includes */
26 static int ignore_missing = 0;
27 static int import_all = 0; /* Follow all includes, but as %import statements */
28 static int imported_depth = 0; /* Depth of %imported files */
29 static int single_include = 1; /* Only include each file once */
30 static Hash *included_files = 0;
31 static List *dependencies = 0;
32 static Scanner *id_scan = 0;
33 static int error_as_warning = 0; /* Understand the cpp #error directive as a special #warning */
34 static int expand_defined_operator = 0;
35 static int macro_level = 0;
36 static int macro_start_line = 0;
37 static const String * macro_start_file = 0;
38
39 /* Test a character to see if it starts an identifier */
40 #define isidentifier(c) ((isalpha(c)) || (c == '_') || (c == '$'))
41
42 /* Test a character to see if it valid in an identifier (after the first letter) */
43 #define isidchar(c) ((isalnum(c)) || (c == '_') || (c == '$'))
44
45 static DOH *Preprocessor_replace(DOH *);
46
47 /* Skip whitespace */
skip_whitespace(String * s,String * out)48 static void skip_whitespace(String *s, String *out) {
49 int c;
50 while ((c = Getc(s)) != EOF) {
51 if (!isspace(c)) {
52 Ungetc(c, s);
53 break;
54 } else if (out)
55 Putc(c, out);
56 }
57 }
58
59 /* Skip to a specified character taking line breaks into account */
skip_tochar(String * s,int ch,String * out)60 static int skip_tochar(String *s, int ch, String *out) {
61 int c;
62 while ((c = Getc(s)) != EOF) {
63 if (out)
64 Putc(c, out);
65 if (c == ch)
66 break;
67 if (c == '\\') {
68 c = Getc(s);
69 if ((c != EOF) && (out))
70 Putc(c, out);
71 }
72 }
73 if (c == EOF)
74 return -1;
75 return 0;
76 }
77
copy_location(const DOH * s1,DOH * s2)78 static void copy_location(const DOH *s1, DOH *s2) {
79 Setfile(s2, Getfile((DOH *) s1));
80 Setline(s2, Getline((DOH *) s1));
81 }
82
cpp_include(const_String_or_char_ptr fn,int sysfile)83 static String *cpp_include(const_String_or_char_ptr fn, int sysfile) {
84 String *s = sysfile ? Swig_include_sys(fn) : Swig_include(fn);
85 if (s && single_include) {
86 String *file = Getfile(s);
87 if (Getattr(included_files, file)) {
88 Delete(s);
89 return 0;
90 }
91 Setattr(included_files, file, file);
92 }
93 if (!s) {
94 if (ignore_missing) {
95 Swig_warning(WARN_PP_MISSING_FILE, Getfile(fn), Getline(fn), "Unable to find '%s'\n", fn);
96 } else {
97 Swig_error(Getfile(fn), Getline(fn), "Unable to find '%s'\n", fn);
98 }
99 } else {
100 String *lf;
101 Seek(s, 0, SEEK_SET);
102 if (!dependencies) {
103 dependencies = NewList();
104 }
105 lf = Copy(Swig_last_file());
106 Append(dependencies, lf);
107 Delete(lf);
108 }
109 return s;
110 }
111
is_digits(const String * str)112 static int is_digits(const String *str) {
113 const char *s = Char(str);
114 int isdigits = (*s != 0);
115 while (*s) {
116 if (!isdigit(*s)) {
117 isdigits = 0;
118 break;
119 }
120 s++;
121 }
122 return isdigits;
123 }
124
Preprocessor_depend(void)125 List *Preprocessor_depend(void) {
126 return dependencies;
127 }
128
129 /* -----------------------------------------------------------------------------
130 * void Preprocessor_cpp_init() - Initialize the preprocessor
131 * ----------------------------------------------------------------------------- */
132 static String *kpp_args = 0;
133 static String *kpp_define = 0;
134 static String *kpp_defined = 0;
135 static String *kpp_elif = 0;
136 static String *kpp_else = 0;
137 static String *kpp_endif = 0;
138 static String *kpp_expanded = 0;
139 static String *kpp_if = 0;
140 static String *kpp_ifdef = 0;
141 static String *kpp_ifndef = 0;
142 static String *kpp_name = 0;
143 static String *kpp_swigmacro = 0;
144 static String *kpp_symbols = 0;
145 static String *kpp_undef = 0;
146 static String *kpp_value = 0;
147 static String *kpp_varargs = 0;
148 static String *kpp_error = 0;
149 static String *kpp_warning = 0;
150 static String *kpp_line = 0;
151 static String *kpp_include = 0;
152 static String *kpp_pragma = 0;
153 static String *kpp_level = 0;
154
155 static String *kpp_dline = 0;
156 static String *kpp_ddefine = 0;
157 static String *kpp_dinclude = 0;
158 static String *kpp_dimport = 0;
159 static String *kpp_dbeginfile = 0;
160 static String *kpp_dextern = 0;
161
162 static String *kpp_LINE = 0;
163 static String *kpp_FILE = 0;
164
165 static String *kpp_hash_if = 0;
166 static String *kpp_hash_elif = 0;
167
Preprocessor_init(void)168 void Preprocessor_init(void) {
169 Hash *s;
170
171 kpp_args = NewString("args");
172 kpp_define = NewString("define");
173 kpp_defined = NewString("defined");
174 kpp_else = NewString("else");
175 kpp_elif = NewString("elif");
176 kpp_endif = NewString("endif");
177 kpp_expanded = NewString("*expanded*");
178 kpp_if = NewString("if");
179 kpp_ifdef = NewString("ifdef");
180 kpp_ifndef = NewString("ifndef");
181 kpp_name = NewString("name");
182 kpp_swigmacro = NewString("swigmacro");
183 kpp_symbols = NewString("symbols");
184 kpp_undef = NewString("undef");
185 kpp_value = NewString("value");
186 kpp_error = NewString("error");
187 kpp_warning = NewString("warning");
188 kpp_pragma = NewString("pragma");
189 kpp_level = NewString("level");
190 kpp_line = NewString("line");
191 kpp_include = NewString("include");
192 kpp_varargs = NewString("varargs");
193
194 kpp_dinclude = NewString("%include");
195 kpp_dimport = NewString("%import");
196 kpp_dbeginfile = NewString("%beginfile");
197 kpp_dextern = NewString("%extern");
198 kpp_ddefine = NewString("%define");
199 kpp_dline = NewString("%line");
200
201
202 kpp_LINE = NewString("__LINE__");
203 kpp_FILE = NewString("__FILE__");
204
205 kpp_hash_if = NewString("#if");
206 kpp_hash_elif = NewString("#elif");
207
208 cpp = NewHash();
209 s = NewHash();
210 Setattr(cpp, kpp_symbols, s);
211 Delete(s);
212 Preprocessor_expr_init(); /* Initialize the expression evaluator */
213 included_files = NewHash();
214
215 id_scan = NewScanner();
216
217 }
218
Preprocessor_delete(void)219 void Preprocessor_delete(void) {
220 Delete(kpp_args);
221 Delete(kpp_define);
222 Delete(kpp_defined);
223 Delete(kpp_else);
224 Delete(kpp_elif);
225 Delete(kpp_endif);
226 Delete(kpp_expanded);
227 Delete(kpp_if);
228 Delete(kpp_ifdef);
229 Delete(kpp_ifndef);
230 Delete(kpp_name);
231 Delete(kpp_swigmacro);
232 Delete(kpp_symbols);
233 Delete(kpp_undef);
234 Delete(kpp_value);
235 Delete(kpp_error);
236 Delete(kpp_warning);
237 Delete(kpp_pragma);
238 Delete(kpp_level);
239 Delete(kpp_line);
240 Delete(kpp_include);
241 Delete(kpp_varargs);
242
243 Delete(kpp_dinclude);
244 Delete(kpp_dimport);
245 Delete(kpp_dbeginfile);
246 Delete(kpp_dextern);
247 Delete(kpp_ddefine);
248 Delete(kpp_dline);
249
250 Delete(kpp_LINE);
251 Delete(kpp_FILE);
252
253 Delete(kpp_hash_if);
254 Delete(kpp_hash_elif);
255
256 Delete(cpp);
257 Delete(included_files);
258 Preprocessor_expr_delete();
259 DelScanner(id_scan);
260
261 Delete(dependencies);
262
263 Delete(Swig_add_directory(0));
264 }
265
266 /* -----------------------------------------------------------------------------
267 * void Preprocessor_include_all() - Instruct preprocessor to include all files
268 * ----------------------------------------------------------------------------- */
Preprocessor_include_all(int a)269 void Preprocessor_include_all(int a) {
270 include_all = a;
271 }
272
Preprocessor_import_all(int a)273 void Preprocessor_import_all(int a) {
274 import_all = a;
275 }
276
Preprocessor_ignore_missing(int a)277 void Preprocessor_ignore_missing(int a) {
278 ignore_missing = a;
279 }
280
Preprocessor_error_as_warning(int a)281 void Preprocessor_error_as_warning(int a) {
282 error_as_warning = a;
283 }
284
285
286 /* -----------------------------------------------------------------------------
287 * Preprocessor_define()
288 *
289 * Defines a new C preprocessor symbol. swigmacro specifies whether or not the macro has
290 * SWIG macro semantics.
291 * ----------------------------------------------------------------------------- */
292
293
Macro_vararg_name(const_String_or_char_ptr str,const_String_or_char_ptr line)294 String *Macro_vararg_name(const_String_or_char_ptr str, const_String_or_char_ptr line) {
295 String *argname;
296 String *varargname;
297 char *s, *dots;
298
299 argname = Copy(str);
300 s = Char(argname);
301 dots = strchr(s, '.');
302 if (!dots) {
303 Delete(argname);
304 return NULL;
305 }
306
307 if (strcmp(dots, "...") != 0) {
308 Swig_error(Getfile(line), Getline(line), "Illegal macro argument name '%s'\n", str);
309 Delete(argname);
310 return NULL;
311 }
312 if (dots == s) {
313 varargname = NewString("__VA_ARGS__");
314 } else {
315 *dots = '\0';
316 varargname = NewString(s);
317 }
318 Delete(argname);
319 return varargname;
320 }
321
Preprocessor_define(const_String_or_char_ptr _str,int swigmacro)322 Hash *Preprocessor_define(const_String_or_char_ptr _str, int swigmacro) {
323 String *macroname = 0, *argstr = 0, *macrovalue = 0, *file = 0, *s = 0;
324 Hash *macro = 0, *symbols = 0, *m1;
325 List *arglist = 0;
326 int c, line;
327 int varargs = 0;
328 String *str;
329
330 assert(cpp);
331 assert(_str);
332
333 /* First make sure that string is actually a string */
334 if (DohCheck(_str)) {
335 s = Copy(_str);
336 copy_location(_str, s);
337 str = s;
338 } else {
339 str = NewString((char *) _str);
340 }
341 Seek(str, 0, SEEK_SET);
342 line = Getline(str);
343 file = Getfile(str);
344
345 /* Skip over any leading whitespace */
346 skip_whitespace(str, 0);
347
348 /* Now look for a macro name */
349 macroname = NewStringEmpty();
350 copy_location(str, macroname);
351 while ((c = Getc(str)) != EOF) {
352 if (c == '(') {
353 argstr = NewStringEmpty();
354 copy_location(str, argstr);
355 /* It is a macro. Go extract its argument string */
356 while ((c = Getc(str)) != EOF) {
357 if (c == ')')
358 break;
359 else
360 Putc(c, argstr);
361 }
362 if (c != ')') {
363 Swig_error(Getfile(argstr), Getline(argstr), "Missing \')\' in macro parameters\n");
364 goto macro_error;
365 }
366 break;
367 } else if (isidchar(c) || (c == '%')) {
368 Putc(c, macroname);
369 } else if (isspace(c)) {
370 break;
371 } else if (c == '\\') {
372 c = Getc(str);
373 if (c != '\n') {
374 Ungetc(c, str);
375 Ungetc('\\', str);
376 break;
377 }
378 } else {
379 Ungetc(c, str);
380 break;
381 }
382 }
383 if (!swigmacro)
384 skip_whitespace(str, 0);
385 macrovalue = NewStringEmpty();
386 copy_location(str, macrovalue);
387 while ((c = Getc(str)) != EOF) {
388 Putc(c, macrovalue);
389 }
390
391 /* If there are any macro arguments, convert into a list */
392 if (argstr) {
393 String *argname, *varargname;
394 arglist = NewList();
395 Seek(argstr, 0, SEEK_SET);
396 argname = NewStringEmpty();
397 while ((c = Getc(argstr)) != EOF) {
398 if (c == ',') {
399 varargname = Macro_vararg_name(argname, argstr);
400 if (varargname) {
401 Delete(varargname);
402 Swig_error(Getfile(argstr), Getline(argstr), "Variable length macro argument must be last parameter\n");
403 } else {
404 Append(arglist, argname);
405 }
406 Delete(argname);
407 argname = NewStringEmpty();
408 } else if (isidchar(c) || (c == '.')) {
409 Putc(c, argname);
410 } else if (!(isspace(c) || (c == '\\'))) {
411 Delete(argname);
412 Swig_error(Getfile(argstr), Getline(argstr), "Illegal character in macro argument name\n");
413 goto macro_error;
414 }
415 }
416 if (Len(argname)) {
417 /* Check for varargs */
418 varargname = Macro_vararg_name(argname, argstr);
419 if (varargname) {
420 Append(arglist, varargname);
421 Delete(varargname);
422 varargs = 1;
423 } else {
424 Append(arglist, argname);
425 }
426 }
427 Delete(argname);
428 }
429
430 if (!swigmacro) {
431 Replace(macrovalue, "\\\n", " ", DOH_REPLACE_NOQUOTE);
432 }
433
434 /* Look for special # substitutions. We only consider # that appears
435 outside of quotes and comments */
436
437 {
438 int state = 0;
439 char *cc = Char(macrovalue);
440 while (*cc) {
441 switch (state) {
442 case 0:
443 if (*cc == '#')
444 *cc = '\001';
445 else if (*cc == '/')
446 state = 10;
447 else if (*cc == '\'')
448 state = 20;
449 else if (*cc == '\"')
450 state = 30;
451 break;
452 case 10:
453 if (*cc == '*')
454 state = 11;
455 else if (*cc == '/')
456 state = 15;
457 else {
458 state = 0;
459 cc--;
460 }
461 break;
462 case 11:
463 if (*cc == '*')
464 state = 12;
465 break;
466 case 12:
467 if (*cc == '/')
468 state = 0;
469 else if (*cc != '*')
470 state = 11;
471 break;
472 case 15:
473 if (*cc == '\n')
474 state = 0;
475 break;
476 case 20:
477 if (*cc == '\'')
478 state = 0;
479 if (*cc == '\\')
480 state = 21;
481 break;
482 case 21:
483 state = 20;
484 break;
485 case 30:
486 if (*cc == '\"')
487 state = 0;
488 if (*cc == '\\')
489 state = 31;
490 break;
491 case 31:
492 state = 30;
493 break;
494 default:
495 break;
496 }
497 cc++;
498 }
499 }
500
501 /* Get rid of whitespace surrounding # */
502 /* Replace(macrovalue,"#","\001",DOH_REPLACE_NOQUOTE); */
503 while (strstr(Char(macrovalue), "\001 ")) {
504 Replace(macrovalue, "\001 ", "\001", DOH_REPLACE_ANY);
505 }
506 while (strstr(Char(macrovalue), " \001")) {
507 Replace(macrovalue, " \001", "\001", DOH_REPLACE_ANY);
508 }
509 /* Replace '##' with a special token */
510 Replace(macrovalue, "\001\001", "\002", DOH_REPLACE_ANY);
511 /* Replace '#@' with a special token */
512 Replace(macrovalue, "\001@", "\004", DOH_REPLACE_ANY);
513 /* Replace '##@' with a special token */
514 Replace(macrovalue, "\002@", "\005", DOH_REPLACE_ANY);
515
516 /* Go create the macro */
517 macro = NewHash();
518 Setattr(macro, kpp_name, macroname);
519
520 if (arglist) {
521 Setattr(macro, kpp_args, arglist);
522 Delete(arglist);
523 if (varargs) {
524 Setattr(macro, kpp_varargs, "1");
525 }
526 }
527 Setattr(macro, kpp_value, macrovalue);
528 Setline(macro, line);
529 Setfile(macro, file);
530 if (swigmacro) {
531 Setattr(macro, kpp_swigmacro, "1");
532 }
533 symbols = Getattr(cpp, kpp_symbols);
534 if ((m1 = Getattr(symbols, macroname))) {
535 if (!Checkattr(m1, kpp_value, macrovalue)) {
536 Swig_error(Getfile(macroname), Getline(macroname), "Macro '%s' redefined,\n", macroname);
537 Swig_error(Getfile(m1), Getline(m1), "previous definition of '%s'.\n", macroname);
538 goto macro_error;
539 }
540 } else {
541 Setattr(symbols, macroname, macro);
542 Delete(macro);
543 }
544
545 Delete(macroname);
546 Delete(macrovalue);
547
548 Delete(str);
549 Delete(argstr);
550 return macro;
551
552 macro_error:
553 Delete(str);
554 Delete(argstr);
555 Delete(arglist);
556 Delete(macroname);
557 Delete(macrovalue);
558 return 0;
559 }
560
561 /* -----------------------------------------------------------------------------
562 * Preprocessor_undef()
563 *
564 * Undefines a macro.
565 * ----------------------------------------------------------------------------- */
Preprocessor_undef(const_String_or_char_ptr str)566 void Preprocessor_undef(const_String_or_char_ptr str) {
567 Hash *symbols;
568 assert(cpp);
569 symbols = Getattr(cpp, kpp_symbols);
570 Delattr(symbols, str);
571 }
572
573 /* -----------------------------------------------------------------------------
574 * find_args()
575 *
576 * Isolates macro arguments and returns them in a list. For each argument,
577 * leading and trailing whitespace is stripped (ala K&R, pg. 230).
578 * ----------------------------------------------------------------------------- */
find_args(String * s,int ismacro,String * macro_name)579 static List *find_args(String *s, int ismacro, String *macro_name) {
580 List *args;
581 String *str;
582 int c, level;
583 long pos;
584
585 /* Create a new list */
586 args = NewList();
587 copy_location(s, args);
588
589 /* First look for a '(' */
590 pos = Tell(s);
591 skip_whitespace(s, 0);
592
593 /* Now see if the next character is a '(' */
594 c = Getc(s);
595 if (c != '(') {
596 /* Not a macro, bail out now! */
597 assert(pos != -1);
598 (void)Seek(s, pos, SEEK_SET);
599 Delete(args);
600 return 0;
601 }
602 c = Getc(s);
603 /* Okay. This appears to be a macro so we will start isolating arguments */
604 while (c != EOF) {
605 if (isspace(c)) {
606 skip_whitespace(s, 0); /* Skip leading whitespace */
607 c = Getc(s);
608 }
609 str = NewStringEmpty();
610 copy_location(s, str);
611 level = 0;
612 while (c != EOF) {
613 if (c == '\"') {
614 Putc(c, str);
615 skip_tochar(s, '\"', str);
616 c = Getc(s);
617 continue;
618 } else if (c == '\'') {
619 Putc(c, str);
620 skip_tochar(s, '\'', str);
621 c = Getc(s);
622 continue;
623 } else if (c == '/') {
624 /* Ensure comments are ignored by eating up the characters */
625 c = Getc(s);
626 /* Handle / * ... * / type comments (multi-line) */
627 if (c == '*') {
628 while ((c = Getc(s)) != EOF) {
629 if (c == '*') {
630 c = Getc(s);
631 if (c == '/' || c == EOF)
632 break;
633 }
634 }
635 c = Getc(s);
636 continue;
637 }
638 /* Handle // ... type comments (single-line) */
639 if (c == '/') {
640 while ((c = Getc(s)) != EOF) {
641 if (c == '\n') {
642 break;
643 }
644 }
645 c = Getc(s);
646 continue;
647 }
648 /* ensure char is available in the stream as this was not a comment*/
649 Ungetc(c, s);
650 c = '/';
651 }
652 if ((c == ',') && (level == 0))
653 break;
654 if ((c == ')') && (level == 0))
655 break;
656 Putc(c, str);
657 if (c == '(')
658 level++;
659 if (c == ')')
660 level--;
661 c = Getc(s);
662 }
663 if (level > 0) {
664 goto unterm;
665 }
666 Chop(str);
667 Append(args, str);
668 Delete(str);
669 if (c == ')')
670 return args;
671 c = Getc(s);
672 }
673 unterm:
674 if (ismacro)
675 Swig_error(Getfile(args), Getline(args), "Unterminated call invoking macro '%s'\n", macro_name);
676 else
677 Swig_error(Getfile(args), Getline(args), "Unterminated call to '%s'\n", macro_name);
678 return args;
679 }
680
681 /* -----------------------------------------------------------------------------
682 * DOH *get_filename()
683 *
684 * Read a filename from str. A filename can be enclosed in quotes, angle brackets,
685 * or bare.
686 * ----------------------------------------------------------------------------- */
687
get_filename(String * str,int * sysfile)688 static String *get_filename(String *str, int *sysfile) {
689 String *fn;
690 int c;
691
692 fn = NewStringEmpty();
693 copy_location(str, fn);
694 c = Getc(str);
695 *sysfile = 0;
696 if (c == '\"') {
697 while (((c = Getc(str)) != EOF) && (c != '\"'))
698 Putc(c, fn);
699 } else if (c == '<') {
700 *sysfile = 1;
701 while (((c = Getc(str)) != EOF) && (c != '>'))
702 Putc(c, fn);
703 } else {
704 String *preprocessed_str;
705 Putc(c, fn);
706 while (((c = Getc(str)) != EOF) && (!isspace(c)))
707 Putc(c, fn);
708 if (isspace(c))
709 Ungetc(c, str);
710 preprocessed_str = Preprocessor_replace(fn);
711 Seek(preprocessed_str, 0, SEEK_SET);
712 Delete(fn);
713
714 fn = NewStringEmpty();
715 copy_location(preprocessed_str, fn);
716 c = Getc(preprocessed_str);
717 if (c == '\"') {
718 while (((c = Getc(preprocessed_str)) != EOF) && (c != '\"'))
719 Putc(c, fn);
720 } else if (c == '<') {
721 *sysfile = 1;
722 while (((c = Getc(preprocessed_str)) != EOF) && (c != '>'))
723 Putc(c, fn);
724 } else {
725 fn = Copy(preprocessed_str);
726 }
727 Delete(preprocessed_str);
728 }
729 Swig_filename_unescape(fn);
730 Swig_filename_correct(fn);
731 Seek(fn, 0, SEEK_SET);
732 return fn;
733 }
734
get_options(String * str)735 static String *get_options(String *str) {
736 int c;
737 c = Getc(str);
738 if (c == '(') {
739 String *opt;
740 int level = 1;
741 opt = NewString("(");
742 while (((c = Getc(str)) != EOF)) {
743 Putc(c, opt);
744 if (c == ')') {
745 level--;
746 if (!level)
747 return opt;
748 }
749 if (c == '(')
750 level++;
751 }
752 Delete(opt);
753 return 0;
754 } else {
755 Ungetc(c, str);
756 return 0;
757 }
758 }
759
760 /* -----------------------------------------------------------------------------
761 * expand_macro()
762 *
763 * Perform macro expansion and return a new string. Returns NULL if some sort
764 * of error occurred.
765 * name - name of the macro
766 * args - arguments passed to the macro
767 * line_file - only used for line/file name when reporting errors
768 * ----------------------------------------------------------------------------- */
769
expand_macro(String * name,List * args,String * line_file)770 static String *expand_macro(String *name, List *args, String *line_file) {
771 String *ns;
772 DOH *symbols, *macro, *margs, *mvalue, *temp, *tempa, *e;
773 int i, l;
774 int isvarargs = 0;
775
776 symbols = Getattr(cpp, kpp_symbols);
777 if (!symbols)
778 return 0;
779
780 /* See if the name is actually defined */
781 macro = Getattr(symbols, name);
782 if (!macro)
783 return 0;
784
785 if (macro_level == 0) {
786 /* Store the start of the macro should the macro contain __LINE__ and __FILE__ for expansion */
787 macro_start_line = Getline(args ? args : line_file);
788 macro_start_file = Getfile(args ? args : line_file);
789 }
790 macro_level++;
791
792 if (Getattr(macro, kpp_expanded)) {
793 ns = NewStringEmpty();
794 Append(ns, name);
795 if (args) {
796 int lenargs = Len(args);
797 if (lenargs)
798 Putc('(', ns);
799 for (i = 0; i < lenargs; i++) {
800 Append(ns, Getitem(args, i));
801 if (i < (lenargs - 1))
802 Putc(',', ns);
803 }
804 if (i)
805 Putc(')', ns);
806 }
807 macro_level--;
808 return ns;
809 }
810
811 /* Get macro arguments and value */
812 mvalue = Getattr(macro, kpp_value);
813 assert(mvalue);
814 margs = Getattr(macro, kpp_args);
815
816 if (args && Getattr(macro, kpp_varargs)) {
817 isvarargs = 1;
818 /* Variable length argument macro. We need to collect all of the extra arguments into a single argument */
819 if (Len(args) >= (Len(margs) - 1)) {
820 int i;
821 int vi, na;
822 String *vararg = NewStringEmpty();
823 vi = Len(margs) - 1;
824 na = Len(args);
825 for (i = vi; i < na; i++) {
826 Append(vararg, Getitem(args, i));
827 if ((i + 1) < na) {
828 Append(vararg, ",");
829 }
830 }
831 /* Remove arguments */
832 for (i = vi; i < na; i++) {
833 Delitem(args, vi);
834 }
835 Append(args, vararg);
836 Delete(vararg);
837 }
838 }
839
840 if (args && margs && Len(margs) == 0 && Len(args) == 1 && Len(Getitem(args, 0)) == 0) {
841 /* FOO() can invoke a macro defined as FOO(X) as well as one defined FOO().
842 *
843 * Handle this by removing the only argument if it's empty and the macro
844 * expects no arguments.
845 *
846 * We don't need to worry about varargs here - a varargs macro will always have
847 * Len(margs) >= 1, since the varargs are put in the final macro argument.
848 */
849 Delitem(args, 0);
850 }
851
852 /* If there are arguments, see if they match what we were given */
853 if (args && (!margs || Len(margs) != Len(args))) {
854 if (margs && Len(margs) > (1 + isvarargs))
855 Swig_error(macro_start_file, macro_start_line, "Macro '%s' expects %d arguments\n", name, Len(margs) - isvarargs);
856 else if (margs && Len(margs) == (1 + isvarargs))
857 Swig_error(macro_start_file, macro_start_line, "Macro '%s' expects 1 argument\n", name);
858 else
859 Swig_error(macro_start_file, macro_start_line, "Macro '%s' expects no arguments\n", name);
860 macro_level--;
861 return 0;
862 }
863
864 /* If the macro expects arguments, but none were supplied, we leave it in place */
865 if (!args && margs) {
866 macro_level--;
867 return NewString(name);
868 }
869
870 /* Copy the macro value */
871 ns = Copy(mvalue);
872 copy_location(mvalue, ns);
873
874 /* Tag the macro as being expanded. This is to avoid recursion in
875 macro expansion */
876
877 temp = NewStringEmpty();
878 tempa = NewStringEmpty();
879 if (args && margs) {
880 l = Len(margs);
881 for (i = 0; i < l; i++) {
882 DOH *arg, *aname;
883 String *reparg;
884 arg = Getitem(args, i); /* Get an argument value */
885 reparg = Preprocessor_replace(arg);
886 aname = Getitem(margs, i); /* Get macro argument name */
887 if (strstr(Char(ns), "\001")) {
888 /* Try to replace a quoted version of the argument */
889 Clear(temp);
890 Clear(tempa);
891 Printf(temp, "\001%s", aname);
892 Printf(tempa, "\"%s\"", arg);
893 Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
894 }
895 if (strstr(Char(ns), "\002")) {
896 /* Look for concatenation tokens */
897 Clear(temp);
898 Clear(tempa);
899 Printf(temp, "\002%s", aname);
900 Append(tempa, "\002\003");
901 Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
902 Clear(temp);
903 Clear(tempa);
904 Printf(temp, "%s\002", aname);
905 Append(tempa, "\003\002");
906 Replace(ns, temp, tempa, DOH_REPLACE_ID_BEGIN);
907 }
908
909 /* Non-standard macro expansion. The value `x` is replaced by a quoted
910 version of the argument except that if the argument is already quoted
911 nothing happens */
912
913 if (strchr(Char(ns), '`')) {
914 String *rep;
915 char *c;
916 Clear(temp);
917 Printf(temp, "`%s`", aname);
918 c = Char(arg);
919 if (*c == '\"') {
920 rep = arg;
921 } else {
922 Clear(tempa);
923 Printf(tempa, "\"%s\"", arg);
924 rep = tempa;
925 }
926 Replace(ns, temp, rep, DOH_REPLACE_ANY);
927 }
928
929 /* Non-standard mangle expansions.
930 The #@Name is replaced by mangle_arg(Name). */
931 if (strstr(Char(ns), "\004")) {
932 String *marg = Swig_string_mangle(arg);
933 Clear(temp);
934 Printf(temp, "\004%s", aname);
935 Replace(ns, temp, marg, DOH_REPLACE_ID_END);
936 Delete(marg);
937 }
938 if (strstr(Char(ns), "\005")) {
939 String *marg = Swig_string_mangle(arg);
940 Clear(temp);
941 Clear(tempa);
942 Printf(temp, "\005%s", aname);
943 Printf(tempa, "\"%s\"", marg);
944 Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
945 Delete(marg);
946 }
947
948 if (isvarargs && i == l - 1 && Len(arg) == 0) {
949 /* Zero length varargs macro argument. We search for commas that might appear before and nuke them */
950 char *a, *s, *t, *name;
951 int namelen;
952 s = Char(ns);
953 name = Char(aname);
954 namelen = Len(aname);
955 a = strstr(s, name);
956 while (a) {
957 char ca = a[namelen];
958 if (!isidchar((int) ca)) {
959 /* Matched the entire vararg name, not just a prefix */
960 if (a > s) {
961 t = a - 1;
962 if (*t == '\002') {
963 t--;
964 while (t >= s) {
965 if (isspace((int) *t))
966 t--;
967 else if (*t == ',') {
968 *t = ' ';
969 } else
970 break;
971 }
972 }
973 }
974 }
975 a = strstr(a + namelen, name);
976 }
977 }
978 /* Replace(ns, aname, arg, DOH_REPLACE_ID); */
979 Replace(ns, aname, reparg, DOH_REPLACE_ID); /* Replace expanded args */
980 Replace(ns, "\003", arg, DOH_REPLACE_ANY); /* Replace unexpanded arg */
981 Delete(reparg);
982 }
983 }
984 Replace(ns, "\002", "", DOH_REPLACE_ANY); /* Get rid of concatenation tokens */
985 Replace(ns, "\001", "#", DOH_REPLACE_ANY); /* Put # back (non-standard C) */
986 Replace(ns, "\004", "#@", DOH_REPLACE_ANY); /* Put # back (non-standard C) */
987
988 /* Expand this macro even further */
989 Setattr(macro, kpp_expanded, "1");
990
991 e = Preprocessor_replace(ns);
992
993 Delattr(macro, kpp_expanded);
994 Delete(ns);
995
996 if (Getattr(macro, kpp_swigmacro)) {
997 String *g;
998 String *f = NewStringEmpty();
999 Seek(e, 0, SEEK_SET);
1000 copy_location(macro, e);
1001 g = Preprocessor_parse(e);
1002
1003 #if 0
1004 /* Drop the macro in place, but with a marker around it */
1005 Printf(f, "/*@%s,%d,%s@*/%s/*@@*/", Getfile(macro), Getline(macro), name, g);
1006 #else
1007 /* Use simplified around markers to properly count lines in cscanner.c */
1008 if (strchr(Char(g), '\n')) {
1009 Printf(f, "/*@SWIG:%s,%d,%s@*/%s/*@SWIG@*/", Getfile(macro), Getline(macro), name, g);
1010 #if 0
1011 Printf(f, "/*@SWIG:%s@*/%s/*@SWIG@*/", name, g);
1012 #endif
1013 } else {
1014 Append(f, g);
1015 }
1016 #endif
1017
1018 Delete(g);
1019 Delete(e);
1020 e = f;
1021 }
1022 macro_level--;
1023 Delete(temp);
1024 Delete(tempa);
1025 return e;
1026 }
1027
1028 /* -----------------------------------------------------------------------------
1029 * DOH *Preprocessor_replace(DOH *s)
1030 *
1031 * Performs a macro substitution on a string s. Returns a new string with
1032 * substitutions applied. This function works by walking down s and looking
1033 * for identifiers. When found, a check is made to see if they are macros
1034 * which are then expanded.
1035 * ----------------------------------------------------------------------------- */
1036
1037 /* #define SWIG_PUT_BUFF */
1038
Preprocessor_replace(DOH * s)1039 static DOH *Preprocessor_replace(DOH *s) {
1040 DOH *ns, *symbols, *m;
1041 int c, i, state = 0;
1042 String *id = NewStringEmpty();
1043
1044 assert(cpp);
1045 symbols = Getattr(cpp, kpp_symbols);
1046
1047 ns = NewStringEmpty();
1048 copy_location(s, ns);
1049 Seek(s, 0, SEEK_SET);
1050
1051 /* Try to locate identifiers in s and replace them with macro replacements */
1052 while ((c = Getc(s)) != EOF) {
1053 switch (state) {
1054 case 0:
1055 if (isidentifier(c)) {
1056 Clear(id);
1057 Putc(c, id);
1058 state = 4;
1059 } else if (c == '%') {
1060 Clear(id);
1061 Putc(c, id);
1062 state = 2;
1063 } else if (c == '#') {
1064 Clear(id);
1065 Putc(c, id);
1066 state = 4;
1067 } else if (c == '\"') {
1068 Putc(c, ns);
1069 skip_tochar(s, '\"', ns);
1070 } else if (c == '\'') {
1071 Putc(c, ns);
1072 skip_tochar(s, '\'', ns);
1073 } else if (c == '/') {
1074 Putc(c, ns);
1075 state = 10;
1076 } else if (c == '\\') {
1077 Putc(c, ns);
1078 c = Getc(s);
1079 if (c == '\n') {
1080 Putc(c, ns);
1081 } else {
1082 Ungetc(c, s);
1083 }
1084 } else if (c == '\n') {
1085 Putc(c, ns);
1086 expand_defined_operator = 0;
1087 } else {
1088 Putc(c, ns);
1089 }
1090 break;
1091 case 2:
1092 /* Found '%#' */
1093 if (c == '#') {
1094 Putc(c, id);
1095 state = 4;
1096 } else {
1097 Ungetc(c, s);
1098 state = 4;
1099 }
1100 break;
1101 case 4: /* An identifier */
1102 if (isidchar(c)) {
1103 Putc(c, id);
1104 state = 4;
1105 } else {
1106 /* We found the end of a valid identifier */
1107 Ungetc(c, s);
1108 /* See if this is the special "defined" operator */
1109 if (Equal(kpp_defined, id)) {
1110 if (expand_defined_operator) {
1111 int lenargs = 0;
1112 DOH *args = 0;
1113 /* See whether or not a parenthesis has been used */
1114 skip_whitespace(s, 0);
1115 c = Getc(s);
1116 if (c == '(') {
1117 Ungetc(c, s);
1118 args = find_args(s, 0, kpp_defined);
1119 } else if (isidchar(c)) {
1120 DOH *arg = NewStringEmpty();
1121 args = NewList();
1122 Putc(c, arg);
1123 while (((c = Getc(s)) != EOF)) {
1124 if (!isidchar(c)) {
1125 Ungetc(c, s);
1126 break;
1127 }
1128 Putc(c, arg);
1129 }
1130 if (Len(arg))
1131 Append(args, arg);
1132 Delete(arg);
1133 } else {
1134 Seek(s, -1, SEEK_CUR);
1135 }
1136 lenargs = Len(args);
1137 if ((!args) || (!lenargs)) {
1138 /* This is not a defined() operator. */
1139 Append(ns, id);
1140 state = 0;
1141 break;
1142 }
1143 for (i = 0; i < lenargs; i++) {
1144 DOH *o = Getitem(args, i);
1145 if (!Getattr(symbols, o)) {
1146 break;
1147 }
1148 }
1149 if (i < lenargs)
1150 Putc('0', ns);
1151 else
1152 Putc('1', ns);
1153 Delete(args);
1154 } else {
1155 Append(ns, id);
1156 }
1157 state = 0;
1158 break;
1159 } else if (Equal(kpp_LINE, id)) {
1160 Printf(ns, "%d", macro_level > 0 ? macro_start_line : Getline(s));
1161 state = 0;
1162 break;
1163 } else if (Equal(kpp_FILE, id)) {
1164 String *fn = Copy(macro_level > 0 ? macro_start_file : Getfile(s));
1165 Replaceall(fn, "\\", "\\\\");
1166 Printf(ns, "\"%s\"", fn);
1167 Delete(fn);
1168 state = 0;
1169 break;
1170 } else if (Equal(kpp_hash_if, id) || Equal(kpp_hash_elif, id)) {
1171 expand_defined_operator = 1;
1172 Append(ns, id);
1173 /*
1174 } else if (Equal("%#if", id) || Equal("%#ifdef", id)) {
1175 Swig_warning(998, Getfile(s), Getline(s), "Found: %s preprocessor directive.\n", id);
1176 Append(ns, id);
1177 } else if (Equal("#ifdef", id) || Equal("#ifndef", id)) {
1178 Swig_warning(998, Getfile(s), Getline(s), "The %s preprocessor directive does not work in macros, try #if instead.\n", id);
1179 Append(ns, id);
1180 */
1181 } else if ((m = Getattr(symbols, id))) {
1182 /* See if the macro is defined in the preprocessor symbol table */
1183 DOH *args = 0;
1184 DOH *e;
1185 int macro_additional_lines = 0;
1186 /* See if the macro expects arguments */
1187 if (Getattr(m, kpp_args)) {
1188 /* Yep. We need to go find the arguments and do a substitution */
1189 int line = Getline(s);
1190 args = find_args(s, 1, id);
1191 macro_additional_lines = Getline(s) - line;
1192 assert(macro_additional_lines >= 0);
1193 } else {
1194 args = 0;
1195 }
1196 e = expand_macro(id, args, s);
1197 if (e) {
1198 Append(ns, e);
1199 }
1200 while (macro_additional_lines--) {
1201 Putc('\n', ns);
1202 }
1203 Delete(e);
1204 Delete(args);
1205 } else {
1206 Append(ns, id);
1207 }
1208 state = 0;
1209 }
1210 break;
1211 case 10:
1212 if (c == '/')
1213 state = 11;
1214 else if (c == '*')
1215 state = 12;
1216 else {
1217 Ungetc(c, s);
1218 state = 0;
1219 break;
1220 }
1221 Putc(c, ns);
1222 break;
1223 case 11:
1224 /* in C++ comment */
1225 Putc(c, ns);
1226 if (c == '\n') {
1227 expand_defined_operator = 0;
1228 state = 0;
1229 }
1230 break;
1231 case 12:
1232 /* in C comment */
1233 Putc(c, ns);
1234 if (c == '*')
1235 state = 13;
1236 break;
1237 case 13:
1238 Putc(c, ns);
1239 if (c == '/')
1240 state = 0;
1241 else if (c != '*')
1242 state = 12;
1243 break;
1244 default:
1245 state = 0;
1246 break;
1247 }
1248 }
1249
1250 /* Identifier at the end */
1251 if (state == 2 || state == 4) {
1252 /* See if this is the special "defined" operator */
1253 if (Equal(kpp_defined, id)) {
1254 Swig_error(Getfile(s), Getline(s), "No arguments given to defined()\n");
1255 } else if (Equal(kpp_LINE, id)) {
1256 Printf(ns, "%d", macro_level > 0 ? macro_start_line : Getline(s));
1257 } else if (Equal(kpp_FILE, id)) {
1258 String *fn = Copy(macro_level > 0 ? macro_start_file : Getfile(s));
1259 Replaceall(fn, "\\", "\\\\");
1260 Printf(ns, "\"%s\"", fn);
1261 Delete(fn);
1262 } else if (Getattr(symbols, id)) {
1263 DOH *e;
1264 /* Yes. There is a macro here */
1265 /* See if the macro expects arguments */
1266 e = expand_macro(id, 0, s);
1267 if (e)
1268 Append(ns, e);
1269 Delete(e);
1270 } else {
1271 Append(ns, id);
1272 }
1273 }
1274 Delete(id);
1275 return ns;
1276 }
1277
1278
1279 /* -----------------------------------------------------------------------------
1280 * int checkpp_id(DOH *s)
1281 *
1282 * Checks the string s to see if it contains any unresolved identifiers. This
1283 * function contains the heuristic that determines whether or not a macro
1284 * definition passes through the preprocessor as a constant declaration.
1285 * ----------------------------------------------------------------------------- */
checkpp_id(DOH * s)1286 static int checkpp_id(DOH *s) {
1287 int c;
1288 int hastok = 0;
1289 Scanner *scan = id_scan;
1290
1291 Seek(s, 0, SEEK_SET);
1292
1293 Scanner_clear(scan);
1294 s = Copy(s);
1295 Seek(s, SEEK_SET, 0);
1296 Scanner_push(scan, s);
1297 while ((c = Scanner_token(scan))) {
1298 hastok = 1;
1299 if ((c == SWIG_TOKEN_ID) || (c == SWIG_TOKEN_LBRACE) || (c == SWIG_TOKEN_RBRACE))
1300 return 1;
1301 }
1302 if (!hastok)
1303 return 1;
1304 return 0;
1305 }
1306
1307 /* addline(). Utility function for adding lines to a chunk */
addline(DOH * s1,DOH * s2,int allow)1308 static void addline(DOH *s1, DOH *s2, int allow) {
1309 if (allow) {
1310 Append(s1, s2);
1311 } else {
1312 char *c = Char(s2);
1313 while (*c) {
1314 if (*c == '\n')
1315 Putc('\n', s1);
1316 c++;
1317 }
1318 }
1319 }
1320
add_chunk(DOH * ns,DOH * chunk,int allow)1321 static void add_chunk(DOH *ns, DOH *chunk, int allow) {
1322 DOH *echunk;
1323 Seek(chunk, 0, SEEK_SET);
1324 if (allow) {
1325 echunk = Preprocessor_replace(chunk);
1326 addline(ns, echunk, allow);
1327 Delete(echunk);
1328 } else {
1329 addline(ns, chunk, 0);
1330 }
1331 Clear(chunk);
1332 }
1333
1334 /*
1335 push/pop_imported(): helper functions for defining and undefining
1336 SWIGIMPORTED (when %importing a file).
1337 */
push_imported()1338 static void push_imported() {
1339 if (imported_depth == 0) {
1340 Preprocessor_define("SWIGIMPORTED 1", 0);
1341 }
1342 ++imported_depth;
1343 }
1344
pop_imported()1345 static void pop_imported() {
1346 --imported_depth;
1347 if (imported_depth == 0) {
1348 Preprocessor_undef("SWIGIMPORTED");
1349 }
1350 }
1351
1352
1353 /* -----------------------------------------------------------------------------
1354 * Preprocessor_parse()
1355 *
1356 * Parses the string s. Returns a new string containing the preprocessed version.
1357 *
1358 * Parsing rules :
1359 * 1. Lines starting with # are C preprocessor directives
1360 * 2. Macro expansion inside strings is not allowed
1361 * 3. All code inside false conditionals is changed to blank lines
1362 * 4. Code in %{, %} is not parsed because it may need to be
1363 * included inline (with all preprocessor directives included).
1364 * ----------------------------------------------------------------------------- */
1365
Preprocessor_parse(String * s)1366 String *Preprocessor_parse(String *s) {
1367 String *ns; /* New string containing the preprocessed text */
1368 String *chunk, *decl;
1369 Hash *symbols;
1370 String *id = 0, *value = 0, *comment = 0;
1371 int i, state, e, c;
1372 int start_line = 0;
1373 int allow = 1;
1374 int level = 0;
1375 int dlevel = 0;
1376 int filelevel = 0;
1377 int mask = 0;
1378 int start_level = 0;
1379 int cpp_lines = 0;
1380 int cond_lines[256];
1381
1382 /* Blow away all carriage returns */
1383 Replace(s, "\015", "", DOH_REPLACE_ANY);
1384
1385 ns = NewStringEmpty(); /* Return result */
1386
1387 decl = NewStringEmpty();
1388 id = NewStringEmpty();
1389 value = NewStringEmpty();
1390 comment = NewStringEmpty();
1391 chunk = NewStringEmpty();
1392 copy_location(s, chunk);
1393 copy_location(s, ns);
1394 symbols = Getattr(cpp, kpp_symbols);
1395
1396 state = 0;
1397 while ((c = Getc(s)) != EOF) {
1398 switch (state) {
1399 case 0: /* Initial state - in first column */
1400 /* Look for C preprocessor directives. Otherwise, go directly to state 1 */
1401 if (c == '#') {
1402 copy_location(s, chunk);
1403 add_chunk(ns, chunk, allow);
1404 cpp_lines = 1;
1405 state = 40;
1406 } else if (isspace(c)) {
1407 Putc(c, chunk);
1408 skip_whitespace(s, chunk);
1409 } else {
1410 state = 1;
1411 Ungetc(c, s);
1412 }
1413 break;
1414 case 1: /* Non-preprocessor directive */
1415 /* Look for SWIG directives */
1416 if (c == '%') {
1417 state = 100;
1418 break;
1419 }
1420 Putc(c, chunk);
1421 if (c == '\n')
1422 state = 0;
1423 else if (c == '\"') {
1424 start_line = Getline(s);
1425 if (skip_tochar(s, '\"', chunk) < 0) {
1426 Swig_error(Getfile(s), start_line, "Unterminated string constant\n");
1427 }
1428 } else if (c == '\'') {
1429 start_line = Getline(s);
1430 if (skip_tochar(s, '\'', chunk) < 0) {
1431 Swig_error(Getfile(s), start_line, "Unterminated character constant\n");
1432 }
1433 } else if (c == '/')
1434 state = 30; /* Comment */
1435 break;
1436
1437 case 30: /* Possibly a comment string of some sort */
1438 start_line = Getline(s);
1439 Putc(c, chunk);
1440 if (c == '/')
1441 state = 31;
1442 else if (c == '*')
1443 state = 32;
1444 else
1445 state = 1;
1446 break;
1447 case 31:
1448 Putc(c, chunk);
1449 if (c == '\n')
1450 state = 0;
1451 break;
1452 case 32:
1453 Putc(c, chunk);
1454 if (c == '*')
1455 state = 33;
1456 break;
1457 case 33:
1458 Putc(c, chunk);
1459 if (c == '/')
1460 state = 1;
1461 else if (c != '*')
1462 state = 32;
1463 break;
1464
1465 case 40: /* Start of a C preprocessor directive */
1466 if (c == '\n') {
1467 Putc('\n', chunk);
1468 state = 0;
1469 } else if (isspace(c)) {
1470 state = 40;
1471 } else {
1472 /* Got the start of a preprocessor directive */
1473 Ungetc(c, s);
1474 Clear(id);
1475 copy_location(s, id);
1476 state = 41;
1477 }
1478 break;
1479
1480 case 41: /* Build up the name of the preprocessor directive */
1481 if ((isspace(c) || (!isidchar(c)))) {
1482 Clear(value);
1483 Clear(comment);
1484 if (c == '\n') {
1485 Ungetc(c, s);
1486 state = 50;
1487 } else {
1488 state = 42;
1489 if (!isspace(c)) {
1490 Ungetc(c, s);
1491 }
1492 }
1493
1494 copy_location(s, value);
1495 break;
1496 }
1497 Putc(c, id);
1498 break;
1499
1500 case 42: /* Strip any leading space after the preprocessor directive (before preprocessor value) */
1501 if (isspace(c)) {
1502 if (c == '\n') {
1503 Ungetc(c, s);
1504 state = 50;
1505 }
1506 break;
1507 }
1508 state = 43;
1509 /* FALL THRU */
1510
1511 case 43:
1512 /* Get preprocessor value */
1513 if (c == '\n') {
1514 Ungetc(c, s);
1515 state = 50;
1516 } else if (c == '/') {
1517 state = 45;
1518 } else if (c == '\"') {
1519 Putc(c, value);
1520 skip_tochar(s, '\"', value);
1521 } else if (c == '\'') {
1522 Putc(c, value);
1523 skip_tochar(s, '\'', value);
1524 } else {
1525 Putc(c, value);
1526 if (c == '\\')
1527 state = 44;
1528 }
1529 break;
1530
1531 case 44:
1532 if (c == '\n') {
1533 Putc(c, value);
1534 cpp_lines++;
1535 } else {
1536 Ungetc(c, s);
1537 }
1538 state = 43;
1539 break;
1540
1541 /* States 45-48 are used to remove, but retain comments from macro values. The comments
1542 will be placed in the output in an alternative form */
1543
1544 case 45:
1545 if (c == '/')
1546 state = 46;
1547 else if (c == '*')
1548 state = 47;
1549 else if (c == '\n') {
1550 Putc('/', value);
1551 Ungetc(c, s);
1552 state = 50;
1553 } else {
1554 Putc('/', value);
1555 Putc(c, value);
1556 state = 43;
1557 }
1558 break;
1559 case 46: /* in C++ comment */
1560 if (c == '\n') {
1561 Ungetc(c, s);
1562 state = 50;
1563 } else
1564 Putc(c, comment);
1565 break;
1566 case 47: /* in C comment */
1567 if (c == '*')
1568 state = 48;
1569 else
1570 Putc(c, comment);
1571 break;
1572 case 48:
1573 if (c == '/')
1574 state = 43;
1575 else if (c == '*')
1576 Putc(c, comment);
1577 else {
1578 Putc('*', comment);
1579 Putc(c, comment);
1580 state = 47;
1581 }
1582 break;
1583 case 50:
1584 /* Check for various preprocessor directives */
1585 Chop(value);
1586 if (Equal(id, kpp_define)) {
1587 if (allow) {
1588 DOH *m, *v, *v1;
1589 Seek(value, 0, SEEK_SET);
1590 m = Preprocessor_define(value, 0);
1591 if ((m) && !(Getattr(m, kpp_args))) {
1592 v = Copy(Getattr(m, kpp_value));
1593 copy_location(m, v);
1594 if (Len(v)) {
1595 Swig_error_silent(1);
1596 v1 = Preprocessor_replace(v);
1597 Swig_error_silent(0);
1598 /* Printf(stdout,"checking '%s'\n", v1); */
1599 if (!checkpp_id(v1)) {
1600 if (Len(comment) == 0)
1601 Printf(ns, "%%constant %s = %s;\n", Getattr(m, kpp_name), v1);
1602 else
1603 Printf(ns, "%%constant %s = %s; /*%s*/\n", Getattr(m, kpp_name), v1, comment);
1604 cpp_lines--;
1605 }
1606 Delete(v1);
1607 }
1608 Delete(v);
1609 }
1610 }
1611 } else if (Equal(id, kpp_undef)) {
1612 if (allow)
1613 Preprocessor_undef(value);
1614 } else if (Equal(id, kpp_ifdef)) {
1615 cond_lines[level] = Getline(id);
1616 level++;
1617 if (allow) {
1618 start_level = level;
1619 if (Len(value) > 0) {
1620 /* See if the identifier is in the hash table */
1621 if (!Getattr(symbols, value))
1622 allow = 0;
1623 } else {
1624 Swig_error(Getfile(s), Getline(id), "Missing identifier for #ifdef.\n");
1625 allow = 0;
1626 }
1627 mask = 1;
1628 }
1629 } else if (Equal(id, kpp_ifndef)) {
1630 cond_lines[level] = Getline(id);
1631 level++;
1632 if (allow) {
1633 start_level = level;
1634 if (Len(value) > 0) {
1635 /* See if the identifier is in the hash table */
1636 if (Getattr(symbols, value))
1637 allow = 0;
1638 } else {
1639 Swig_error(Getfile(s), Getline(id), "Missing identifier for #ifndef.\n");
1640 allow = 0;
1641 }
1642 mask = 1;
1643 }
1644 } else if (Equal(id, kpp_else)) {
1645 if (level <= 0) {
1646 Swig_error(Getfile(s), Getline(id), "Misplaced #else.\n");
1647 } else {
1648 cond_lines[level - 1] = Getline(id);
1649 if (Len(value) != 0)
1650 Swig_warning(WARN_PP_UNEXPECTED_TOKENS, Getfile(s), Getline(id), "Unexpected tokens after #else directive.\n");
1651 if (allow) {
1652 allow = 0;
1653 mask = 0;
1654 } else if (level == start_level) {
1655 allow = 1 * mask;
1656 }
1657 }
1658 } else if (Equal(id, kpp_endif)) {
1659 level--;
1660 if (level < 0) {
1661 Swig_error(Getfile(id), Getline(id), "Extraneous #endif.\n");
1662 level = 0;
1663 } else {
1664 if (level < start_level) {
1665 if (Len(value) != 0)
1666 Swig_warning(WARN_PP_UNEXPECTED_TOKENS, Getfile(s), Getline(id), "Unexpected tokens after #endif directive.\n");
1667 allow = 1;
1668 start_level--;
1669 }
1670 }
1671 } else if (Equal(id, kpp_if)) {
1672 cond_lines[level] = Getline(id);
1673 level++;
1674 if (allow) {
1675 int val;
1676 String *sval;
1677 expand_defined_operator = 1;
1678 sval = Preprocessor_replace(value);
1679 start_level = level;
1680 Seek(sval, 0, SEEK_SET);
1681 /* Printf(stdout,"Evaluating '%s'\n", sval); */
1682 if (Len(sval) > 0) {
1683 val = Preprocessor_expr(sval, &e);
1684 if (e) {
1685 const char *msg = Preprocessor_expr_error();
1686 Seek(value, 0, SEEK_SET);
1687 Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Could not evaluate expression '%s'\n", value);
1688 if (msg)
1689 Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Error: '%s'\n", msg);
1690 allow = 0;
1691 } else {
1692 if (val == 0)
1693 allow = 0;
1694 }
1695 } else {
1696 Swig_error(Getfile(s), Getline(id), "Missing expression for #if.\n");
1697 allow = 0;
1698 }
1699 expand_defined_operator = 0;
1700 mask = 1;
1701 }
1702 } else if (Equal(id, kpp_elif)) {
1703 if (level == 0) {
1704 Swig_error(Getfile(s), Getline(id), "Misplaced #elif.\n");
1705 } else {
1706 cond_lines[level - 1] = Getline(id);
1707 if (allow) {
1708 allow = 0;
1709 mask = 0;
1710 } else if (level == start_level) {
1711 int val;
1712 String *sval;
1713 expand_defined_operator = 1;
1714 sval = Preprocessor_replace(value);
1715 Seek(sval, 0, SEEK_SET);
1716 if (Len(sval) > 0) {
1717 val = Preprocessor_expr(sval, &e);
1718 if (e) {
1719 const char *msg = Preprocessor_expr_error();
1720 Seek(value, 0, SEEK_SET);
1721 Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Could not evaluate expression '%s'\n", value);
1722 if (msg)
1723 Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Error: '%s'\n", msg);
1724 allow = 0;
1725 } else {
1726 if (val)
1727 allow = 1 * mask;
1728 else
1729 allow = 0;
1730 }
1731 } else {
1732 Swig_error(Getfile(s), Getline(id), "Missing expression for #elif.\n");
1733 allow = 0;
1734 }
1735 expand_defined_operator = 0;
1736 }
1737 }
1738 } else if (Equal(id, kpp_warning)) {
1739 if (allow) {
1740 Swig_warning(WARN_PP_CPP_WARNING, Getfile(s), Getline(id), "CPP #warning, \"%s\".\n", value);
1741 }
1742 } else if (Equal(id, kpp_error)) {
1743 if (allow) {
1744 if (error_as_warning) {
1745 Swig_warning(WARN_PP_CPP_ERROR, Getfile(s), Getline(id), "CPP #error \"%s\".\n", value);
1746 } else {
1747 Swig_error(Getfile(s), Getline(id), "CPP #error \"%s\". Use the -cpperraswarn option to continue swig processing.\n", value);
1748 }
1749 }
1750 } else if (Equal(id, kpp_line)) {
1751 } else if (Equal(id, kpp_include)) {
1752 if (((include_all) || (import_all)) && (allow)) {
1753 String *s1, *s2, *fn;
1754 String *dirname;
1755 int sysfile = 0;
1756 if (include_all && import_all) {
1757 Swig_warning(WARN_PP_INCLUDEALL_IMPORTALL, Getfile(s), Getline(id), "Both includeall and importall are defined: using includeall.\n");
1758 import_all = 0;
1759 }
1760 Seek(value, 0, SEEK_SET);
1761 fn = get_filename(value, &sysfile);
1762 s1 = cpp_include(fn, sysfile);
1763 if (s1) {
1764 if (include_all)
1765 Printf(ns, "%%includefile \"%s\" %%beginfile\n", Swig_filename_escape(Swig_last_file()));
1766 else if (import_all) {
1767 Printf(ns, "%%importfile \"%s\" %%beginfile\n", Swig_filename_escape(Swig_last_file()));
1768 push_imported();
1769 }
1770
1771 /* See if the filename has a directory component */
1772 dirname = Swig_file_dirname(Swig_last_file());
1773 if (sysfile || !Len(dirname)) {
1774 Delete(dirname);
1775 dirname = 0;
1776 }
1777 if (dirname) {
1778 int len = Len(dirname);
1779 Delslice(dirname, len - 1, len); /* Kill trailing directory delimiter */
1780 Swig_push_directory(dirname);
1781 }
1782 s2 = Preprocessor_parse(s1);
1783 addline(ns, s2, allow);
1784 Append(ns, "%endoffile");
1785 if (dirname) {
1786 Swig_pop_directory();
1787 }
1788 if (import_all) {
1789 pop_imported();
1790 }
1791 Delete(s2);
1792 Delete(dirname);
1793 Delete(s1);
1794 }
1795 Delete(fn);
1796 }
1797 } else if (Equal(id, kpp_pragma)) {
1798 if (Strncmp(value, "SWIG ", 5) == 0) {
1799 char *c = Char(value) + 5;
1800 while (*c && (isspace((int) *c)))
1801 c++;
1802 if (*c) {
1803 if (strncmp(c, "nowarn=", 7) == 0) {
1804 String *val = NewString(c + 7);
1805 String *nowarn = Preprocessor_replace(val);
1806 Swig_warnfilter(nowarn, 1);
1807 Delete(nowarn);
1808 Delete(val);
1809 } else if (strncmp(c, "cpperraswarn=", 13) == 0) {
1810 error_as_warning = atoi(c + 13);
1811 } else {
1812 Swig_error(Getfile(s), Getline(id), "Unknown SWIG pragma: %s\n", c);
1813 }
1814 }
1815 }
1816 } else if (Equal(id, kpp_level)) {
1817 Swig_error(Getfile(s), Getline(id), "cpp debug: level = %d, startlevel = %d\n", level, start_level);
1818 } else if (Equal(id, "")) {
1819 /* Null directive */
1820 } else if (is_digits(id)) {
1821 /* A gcc linemarker of the form '# linenum filename flags' (resulting from running gcc -E) */
1822 } else {
1823 /* Ignore unknown preprocessor directives which are inside an inactive
1824 * conditional (github issue #394). */
1825 if (allow)
1826 Swig_error(Getfile(s), Getline(id), "Unknown SWIG preprocessor directive: %s (if this is a block of target language code, delimit it with %%{ and %%})\n", id);
1827 }
1828 for (i = 0; i < cpp_lines; i++)
1829 Putc('\n', ns);
1830 state = 0;
1831 break;
1832
1833 /* SWIG directives */
1834 case 100:
1835 /* %{,%} block */
1836 if (c == '{') {
1837 start_line = Getline(s);
1838 copy_location(s, chunk);
1839 add_chunk(ns, chunk, allow);
1840 Putc('%', chunk);
1841 Putc(c, chunk);
1842 state = 105;
1843 }
1844 /* %#cpp - an embedded C preprocessor directive (we strip off the %) */
1845 else if (c == '#') {
1846 add_chunk(ns, chunk, allow);
1847 Putc(c, chunk);
1848 state = 107;
1849 } else if (isidentifier(c)) {
1850 Clear(decl);
1851 Putc('%', decl);
1852 Putc(c, decl);
1853 state = 110;
1854 } else {
1855 Putc('%', chunk);
1856 Putc(c, chunk);
1857 state = 1;
1858 }
1859 break;
1860
1861 case 105:
1862 Putc(c, chunk);
1863 if (c == '%')
1864 state = 106;
1865 break;
1866
1867 case 106:
1868 Putc(c, chunk);
1869 if (c == '}') {
1870 state = 1;
1871 addline(ns, chunk, allow);
1872 Clear(chunk);
1873 copy_location(s, chunk);
1874 } else {
1875 state = 105;
1876 }
1877 break;
1878
1879 case 107:
1880 Putc(c, chunk);
1881 if (c == '\n') {
1882 addline(ns, chunk, allow);
1883 Clear(chunk);
1884 state = 0;
1885 } else if (c == '\\') {
1886 state = 108;
1887 }
1888 break;
1889
1890 case 108:
1891 Putc(c, chunk);
1892 state = 107;
1893 break;
1894
1895 case 110:
1896 if (!isidchar(c)) {
1897 Ungetc(c, s);
1898 /* Look for common SWIG directives */
1899 if (Equal(decl, kpp_dinclude) || Equal(decl, kpp_dimport) || Equal(decl, kpp_dextern)) {
1900 /* Got some kind of file inclusion directive, eg: %import(option1="value1") "filename" */
1901 if (allow) {
1902 DOH *s1, *s2, *fn, *opt;
1903 String *options_whitespace = NewStringEmpty();
1904 String *filename_whitespace = NewStringEmpty();
1905 int sysfile = 0;
1906
1907 if (Equal(decl, kpp_dextern)) {
1908 Swig_warning(WARN_DEPRECATED_EXTERN, Getfile(s), Getline(s), "%%extern is deprecated. Use %%import instead.\n");
1909 Clear(decl);
1910 Append(decl, "%%import");
1911 }
1912 skip_whitespace(s, options_whitespace);
1913 opt = get_options(s);
1914
1915 skip_whitespace(s, filename_whitespace);
1916 fn = get_filename(s, &sysfile);
1917 s1 = cpp_include(fn, sysfile);
1918 if (s1) {
1919 String *dirname;
1920 copy_location(s, chunk);
1921 add_chunk(ns, chunk, allow);
1922 Printf(ns, "%sfile%s%s%s\"%s\" %%beginfile\n", decl, options_whitespace, opt, filename_whitespace, Swig_filename_escape(Swig_last_file()));
1923 if (Equal(decl, kpp_dimport)) {
1924 push_imported();
1925 }
1926 dirname = Swig_file_dirname(Swig_last_file());
1927 if (sysfile || !Len(dirname)) {
1928 Delete(dirname);
1929 dirname = 0;
1930 }
1931 if (dirname) {
1932 int len = Len(dirname);
1933 Delslice(dirname, len - 1, len); /* Kill trailing directory delimiter */
1934 Swig_push_directory(dirname);
1935 }
1936 s2 = Preprocessor_parse(s1);
1937 if (dirname) {
1938 Swig_pop_directory();
1939 }
1940 if (Equal(decl, kpp_dimport)) {
1941 pop_imported();
1942 }
1943 addline(ns, s2, allow);
1944 Append(ns, "%endoffile");
1945 Delete(s2);
1946 Delete(dirname);
1947 Delete(s1);
1948 }
1949 Delete(fn);
1950 Delete(filename_whitespace);
1951 Delete(options_whitespace);
1952 }
1953 state = 1;
1954 } else if (Equal(decl, kpp_dbeginfile)) {
1955 /* Got an internal directive marking the beginning of an included file: %beginfile ... %endoffile */
1956 filelevel++;
1957 start_line = Getline(s);
1958 copy_location(s, chunk);
1959 add_chunk(ns, chunk, allow);
1960 Append(chunk, decl);
1961 state = 120;
1962 } else if (Equal(decl, kpp_dline)) {
1963 /* Got a line directive */
1964 state = 1;
1965 } else if (Equal(decl, kpp_ddefine)) {
1966 /* Got a define directive */
1967 dlevel++;
1968 copy_location(s, chunk);
1969 add_chunk(ns, chunk, allow);
1970 Clear(value);
1971 copy_location(s, value);
1972 state = 150;
1973 } else {
1974 Append(chunk, decl);
1975 state = 1;
1976 }
1977 } else {
1978 Putc(c, decl);
1979 }
1980 break;
1981
1982 /* Searching for the end of a %beginfile block */
1983 case 120:
1984 Putc(c, chunk);
1985 if (c == '%') {
1986 const char *bf = "beginfile";
1987 const char *ef = "endoffile";
1988 char statement[10];
1989 int i = 0;
1990 for (i = 0; i < 9;) {
1991 c = Getc(s);
1992 Putc(c, chunk);
1993 statement[i++] = (char)c;
1994 if (strncmp(statement, bf, i) && strncmp(statement, ef, i))
1995 break;
1996 }
1997 c = Getc(s);
1998 Ungetc(c, s);
1999 if ((i == 9) && (isspace(c))) {
2000 if (strncmp(statement, bf, i) == 0) {
2001 ++filelevel;
2002 } else if (strncmp(statement, ef, i) == 0) {
2003 --filelevel;
2004 if (!filelevel) {
2005 /* Reached end of included file */
2006 addline(ns, chunk, allow);
2007 Clear(chunk);
2008 copy_location(s, chunk);
2009 state = 1;
2010 }
2011 }
2012 }
2013 }
2014 break;
2015
2016 /* Searching for the end of a %define statement */
2017 case 150:
2018 Putc(c, value);
2019 if (c == '%') {
2020 const char *ed = "enddef";
2021 const char *df = "define";
2022 char statement[7];
2023 int i = 0;
2024 for (i = 0; i < 6;) {
2025 c = Getc(s);
2026 Putc(c, value);
2027 statement[i++] = (char)c;
2028 if (strncmp(statement, ed, i) && strncmp(statement, df, i))
2029 break;
2030 }
2031 c = Getc(s);
2032 Ungetc(c, s);
2033 if ((i == 6) && (isspace(c))) {
2034 if (strncmp(statement, df, i) == 0) {
2035 ++dlevel;
2036 } else {
2037 if (strncmp(statement, ed, i) == 0) {
2038 --dlevel;
2039 if (!dlevel) {
2040 /* Got the macro */
2041 for (i = 0; i < 7; i++) {
2042 Delitem(value, DOH_END);
2043 }
2044 if (allow) {
2045 Seek(value, 0, SEEK_SET);
2046 Preprocessor_define(value, 1);
2047 }
2048 addline(ns, value, 0);
2049 state = 0;
2050 }
2051 }
2052 }
2053 }
2054 }
2055 break;
2056 default:
2057 Printf(stderr, "cpp: Invalid parser state %d\n", state);
2058 abort();
2059 break;
2060 }
2061 }
2062 while (level > 0) {
2063 Swig_error(Getfile(s), cond_lines[level - 1], "Missing #endif for conditional starting here\n");
2064 level--;
2065 }
2066 if (state == 120) {
2067 Swig_error(Getfile(s), start_line, "Missing %%endoffile for file inclusion block starting here\n");
2068 }
2069 if (state == 150) {
2070 Seek(value, 0, SEEK_SET);
2071 Swig_error(Getfile(s), Getline(value), "Missing %%enddef for macro starting here\n", Getline(value));
2072 }
2073 if ((state >= 105) && (state < 107)) {
2074 Swig_error(Getfile(s), start_line, "Unterminated %%{ ... %%} block\n");
2075 }
2076 if ((state >= 30) && (state < 40)) {
2077 Swig_error(Getfile(s), start_line, "Unterminated comment\n");
2078 }
2079
2080 copy_location(s, chunk);
2081 add_chunk(ns, chunk, allow);
2082
2083 /* DelScope(scp); */
2084 Delete(decl);
2085 Delete(id);
2086 Delete(value);
2087 Delete(comment);
2088 Delete(chunk);
2089
2090 return ns;
2091 }
2092