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