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