swig/Source/Preprocessor/cpp.c
Jamie Kirkpatrick 825e67b2b0 Merged revisions 10487,10498-10499,10503-10504,10506,10508,10511,10515-10516,10518-10519,10527,10530-10531,10536-10537,10539-10552,10558-10568,10574-10580,10582,10584,10588-10589,10594,10607-10610,10616,10621,10624-10629,10633-10641,10643,10647,10649-10650,10662,10672,10676-10677,10682-10683,10714,10726-10727,10738,10743,10747,10749,10794,10801-10809,10827-10831,10834 via svnmerge from
https://swig.svn.sourceforge.net/svnroot/swig/trunk

................
  r10487 | wsfulton | 2008-05-21 23:15:52 +0100 (Wed, 21 May 2008) | 1 line
  
  Apply patch from Petr Viktorin to fix some recent regressions in CFFI/CLOS
................
  r10498 | talby | 2008-05-26 21:09:56 +0100 (Mon, 26 May 2008) | 2 lines
  
  run test cases in the Perl set by the --with-perl5 configure option.
................
  r10499 | talby | 2008-05-26 22:04:06 +0100 (Mon, 26 May 2008) | 3 lines
  
  The perl5 minherit runtime test will work better if the classes are 
  actually built under SWIGPERL.
................
  r10503 | wsfulton | 2008-05-28 10:44:37 +0100 (Wed, 28 May 2008) | 1 line
  
  Fix variable wrappers when using -proxy. Patch from Jan Jezabek
................
  r10504 | bhy | 2008-05-28 18:27:48 +0100 (Wed, 28 May 2008) | 2 lines
  
  Fixed SF #1971977:  typo in pycontainer.swg (related to -extranative option)
................
  r10506 | wsfulton | 2008-05-29 01:45:28 +0100 (Thu, 29 May 2008) | 1 line
  
  Fix variable wrappers when using -noproxy
................
  r10508 | bhy | 2008-05-30 14:53:33 +0100 (Fri, 30 May 2008) | 1 line
  
  Fixed SF #1976978, apply the macros for primitive types to std::wstring
................
  r10511 | olly | 2008-05-30 17:11:27 +0100 (Fri, 30 May 2008) | 4 lines
  
  Fix typo in handling of /*@SWIG[...]*/ comments in the scanner.  This just
  meant we were only actually looking for /*@SWI at the start of the comment, so
  was pretty harmless in practice.
................
  r10515 | wsfulton | 2008-06-02 21:10:40 +0100 (Mon, 02 Jun 2008) | 1 line
  
  Fix samename testcase for c# and java
................
  r10516 | wsfulton | 2008-06-02 21:15:39 +0100 (Mon, 02 Jun 2008) | 1 line
  
  Fix enums when using -noproxy
................
  r10518 | bhy | 2008-06-07 12:20:07 +0100 (Sat, 07 Jun 2008) | 4 lines
  
  Added a test case for keyword renaming.
  Now it works for Python in SWIG's -c++ mode,
  but in C mode it doesn't work! (you can try with make keyword_rename.ctest)
................
  r10519 | bhy | 2008-06-07 14:40:51 +0100 (Sat, 07 Jun 2008) | 1 line
  
  fixed keyword_rename.ctest tese case, caused by a mistake in Swig/naming.c
................
  r10527 | mgossage | 2008-06-17 03:57:15 +0100 (Tue, 17 Jun 2008) | 1 line
  
  [lua] bugfix 1938142 (bool& and bool* support)
................
  r10530 | wsfulton | 2008-06-19 21:02:13 +0100 (Thu, 19 Jun 2008) | 1 line
  
  Add R keyword support. Rename keywords for successful compilation of Java and C# code. More consistent keyword warnings across the different languages.
................
  r10531 | wsfulton | 2008-06-19 22:15:48 +0100 (Thu, 19 Jun 2008) | 1 line
  
  add complete list of R reserved words
................
  r10536 | wsfulton | 2008-06-21 12:35:33 +0100 (Sat, 21 Jun 2008) | 1 line
  
  better terminology for static types
................
  r10537 | wsfulton | 2008-06-21 12:42:48 +0100 (Sat, 21 Jun 2008) | 1 line
  
  remove raise as keyword test- it conflicts with _raise in LIBCMT on windows
................
  r10539 | wsfulton | 2008-06-21 16:21:29 +0100 (Sat, 21 Jun 2008) | 1 line
  
  Lua example warning removal fixes for vc++
................
  r10540 | wsfulton | 2008-06-21 16:23:02 +0100 (Sat, 21 Jun 2008) | 1 line
  
  Remove some vc++ /W4 warnings
................
  r10541 | wsfulton | 2008-06-21 17:04:55 +0100 (Sat, 21 Jun 2008) | 1 line
  
  minor vc++ /W4 warning fixes
................
  r10542 | wsfulton | 2008-06-21 20:07:51 +0100 (Sat, 21 Jun 2008) | 1 line
  
  'byte' is already used in Ruby on windows, so use another keyword
................
  r10543 | wsfulton | 2008-06-21 21:45:32 +0100 (Sat, 21 Jun 2008) | 1 line
  
  Fix crashing in the Ruby reject method in the STL wrappers
................
  r10544 | wsfulton | 2008-06-21 21:48:28 +0100 (Sat, 21 Jun 2008) | 1 line
  
  Fix crashing in the Ruby reject method in the STL wrappers
................
  r10545 | wsfulton | 2008-06-21 21:49:10 +0100 (Sat, 21 Jun 2008) | 1 line
  
  remove unnecessary variable int the char **STRING_ARRAY out typemap
................
  r10546 | wsfulton | 2008-06-21 22:07:49 +0100 (Sat, 21 Jun 2008) | 1 line
  
  Fix Ruby C++ example dependencies in dsp files
................
  r10547 | wsfulton | 2008-06-21 23:25:36 +0100 (Sat, 21 Jun 2008) | 1 line
  
  Fix unused parameter warnings in python when using gcc's -W -Wall options
................
  r10548 | wsfulton | 2008-06-21 23:26:35 +0100 (Sat, 21 Jun 2008) | 1 line
  
  Fix virtual destructor
................
  r10549 | wsfulton | 2008-06-22 00:25:20 +0100 (Sun, 22 Jun 2008) | 1 line
  
  various warning fixes
................
  r10550 | wsfulton | 2008-06-22 01:09:11 +0100 (Sun, 22 Jun 2008) | 1 line
  
  Another fix for the JVM hanging on exit problem when using directors
................
  r10551 | wsfulton | 2008-06-22 01:09:51 +0100 (Sun, 22 Jun 2008) | 1 line
  
  documentation sections update
................
  r10552 | wsfulton | 2008-06-22 01:18:10 +0100 (Sun, 22 Jun 2008) | 1 line
  
  more docs on defining macros for the thread hanging problem
................
  r10558 | wsfulton | 2008-06-22 22:30:20 +0100 (Sun, 22 Jun 2008) | 1 line
  
  fix unused parms in last commit for C code
................
  r10559 | wsfulton | 2008-06-22 23:12:43 +0100 (Sun, 22 Jun 2008) | 1 line
  
  Suppress unused methods warning for VC++
................
  r10560 | wsfulton | 2008-06-23 21:26:07 +0100 (Mon, 23 Jun 2008) | 1 line
  
  fix partialcheck-test-suite and parallel make for r, chicken, tcl and php
................
  r10561 | wsfulton | 2008-06-23 21:39:41 +0100 (Mon, 23 Jun 2008) | 1 line
  
  correct message display when running the partialcheck-test-suite make target
................
  r10562 | wsfulton | 2008-06-23 22:14:53 +0100 (Mon, 23 Jun 2008) | 1 line
  
  fix typo
................
  r10563 | olly | 2008-06-23 22:23:54 +0100 (Mon, 23 Jun 2008) | 3 lines
  
  Fix bad use of Python API (untested, since I can't even compile this code on
  x86-64!)
................
  r10564 | olly | 2008-06-23 23:58:03 +0100 (Mon, 23 Jun 2008) | 3 lines
  
  [PHP] Fix segfault when wrapping a non-class function marked with
  %newobject (testcase char_strings).
................
  r10565 | olly | 2008-06-24 01:27:34 +0100 (Tue, 24 Jun 2008) | 3 lines
  
  [PHP] Fix assertion failure when handling %typemap(in,numinputs=0)
  (testcase ignore_parameter).
................
  r10566 | olly | 2008-06-24 01:33:08 +0100 (Tue, 24 Jun 2008) | 2 lines
  
  [PHP] Fix typemap_namespace.i to not try to copy a non-existent typemap.
................
  r10567 | olly | 2008-06-24 01:41:07 +0100 (Tue, 24 Jun 2008) | 3 lines
  
  Clean up dead and unused code in SwigToPhpType(), and rename to
  GetShadowReturnType().
................
  r10568 | olly | 2008-06-24 01:42:29 +0100 (Tue, 24 Jun 2008) | 2 lines
  
  Fix cosmetic typo in string constant.
................
  r10574 | wsfulton | 2008-06-24 21:10:28 +0100 (Tue, 24 Jun 2008) | 1 line
  
  zap last entry
................
  r10575 | wsfulton | 2008-06-24 21:11:46 +0100 (Tue, 24 Jun 2008) | 1 line
  
  variable name changes to remove php keywords
................
  r10576 | wsfulton | 2008-06-24 21:12:08 +0100 (Tue, 24 Jun 2008) | 1 line
  
  variable name hiding fix
................
  r10577 | wsfulton | 2008-06-24 21:12:43 +0100 (Tue, 24 Jun 2008) | 1 line
  
  More info about numobjects added
................
  r10578 | wsfulton | 2008-06-24 21:13:41 +0100 (Tue, 24 Jun 2008) | 1 line
  
  update for 1.3.36 release
................
  r10579 | wsfulton | 2008-06-24 22:48:46 +0100 (Tue, 24 Jun 2008) | 1 line
  
  remove deprecated -c commandline option (runtime library generation)
................
  r10580 | wsfulton | 2008-06-24 22:53:12 +0100 (Tue, 24 Jun 2008) | 1 line
  
  correct comment about deprecated option
................
  r10582 | wsfulton | 2008-06-25 00:00:27 +0100 (Wed, 25 Jun 2008) | 1 line
  
  use rsync and ssh to upload releases to SourceForge as ftp no longer works
................
  r10584 | wsfulton | 2008-06-25 00:24:48 +0100 (Wed, 25 Jun 2008) | 1 line
  
  correction for 1.3.36
................
  r10588 | wsfulton | 2008-06-25 01:16:04 +0100 (Wed, 25 Jun 2008) | 1 line
  
  section update
................
  r10589 | wsfulton | 2008-06-25 01:16:40 +0100 (Wed, 25 Jun 2008) | 1 line
  
  bump version to 1.3.37
................
  r10594 | wsfulton | 2008-06-26 19:33:06 +0100 (Thu, 26 Jun 2008) | 1 line
  
  correct typo in first entry about %fragment
................
  r10607 | wsfulton | 2008-06-29 01:19:05 +0100 (Sun, 29 Jun 2008) | 1 line
  
  fix some potential null pointer usage as reported by CoveriCoverity Prevent
................
  r10608 | wsfulton | 2008-06-29 01:50:27 +0100 (Sun, 29 Jun 2008) | 1 line
  
  fix potential null pointer usage as reported by Coverity Prevent
................
  r10609 | wsfulton | 2008-06-29 10:57:41 +0100 (Sun, 29 Jun 2008) | 1 line
  
  make life easier for svn status updates as everyone has different autotool versions installed - use svn:ignore on config.sub and config.guess
................
  r10610 | wsfulton | 2008-06-29 11:08:14 +0100 (Sun, 29 Jun 2008) | 1 line
  
  make life easier for svn status updates as everyone has different autotool versions installed - use svn:ignore on config.sub and config.guess
................
  r10616 | talby | 2008-07-01 00:41:27 +0100 (Tue, 01 Jul 2008) | 2 lines
  
  Hopefully this provides more portable values for Infinity and NaN in Perl.
................
  r10621 | wsfulton | 2008-07-01 23:02:14 +0100 (Tue, 01 Jul 2008) | 1 line
  
  update old commandline option
................
  r10624 | olly | 2008-07-02 04:17:46 +0100 (Wed, 02 Jul 2008) | 5 lines
  
  [Python] Import the C extension differently for Python 2.6 and
  later so that an implicit relative import doesn't produce a
  deprecation warning for 2.6 and a failure for 2.7 and later.
  Patch from Richard Boulton in SF#2008229.
................
  r10625 | bhy | 2008-07-02 05:56:11 +0100 (Wed, 02 Jul 2008) | 1 line
  
  fix the relative import patch by try both relative and absolute import
................
  r10626 | olly | 2008-07-02 06:55:18 +0100 (Wed, 02 Jul 2008) | 4 lines
  
  [PHP4] Support for PHP4 has been removed.  The PHP developers are
  no longer making new PHP4 releases, and won't even be patching
  critical security issues after 2008-08-08.
................
  r10627 | bhy | 2008-07-02 07:06:56 +0100 (Wed, 02 Jul 2008) | 1 line
  
  fix the previous commit -- new approach using imp module
................
  r10628 | bhy | 2008-07-02 07:29:15 +0100 (Wed, 02 Jul 2008) | 1 line
  
  minor fix on relative import: close fp if exception occured during imp.find_module
................
  r10629 | bhy | 2008-07-02 08:08:00 +0100 (Wed, 02 Jul 2008) | 1 line
  
  reconstruct the relative import, now the generated code looks better
................
  r10633 | olly | 2008-07-03 01:09:56 +0100 (Thu, 03 Jul 2008) | 9 lines
  
  WARN_* constants are user visible, so keep existing WARN_PHP4_* for
  backward compatibility, but add preferred forms WARN_PHP_* and use
  these ourselves.
  
  Rename Lib/php4 to Lib/php, Source/Modules/php4.cxx to Source/Modules/php.cxx.
   
  Add typemaps for const reference so Examples/test-suite/apply_signed_char.i
  works.
................
  r10634 | olly | 2008-07-03 01:12:58 +0100 (Thu, 03 Jul 2008) | 2 lines
  
  Remove file added in error.
................
  r10635 | olly | 2008-07-03 01:37:38 +0100 (Thu, 03 Jul 2008) | 2 lines
  
  Rename php4*.swg to php*.swg.
................
  r10636 | olly | 2008-07-03 02:13:51 +0100 (Thu, 03 Jul 2008) | 2 lines
  
  Update wrt PHP4.
................
  r10637 | olly | 2008-07-03 03:32:11 +0100 (Thu, 03 Jul 2008) | 4 lines
  
  [PHP] The deprecated command line option "-phpfull" has been
  removed.  We recommend building your extension as a dynamically
  loadable module.
................
  r10638 | olly | 2008-07-03 03:32:41 +0100 (Thu, 03 Jul 2008) | 2 lines
  
  Fix version number
................
  r10639 | olly | 2008-07-03 07:04:24 +0100 (Thu, 03 Jul 2008) | 2 lines
  
  Make t_output_helper() static.
................
  r10640 | olly | 2008-07-03 07:05:34 +0100 (Thu, 03 Jul 2008) | 2 lines
  
  Make testcase li_typemaps work for PHP.
................
  r10641 | olly | 2008-07-03 10:12:16 +0100 (Thu, 03 Jul 2008) | 2 lines
  
  Fix check::classname() to compare case-insensitively and not try to interpolate objects into strings.
................
  r10643 | olly | 2008-07-03 23:00:01 +0100 (Thu, 03 Jul 2008) | 4 lines
  
  The operator& trick in allowexcept.i doesn't work for SWIG/PHP because the
  generated code takes the address of the variable in the code in the "vinit"
  section.  So comment out the private operator& for PHP.
................
  r10647 | olly | 2008-07-04 00:55:33 +0100 (Fri, 04 Jul 2008) | 2 lines
  
  [PHP] The SWIG cdata.i library module is now supported.
................
  r10649 | olly | 2008-07-04 02:02:22 +0100 (Fri, 04 Jul 2008) | 4 lines
  
  [PHP] The deprecated command line option "-make" has been removed.  
  Searches on Google codesearch suggest that nobody is using it now
  anyway.
................
  r10650 | olly | 2008-07-04 02:22:11 +0100 (Fri, 04 Jul 2008) | 4 lines
  
  [PHP] For std_vector.i and std_map.i, rename empty() to is_empty()
  since "empty" is a PHP reserved word.  Based of patch from Mark Klein
  in SF#1943417.
................
  r10662 | wsfulton | 2008-07-14 22:09:23 +0100 (Mon, 14 Jul 2008) | 1 line
  
  Fix director typemaps for pointers so that NULL pointers are correctly marshalled to C#/Java null in director methods
................
  r10672 | olly | 2008-07-17 02:17:08 +0100 (Thu, 17 Jul 2008) | 2 lines
  
  Fix a typo; improve wording.
................
  r10676 | wsfulton | 2008-07-17 22:05:49 +0100 (Thu, 17 Jul 2008) | 1 line
  
  SF #2019156 Configuring with --without-octave or --without-alllang did not disable octave.
................
  r10677 | wsfulton | 2008-07-17 22:08:22 +0100 (Thu, 17 Jul 2008) | 1 line
  
  tidy output after detecting X11 headers
................
  r10682 | wsfulton | 2008-07-19 19:08:06 +0100 (Sat, 19 Jul 2008) | 1 line
  
  a bit more on pgcpp
................
  r10683 | wsfulton | 2008-07-19 23:45:54 +0100 (Sat, 19 Jul 2008) | 1 line
  
  Fix building of Tcl examples/test-suite on Mac OSX
................
  r10714 | olly | 2008-07-27 13:51:16 +0100 (Sun, 27 Jul 2008) | 2 lines
  
  Fix "can can" typo in docs (SF#2026756)
................
  r10726 | wuzzeb | 2008-08-02 09:28:02 +0100 (Sat, 02 Aug 2008) | 1 line
  
  Commit patch 2019314
................
  r10727 | wuzzeb | 2008-08-02 09:49:43 +0100 (Sat, 02 Aug 2008) | 1 line
  
  add assert.h to fix chicken build of external runtime (ext_test testsuite)
................
  r10738 | talby | 2008-08-07 07:28:13 +0100 (Thu, 07 Aug 2008) | 2 lines
  
  hoist globals to local scope where trival.
................
  r10743 | talby | 2008-08-08 04:10:55 +0100 (Fri, 08 Aug 2008) | 2 lines
  
  initial steps to clean up perl5 class methods (primarily constructors).
................
  r10747 | talby | 2008-08-09 05:08:26 +0100 (Sat, 09 Aug 2008) | 2 lines
  
  moves perl space constructor fixups into wrapper code.
................
  r10749 | talby | 2008-08-10 00:57:55 +0100 (Sun, 10 Aug 2008) | 2 lines
  
  usage_func() fix + CHANGES.current entry to explain my past few commits.
................
  r10794 | talby | 2008-08-19 08:09:29 +0100 (Tue, 19 Aug 2008) | 3 lines
  
  rollback 10737:10749, this work is better left on a branch until it is 
  in support a significant feature enhancement.
................
  r10801 | drjoe | 2008-08-31 17:07:43 +0100 (Sun, 31 Aug 2008) | 2 lines
  
  change Rf_warning to warning.  Looks like a typo
................
  r10802 | wsfulton | 2008-09-01 20:59:23 +0100 (Mon, 01 Sep 2008) | 1 line
  
  Fix ruby detection problem breaking configure
................
  r10803 | wsfulton | 2008-09-01 21:00:28 +0100 (Mon, 01 Sep 2008) | 1 line
  
  Fix another perl global namespace pollution
................
  r10804 | wsfulton | 2008-09-01 21:32:53 +0100 (Mon, 01 Sep 2008) | 1 line
  
  Fix array bounds checking in C# std::vector wrappers
................
  r10805 | wsfulton | 2008-09-01 21:34:49 +0100 (Mon, 01 Sep 2008) | 1 line
  
  fix runtime problem in Ruby std_vector example
................
  r10806 | wsfulton | 2008-09-01 21:42:40 +0100 (Mon, 01 Sep 2008) | 1 line
  
  Fix portability problem using /dev/null
................
  r10807 | wsfulton | 2008-09-01 22:46:41 +0100 (Mon, 01 Sep 2008) | 1 line
  
  patch #2079381 submitted by Boris Smilga - constant exprs put into no-eval context in DEFCENUM
................
  r10808 | wsfulton | 2008-09-02 21:56:52 +0100 (Tue, 02 Sep 2008) | 1 line
  
  Add new terminator attribute for the csin typemap for C#
................
  r10809 | wsfulton | 2008-09-03 00:01:37 +0100 (Wed, 03 Sep 2008) | 1 line
  
  Fix #1988296 - Multiple module director linking issue
................
  r10827 | richardb | 2008-09-10 11:08:21 +0100 (Wed, 10 Sep 2008) | 6 lines
  
  [Python] Commit patch #2089149: Director exception handling mangles
  returned exception.  Exceptions raised by Python code in directors
  are now passed through to the caller without change.  Also, remove
  the ": " prefix which used to be added to other director exceptions
  (eg, those due to incorrect return types).
................
  r10828 | bhy | 2008-09-10 11:45:33 +0100 (Wed, 10 Sep 2008) | 3 lines
  
  Initialized merge tracking via "svnmerge" with revisions "1-10827" from 
  https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2008-bhy
................
  r10829 | bhy | 2008-09-10 12:04:09 +0100 (Wed, 10 Sep 2008) | 4 lines
  
  Removed merge tracking for "svnmerge" for 
  https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2008-bhy
  (Undo the init due to user error)
................
  r10830 | bhy | 2008-09-10 12:08:16 +0100 (Wed, 10 Sep 2008) | 3 lines
  
  Initialized merge tracking via "svnmerge" with revisions "1-10403" from 
  https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2008-bhy
................
  r10831 | bhy | 2008-09-10 12:51:12 +0100 (Wed, 10 Sep 2008) | 11 lines
  
  (Still trying to set right properity to get svnmerge work...)
  Recorded merge of revisions 10404 via svnmerge from 
  https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2008-bhy
  
  ........
    r10404 | bhy | 2008-05-01 08:35:49 +0800 (Thu, 01 May 2008) | 5 lines
    
    Start of gsoc2008-bhy branch. This is a branch for Haoyu Bai's Python 3.0 backend project.
    Some file already modified since a little of work already done when starting the branch. 
  ........
................
  r10834 | bhy | 2008-09-11 18:18:07 +0100 (Thu, 11 Sep 2008) | 8 lines
  
  Merged the Python 3.0 support branch. The merging progress is not so smooth, so hope this commit won't make anything broken.
  
  This is the (incomplemete) log produced by svnmerge.py:
  
  Merged revisions 10405-10409,10420-10422,10426,10438,10445,10451,10454-10465,10467,10473-10475,10485,10488-10489,10493-10495,10497,10509-10510,10513-10514,10517,10520,10525,10528-10529,10533-10535,10554-10557,10570,10573,10593,10614,10666-10669,10673,10678,10687,10690,10704-10706,10731,10744,10750-10752,10755,10759,10770,10775-10776,10813,10819 via svnmerge from 
  https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2008-bhy
................


git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2008-cherylfoil@10837 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2008-09-12 10:51:51 +00:00

1859 lines
45 KiB
C

/* -----------------------------------------------------------------------------
* See the LICENSE file for information on copyright, usage and redistribution
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
*
* cpp.c
*
* An implementation of a C preprocessor plus some support for additional
* SWIG directives.
*
* - SWIG directives such as %include, %extern, and %import are handled
* - A new macro %define ... %enddef can be used for multiline macros
* - No preprocessing is performed in %{ ... %} blocks
* - Lines beginning with %# are stripped down to #... and passed through.
* ----------------------------------------------------------------------------- */
char cvsroot_cpp_c[] = "$Id$";
#include "swig.h"
#include "preprocessor.h"
#include <ctype.h>
static Hash *cpp = 0; /* C preprocessor data */
static int include_all = 0; /* Follow all includes */
static int ignore_missing = 0;
static int import_all = 0; /* Follow all includes, but as %import statements */
static int imported_depth = 0; /* Depth of %imported files */
static int single_include = 1; /* Only include each file once */
static Hash *included_files = 0;
static List *dependencies = 0;
static Scanner *id_scan = 0;
static int error_as_warning = 0; /* Understand the cpp #error directive as a special #warning */
/* Test a character to see if it starts an identifier */
#define isidentifier(c) ((isalpha(c)) || (c == '_') || (c == '$'))
/* Test a character to see if it valid in an identifier (after the first letter) */
#define isidchar(c) ((isalnum(c)) || (c == '_') || (c == '$'))
DOH *Preprocessor_replace(DOH *);
/* Skip whitespace */
static void skip_whitespace(String *s, String *out) {
int c;
while ((c = Getc(s)) != EOF) {
if (!isspace(c)) {
Ungetc(c, s);
break;
} else if (out)
Putc(c, out);
}
}
/* Skip to a specified character taking line breaks into account */
static int skip_tochar(String *s, int ch, String *out) {
int c;
while ((c = Getc(s)) != EOF) {
if (out)
Putc(c, out);
if (c == ch)
break;
if (c == '\\') {
c = Getc(s);
if ((c != EOF) && (out))
Putc(c, out);
}
}
if (c == EOF)
return -1;
return 0;
}
static void copy_location(const DOH *s1, DOH *s2) {
Setfile(s2, Getfile((DOH *) s1));
Setline(s2, Getline((DOH *) s1));
}
static String *cpp_include(String_or_char *fn, int sysfile) {
String *s = sysfile ? Swig_include_sys(fn) : Swig_include(fn);
if (s && single_include) {
String *file = Getfile(s);
if (Getattr(included_files, file)) {
Delete(s);
return 0;
}
Setattr(included_files, file, file);
}
if (!s) {
Seek(fn, 0, SEEK_SET);
if (ignore_missing) {
Swig_warning(WARN_PP_MISSING_FILE, Getfile(fn), Getline(fn), "Unable to find '%s'\n", fn);
} else {
Swig_error(Getfile(fn), Getline(fn), "Unable to find '%s'\n", fn);
}
} else {
String *lf;
Seek(s, 0, SEEK_SET);
if (!dependencies) {
dependencies = NewList();
}
lf = Copy(Swig_last_file());
Append(dependencies, lf);
Delete(lf);
}
return s;
}
List *Preprocessor_depend(void) {
return dependencies;
}
/* -----------------------------------------------------------------------------
* void Preprocessor_cpp_init() - Initialize the preprocessor
* ----------------------------------------------------------------------------- */
static String *kpp_args = 0;
static String *kpp_define = 0;
static String *kpp_defined = 0;
static String *kpp_elif = 0;
static String *kpp_else = 0;
static String *kpp_endif = 0;
static String *kpp_expanded = 0;
static String *kpp_if = 0;
static String *kpp_ifdef = 0;
static String *kpp_ifndef = 0;
static String *kpp_name = 0;
static String *kpp_swigmacro = 0;
static String *kpp_symbols = 0;
static String *kpp_undef = 0;
static String *kpp_value = 0;
static String *kpp_varargs = 0;
static String *kpp_error = 0;
static String *kpp_warning = 0;
static String *kpp_line = 0;
static String *kpp_include = 0;
static String *kpp_pragma = 0;
static String *kpp_level = 0;
static String *kpp_dline = 0;
static String *kpp_ddefine = 0;
static String *kpp_dinclude = 0;
static String *kpp_dimport = 0;
static String *kpp_dextern = 0;
static String *kpp_LINE = 0;
static String *kpp_FILE = 0;
void Preprocessor_init(void) {
Hash *s;
kpp_args = NewString("args");
kpp_define = NewString("define");
kpp_defined = NewString("defined");
kpp_else = NewString("else");
kpp_elif = NewString("elif");
kpp_endif = NewString("endif");
kpp_expanded = NewString("*expanded*");
kpp_if = NewString("if");
kpp_ifdef = NewString("ifdef");
kpp_ifndef = NewString("ifndef");
kpp_name = NewString("name");
kpp_swigmacro = NewString("swigmacro");
kpp_symbols = NewString("symbols");
kpp_undef = NewString("undef");
kpp_value = NewString("value");
kpp_error = NewString("error");
kpp_warning = NewString("warning");
kpp_pragma = NewString("pragma");
kpp_level = NewString("level");
kpp_line = NewString("line");
kpp_include = NewString("include");
kpp_varargs = NewString("varargs");
kpp_dinclude = NewString("%include");
kpp_dimport = NewString("%import");
kpp_dextern = NewString("%extern");
kpp_ddefine = NewString("%define");
kpp_dline = NewString("%line");
kpp_LINE = NewString("__LINE__");
kpp_FILE = NewString("__FILE__");
cpp = NewHash();
s = NewHash();
Setattr(cpp, kpp_symbols, s);
Delete(s);
Preprocessor_expr_init(); /* Initialize the expression evaluator */
included_files = NewHash();
id_scan = NewScanner();;
}
void Preprocessor_delete(void) {
Delete(kpp_args);
Delete(kpp_define);
Delete(kpp_defined);
Delete(kpp_else);
Delete(kpp_elif);
Delete(kpp_endif);
Delete(kpp_expanded);
Delete(kpp_if);
Delete(kpp_ifdef);
Delete(kpp_ifndef);
Delete(kpp_name);
Delete(kpp_swigmacro);
Delete(kpp_symbols);
Delete(kpp_undef);
Delete(kpp_value);
Delete(kpp_error);
Delete(kpp_warning);
Delete(kpp_pragma);
Delete(kpp_level);
Delete(kpp_line);
Delete(kpp_include);
Delete(kpp_varargs);
Delete(kpp_dinclude);
Delete(kpp_dimport);
Delete(kpp_dextern);
Delete(kpp_ddefine);
Delete(kpp_dline);
Delete(kpp_LINE);
Delete(kpp_FILE);
Delete(cpp);
Delete(included_files);
Preprocessor_expr_delete();
DelScanner(id_scan);
Delete(dependencies);
Delete(Swig_add_directory(0));
}
/* -----------------------------------------------------------------------------
* void Preprocessor_include_all() - Instruct preprocessor to include all files
* ----------------------------------------------------------------------------- */
void Preprocessor_include_all(int a) {
include_all = a;
}
void Preprocessor_import_all(int a) {
import_all = a;
}
void Preprocessor_ignore_missing(int a) {
ignore_missing = a;
}
void Preprocessor_error_as_warning(int a) {
error_as_warning = a;
}
/* -----------------------------------------------------------------------------
* Preprocessor_define()
*
* Defines a new C preprocessor symbol. swigmacro specifies whether or not the macro has
* SWIG macro semantics.
* ----------------------------------------------------------------------------- */
String_or_char *Macro_vararg_name(String_or_char *str, String_or_char *line) {
String_or_char *argname, *varargname;
char *s, *dots;
argname = Copy(str);
s = Char(argname);
dots = strchr(s, '.');
if (!dots) {
Delete(argname);
return NULL;
}
if (strcmp(dots, "...") != 0) {
Swig_error(Getfile(line), Getline(line), "Illegal macro argument name '%s'\n", str);
Delete(argname);
return NULL;
}
if (dots == s) {
varargname = NewString("__VA_ARGS__");
} else {
*dots = '\0';
varargname = NewString(s);
}
Delete(argname);
return varargname;
}
Hash *Preprocessor_define(const String_or_char *_str, int swigmacro) {
String *macroname = 0, *argstr = 0, *macrovalue = 0, *file = 0, *s = 0;
Hash *macro = 0, *symbols = 0, *m1;
List *arglist = 0;
int c, line;
int varargs = 0;
String_or_char *str = (String_or_char *) _str;
assert(cpp);
assert(str);
/* First make sure that string is actually a string */
if (DohCheck(str)) {
s = Copy(str);
copy_location(str, s);
str = s;
} else {
str = NewString((char *) str);
}
Seek(str, 0, SEEK_SET);
line = Getline(str);
file = Getfile(str);
/* Skip over any leading whitespace */
skip_whitespace(str, 0);
/* Now look for a macro name */
macroname = NewStringEmpty();
while ((c = Getc(str)) != EOF) {
if (c == '(') {
argstr = NewStringEmpty();
copy_location(str, argstr);
/* It is a macro. Go extract its argument string */
while ((c = Getc(str)) != EOF) {
if (c == ')')
break;
else
Putc(c, argstr);
}
if (c != ')') {
Swig_error(Getfile(str), Getline(str), "Missing \')\' in macro parameters\n");
goto macro_error;
}
break;
} else if (isidchar(c) || (c == '%')) {
Putc(c, macroname);
} else if (isspace(c)) {
break;
} else if (c == '\\') {
c = Getc(str);
if (c != '\n') {
Ungetc(c, str);
Ungetc('\\', str);
break;
}
} else {
/*Swig_error(Getfile(str),Getline(str),"Illegal character in macro name\n");
goto macro_error; */
Ungetc(c, str);
break;
}
}
if (!swigmacro)
skip_whitespace(str, 0);
macrovalue = NewStringEmpty();
while ((c = Getc(str)) != EOF) {
Putc(c, macrovalue);
}
/* If there are any macro arguments, convert into a list */
if (argstr) {
String *argname, *varargname;
arglist = NewList();
Seek(argstr, 0, SEEK_SET);
argname = NewStringEmpty();
while ((c = Getc(argstr)) != EOF) {
if (c == ',') {
varargname = Macro_vararg_name(argname, str);
if (varargname) {
Delete(varargname);
Swig_error(Getfile(str), Getline(str), "Variable-length macro argument must be last parameter\n");
} else {
Append(arglist, argname);
}
Delete(argname);
argname = NewStringEmpty();
} else if (isidchar(c) || (c == '.')) {
Putc(c, argname);
} else if (!(isspace(c) || (c == '\\'))) {
Delete(argname);
Swig_error(Getfile(str), Getline(str), "Illegal character in macro argument name\n");
goto macro_error;
}
}
if (Len(argname)) {
/* Check for varargs */
varargname = Macro_vararg_name(argname, str);
if (varargname) {
Append(arglist, varargname);
Delete(varargname);
varargs = 1;
} else {
Append(arglist, argname);
}
}
Delete(argname);
}
if (!swigmacro) {
Replace(macrovalue, "\\\n", " ", DOH_REPLACE_NOQUOTE);
}
/* Look for special # substitutions. We only consider # that appears
outside of quotes and comments */
{
int state = 0;
char *cc = Char(macrovalue);
while (*cc) {
switch (state) {
case 0:
if (*cc == '#')
*cc = '\001';
else if (*cc == '/')
state = 10;
else if (*cc == '\'')
state = 20;
else if (*cc == '\"')
state = 30;
break;
case 10:
if (*cc == '*')
state = 11;
else if (*cc == '/')
state = 15;
else {
state = 0;
cc--;
}
break;
case 11:
if (*cc == '*')
state = 12;
break;
case 12:
if (*cc == '/')
state = 0;
else if (*cc != '*')
state = 11;
break;
case 15:
if (*cc == '\n')
state = 0;
break;
case 20:
if (*cc == '\'')
state = 0;
if (*cc == '\\')
state = 21;
break;
case 21:
state = 20;
break;
case 30:
if (*cc == '\"')
state = 0;
if (*cc == '\\')
state = 31;
break;
case 31:
state = 30;
break;
default:
break;
}
cc++;
}
}
/* Get rid of whitespace surrounding # */
/* Replace(macrovalue,"#","\001",DOH_REPLACE_NOQUOTE); */
while (strstr(Char(macrovalue), "\001 ")) {
Replace(macrovalue, "\001 ", "\001", DOH_REPLACE_ANY);
}
while (strstr(Char(macrovalue), " \001")) {
Replace(macrovalue, " \001", "\001", DOH_REPLACE_ANY);
}
/* Replace '##' with a special token */
Replace(macrovalue, "\001\001", "\002", DOH_REPLACE_ANY);
/* Replace '#@' with a special token */
Replace(macrovalue, "\001@", "\004", DOH_REPLACE_ANY);
/* Replace '##@' with a special token */
Replace(macrovalue, "\002@", "\005", DOH_REPLACE_ANY);
/* Go create the macro */
macro = NewHash();
Setattr(macro, kpp_name, macroname);
if (arglist) {
Setattr(macro, kpp_args, arglist);
Delete(arglist);
if (varargs) {
Setattr(macro, kpp_varargs, "1");
}
}
Setattr(macro, kpp_value, macrovalue);
Setline(macro, line);
Setfile(macro, file);
if (swigmacro) {
Setattr(macro, kpp_swigmacro, "1");
}
symbols = Getattr(cpp, kpp_symbols);
if ((m1 = Getattr(symbols, macroname))) {
if (!Checkattr(m1, kpp_value, macrovalue)) {
Swig_error(Getfile(str), Getline(str), "Macro '%s' redefined,\n", macroname);
Swig_error(Getfile(m1), Getline(m1), "previous definition of '%s'.\n", macroname);
goto macro_error;
}
} else {
Setattr(symbols, macroname, macro);
Delete(macro);
}
Delete(macroname);
Delete(macrovalue);
Delete(str);
Delete(argstr);
return macro;
macro_error:
Delete(str);
Delete(argstr);
Delete(arglist);
Delete(macroname);
Delete(macrovalue);
return 0;
}
/* -----------------------------------------------------------------------------
* Preprocessor_undef()
*
* Undefines a macro.
* ----------------------------------------------------------------------------- */
void Preprocessor_undef(const String_or_char *str) {
Hash *symbols;
assert(cpp);
symbols = Getattr(cpp, kpp_symbols);
Delattr(symbols, str);
}
/* -----------------------------------------------------------------------------
* find_args()
*
* Isolates macro arguments and returns them in a list. For each argument,
* leading and trailing whitespace is stripped (ala K&R, pg. 230).
* ----------------------------------------------------------------------------- */
static List *find_args(String *s) {
List *args;
String *str;
int c, level;
long pos;
/* Create a new list */
args = NewList();
copy_location(s, args);
/* First look for a '(' */
pos = Tell(s);
skip_whitespace(s, 0);
/* Now see if the next character is a '(' */
c = Getc(s);
if (c != '(') {
/* Not a macro, bail out now! */
Seek(s, pos, SEEK_SET);
Delete(args);
return 0;
}
c = Getc(s);
/* Okay. This appears to be a macro so we will start isolating arguments */
while (c != EOF) {
if (isspace(c)) {
skip_whitespace(s, 0); /* Skip leading whitespace */
c = Getc(s);
}
str = NewStringEmpty();
copy_location(s, str);
level = 0;
while (c != EOF) {
if (c == '\"') {
Putc(c, str);
skip_tochar(s, '\"', str);
c = Getc(s);
continue;
} else if (c == '\'') {
Putc(c, str);
skip_tochar(s, '\'', str);
c = Getc(s);
continue;
}
if ((c == ',') && (level == 0))
break;
if ((c == ')') && (level == 0))
break;
Putc(c, str);
if (c == '(')
level++;
if (c == ')')
level--;
c = Getc(s);
}
if (level > 0) {
goto unterm;
}
Chop(str);
if (Len(args) || Len(str))
Append(args, str);
Delete(str);
/* if (Len(str) && (c != ')'))
Append(args,str); */
if (c == ')')
return args;
c = Getc(s);
}
unterm:
Swig_error(Getfile(args), Getline(args), "Unterminated macro call.\n");
return args;
}
/* -----------------------------------------------------------------------------
* DOH *get_filename(DOH *str)
*
* Read a filename from str. A filename can be enclose in quotes, angle brackets,
* or bare.
* ----------------------------------------------------------------------------- */
static String *get_filename(String *str, int *sysfile) {
String *fn;
int c;
skip_whitespace(str, 0);
fn = NewStringEmpty();
copy_location(str, fn);
c = Getc(str);
*sysfile = 0;
if (c == '\"') {
while (((c = Getc(str)) != EOF) && (c != '\"'))
Putc(c, fn);
} else if (c == '<') {
*sysfile = 1;
while (((c = Getc(str)) != EOF) && (c != '>'))
Putc(c, fn);
} else {
Putc(c, fn);
while (((c = Getc(str)) != EOF) && (!isspace(c)))
Putc(c, fn);
if (isspace(c))
Ungetc(c, str);
}
#if defined(_WIN32) || defined(MACSWIG)
/* accept Unix path separator on non-Unix systems */
Replaceall(fn, "/", SWIG_FILE_DELIMITER);
#endif
#if defined(__CYGWIN__)
/* accept Windows path separator in addition to Unix path separator */
Replaceall(fn, "\\", SWIG_FILE_DELIMITER);
#endif
Seek(fn, 0, SEEK_SET);
return fn;
}
static String *get_options(String *str) {
int c;
skip_whitespace(str, 0);
c = Getc(str);
if (c == '(') {
String *opt;
int level = 1;
opt = NewString("(");
while (((c = Getc(str)) != EOF)) {
Putc(c, opt);
if (c == ')') {
level--;
if (!level)
return opt;
}
if (c == '(')
level++;
}
Delete(opt);
return 0;
} else {
Ungetc(c, str);
return 0;
}
}
/* -----------------------------------------------------------------------------
* expand_macro()
*
* Perform macro expansion and return a new string. Returns NULL if some sort
* of error occurred.
* ----------------------------------------------------------------------------- */
static String *expand_macro(String *name, List *args) {
String *ns;
DOH *symbols, *macro, *margs, *mvalue, *temp, *tempa, *e;
int i, l;
int isvarargs = 0;
symbols = Getattr(cpp, kpp_symbols);
if (!symbols)
return 0;
/* See if the name is actually defined */
macro = Getattr(symbols, name);
if (!macro)
return 0;
if (Getattr(macro, kpp_expanded)) {
ns = NewStringEmpty();
Append(ns, name);
if (args) {
int lenargs = Len(args);
if (lenargs)
Putc('(', ns);
for (i = 0; i < lenargs; i++) {
Append(ns, Getitem(args, i));
if (i < (lenargs - 1))
Putc(',', ns);
}
if (i)
Putc(')', ns);
}
return ns;
}
/* Get macro arguments and value */
mvalue = Getattr(macro, kpp_value);
assert(mvalue);
margs = Getattr(macro, kpp_args);
if (args && Getattr(macro, kpp_varargs)) {
isvarargs = 1;
/* Variable length argument macro. We need to collect all of the extra arguments into a single argument */
if (Len(args) >= (Len(margs) - 1)) {
int i;
int vi, na;
String *vararg = NewStringEmpty();
vi = Len(margs) - 1;
na = Len(args);
for (i = vi; i < na; i++) {
Append(vararg, Getitem(args, i));
if ((i + 1) < na) {
Append(vararg, ",");
}
}
/* Remove arguments */
for (i = vi; i < na; i++) {
Delitem(args, vi);
}
Append(args, vararg);
Delete(vararg);
}
}
/* If there are arguments, see if they match what we were given */
if (args && (margs) && (Len(margs) != Len(args))) {
if (Len(margs) > (1 + isvarargs))
Swig_error(Getfile(args), Getline(args), "Macro '%s' expects %d arguments\n", name, Len(margs) - isvarargs);
else if (Len(margs) == (1 + isvarargs))
Swig_error(Getfile(args), Getline(args), "Macro '%s' expects 1 argument\n", name);
else
Swig_error(Getfile(args), Getline(args), "Macro '%s' expects no arguments\n", name);
return 0;
}
/* If the macro expects arguments, but none were supplied, we leave it in place */
if (!args && (margs) && Len(margs) > 0) {
return NewString(name);
}
/* Copy the macro value */
ns = Copy(mvalue);
copy_location(mvalue, ns);
/* Tag the macro as being expanded. This is to avoid recursion in
macro expansion */
temp = NewStringEmpty();
tempa = NewStringEmpty();
if (args && margs) {
l = Len(margs);
for (i = 0; i < l; i++) {
DOH *arg, *aname;
String *reparg;
arg = Getitem(args, i); /* Get an argument value */
reparg = Preprocessor_replace(arg);
aname = Getitem(margs, i); /* Get macro argument name */
if (strstr(Char(ns), "\001")) {
/* Try to replace a quoted version of the argument */
Clear(temp);
Clear(tempa);
Printf(temp, "\001%s", aname);
Printf(tempa, "\"%s\"", arg);
Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
}
if (strstr(Char(ns), "\002")) {
/* Look for concatenation tokens */
Clear(temp);
Clear(tempa);
Printf(temp, "\002%s", aname);
Append(tempa, "\002\003");
Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
Clear(temp);
Clear(tempa);
Printf(temp, "%s\002", aname);
Append(tempa, "\003\002");
Replace(ns, temp, tempa, DOH_REPLACE_ID_BEGIN);
}
/* Non-standard macro expansion. The value `x` is replaced by a quoted
version of the argument except that if the argument is already quoted
nothing happens */
if (strchr(Char(ns), '`')) {
String *rep;
char *c;
Clear(temp);
Printf(temp, "`%s`", aname);
c = Char(arg);
if (*c == '\"') {
rep = arg;
} else {
Clear(tempa);
Printf(tempa, "\"%s\"", arg);
rep = tempa;
}
Replace(ns, temp, rep, DOH_REPLACE_ANY);
}
/* Non-standard mangle expansions.
The #@Name is replaced by mangle_arg(Name). */
if (strstr(Char(ns), "\004")) {
String *marg = Swig_string_mangle(arg);
Clear(temp);
Printf(temp, "\004%s", aname);
Replace(ns, temp, marg, DOH_REPLACE_ID_END);
Delete(marg);
}
if (strstr(Char(ns), "\005")) {
String *marg = Swig_string_mangle(arg);
Clear(temp);
Clear(tempa);
Printf(temp, "\005%s", aname);
Printf(tempa, "\"%s\"", marg);
Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
Delete(marg);
}
if (isvarargs && i == l - 1 && Len(arg) == 0) {
/* Zero length varargs macro argument. We search for commas that might appear before and nuke them */
char *a, *s, *t, *name;
int namelen;
s = Char(ns);
name = Char(aname);
namelen = Len(aname);
a = strstr(s, name);
while (a) {
char ca = a[namelen + 1];
if (!isidchar((int) ca)) {
/* Matched the entire vararg name, not just a prefix */
t = a - 1;
if (*t == '\002') {
t--;
while (t >= s) {
if (isspace((int) *t))
t--;
else if (*t == ',') {
*t = ' ';
} else
break;
}
}
}
a = strstr(a + namelen, name);
}
}
/* Replace(ns, aname, arg, DOH_REPLACE_ID); */
Replace(ns, aname, reparg, DOH_REPLACE_ID); /* Replace expanded args */
Replace(ns, "\003", arg, DOH_REPLACE_ANY); /* Replace unexpanded arg */
Delete(reparg);
}
}
Replace(ns, "\002", "", DOH_REPLACE_ANY); /* Get rid of concatenation tokens */
Replace(ns, "\001", "#", DOH_REPLACE_ANY); /* Put # back (non-standard C) */
Replace(ns, "\004", "#@", DOH_REPLACE_ANY); /* Put # back (non-standard C) */
/* Expand this macro even further */
Setattr(macro, kpp_expanded, "1");
e = Preprocessor_replace(ns);
Delattr(macro, kpp_expanded);
Delete(ns);
if (Getattr(macro, kpp_swigmacro)) {
String *g;
String *f = NewStringEmpty();
Seek(e, 0, SEEK_SET);
copy_location(macro, e);
g = Preprocessor_parse(e);
#if 0
/* Drop the macro in place, but with a marker around it */
Printf(f, "/*@%s,%d,%s@*/%s/*@@*/", Getfile(macro), Getline(macro), name, g);
#else
/* Use simplified around markers to properly count lines in cscanner.c */
if (strchr(Char(g), '\n')) {
Printf(f, "/*@SWIG:%s,%d,%s@*/%s/*@SWIG@*/", Getfile(macro), Getline(macro), name, g);
#if 0
Printf(f, "/*@SWIG:%s@*/%s/*@SWIG@*/", name, g);
#endif
} else {
Append(f, g);
}
#endif
Delete(g);
Delete(e);
e = f;
}
Delete(temp);
Delete(tempa);
return e;
}
/* -----------------------------------------------------------------------------
* evaluate_args()
*
* Evaluate the arguments of a macro
* ----------------------------------------------------------------------------- */
List *evaluate_args(List *x) {
Iterator i;
List *nl = NewList();
for (i = First(x); i.item; i = Next(i)) {
Append(nl, Preprocessor_replace(i.item));
}
return nl;
}
/* -----------------------------------------------------------------------------
* DOH *Preprocessor_replace(DOH *s)
*
* Performs a macro substitution on a string s. Returns a new string with
* substitutions applied. This function works by walking down s and looking
* for identifiers. When found, a check is made to see if they are macros
* which are then expanded.
* ----------------------------------------------------------------------------- */
/* #define SWIG_PUT_BUFF */
DOH *Preprocessor_replace(DOH *s) {
DOH *ns, *symbols, *m;
int c, i, state = 0;
String *id = NewStringEmpty();
assert(cpp);
symbols = Getattr(cpp, kpp_symbols);
ns = NewStringEmpty();
copy_location(s, ns);
Seek(s, 0, SEEK_SET);
/* Try to locate identifiers in s and replace them with macro replacements */
while ((c = Getc(s)) != EOF) {
switch (state) {
case 0:
if (isidentifier(c) || (c == '%')) {
Clear(id);
Putc(c, id);
state = 1;
} else if (c == '\"') {
Putc(c, ns);
skip_tochar(s, '\"', ns);
} else if (c == '\'') {
Putc(c, ns);
skip_tochar(s, '\'', ns);
} else if (c == '/') {
Putc(c, ns);
state = 10;
} else {
Putc(c, ns);
}
break;
case 1: /* An identifier */
if (isidchar(c)) {
Putc(c, id);
state = 1;
} else {
/* We found the end of a valid identifier */
Ungetc(c, s);
/* See if this is the special "defined" macro */
if (Equal(kpp_defined, id)) {
int lenargs = 0;
DOH *args = 0;
/* See whether or not a paranthesis has been used */
skip_whitespace(s, 0);
c = Getc(s);
if (c == '(') {
Ungetc(c, s);
args = find_args(s);
} else if (isidchar(c)) {
DOH *arg = NewStringEmpty();
args = NewList();
Putc(c, arg);
while (((c = Getc(s)) != EOF)) {
if (!isidchar(c)) {
Ungetc(c, s);
break;
}
Putc(c, arg);
}
if (Len(arg))
Append(args, arg);
Delete(arg);
} else {
Seek(s, -1, SEEK_CUR);
}
lenargs = Len(args);
if ((!args) || (!lenargs)) {
/* This is not a defined() macro. */
Append(ns, id);
state = 0;
break;
}
for (i = 0; i < lenargs; i++) {
DOH *o = Getitem(args, i);
if (!Getattr(symbols, o)) {
break;
}
}
if (i < lenargs)
Putc('0', ns);
else
Putc('1', ns);
Delete(args);
state = 0;
break;
}
if (Equal(kpp_LINE, id)) {
Printf(ns, "%d", Getline(s));
state = 0;
break;
}
if (Equal(kpp_FILE, id)) {
String *fn = Copy(Getfile(s));
Replaceall(fn, "\\", "\\\\");
Printf(ns, "\"%s\"", fn);
Delete(fn);
state = 0;
break;
}
/* See if the macro is defined in the preprocessor symbol table */
if ((m = Getattr(symbols, id))) {
DOH *args = 0;
DOH *e;
/* See if the macro expects arguments */
if (Getattr(m, kpp_args)) {
/* Yep. We need to go find the arguments and do a substitution */
args = find_args(s);
if (!Len(args)) {
Delete(args);
args = 0;
}
} else {
args = 0;
}
e = expand_macro(id, args);
if (e) {
Append(ns, e);
}
Delete(e);
Delete(args);
} else {
Append(ns, id);
}
state = 0;
}
break;
case 10:
if (c == '/')
state = 11;
else if (c == '*')
state = 12;
else {
Ungetc(c, s);
state = 0;
break;
}
Putc(c, ns);
break;
case 11:
Putc(c, ns);
if (c == '\n')
state = 0;
break;
case 12:
Putc(c, ns);
if (c == '*')
state = 13;
break;
case 13:
Putc(c, ns);
if (c == '/')
state = 0;
else if (c != '*')
state = 12;
break;
default:
state = 0;
break;
}
}
/* Identifier at the end */
if (state == 1) {
/* See if this is the special "defined" macro */
if (Equal(kpp_defined, id)) {
Swig_error(Getfile(s), Getline(s), "No arguments given to defined()\n");
} else if ((m = Getattr(symbols, id))) {
DOH *e;
/* Yes. There is a macro here */
/* See if the macro expects arguments */
/* if (Getattr(m,"args")) {
Swig_error(Getfile(id),Getline(id),"Macro arguments expected.\n");
} */
e = expand_macro(id, 0);
Append(ns, e);
Delete(e);
} else {
Append(ns, id);
}
}
Delete(id);
return ns;
}
/* -----------------------------------------------------------------------------
* int checkpp_id(DOH *s)
*
* Checks the string s to see if it contains any unresolved identifiers. This
* function contains the heuristic that determines whether or not a macro
* definition passes through the preprocessor as a constant declaration.
* ----------------------------------------------------------------------------- */
static int checkpp_id(DOH *s) {
int c;
int hastok = 0;
Scanner *scan = id_scan;
Seek(s, 0, SEEK_SET);
Scanner_clear(scan);
s = Copy(s);
Seek(s, SEEK_SET, 0);
Scanner_push(scan, s);
while ((c = Scanner_token(scan))) {
hastok = 1;
if ((c == SWIG_TOKEN_ID) || (c == SWIG_TOKEN_LBRACE) || (c == SWIG_TOKEN_RBRACE))
return 1;
}
if (!hastok)
return 1;
return 0;
}
/* addline(). Utility function for adding lines to a chunk */
static void addline(DOH *s1, DOH *s2, int allow) {
if (allow) {
Append(s1, s2);
} else {
char *c = Char(s2);
while (*c) {
if (*c == '\n')
Putc('\n', s1);
c++;
}
}
}
static void add_chunk(DOH *ns, DOH *chunk, int allow) {
DOH *echunk;
Seek(chunk, 0, SEEK_SET);
if (allow) {
echunk = Preprocessor_replace(chunk);
addline(ns, echunk, allow);
Delete(echunk);
} else {
addline(ns, chunk, 0);
}
Clear(chunk);
}
/*
push/pop_imported(): helper functions for defining and undefining
SWIGIMPORTED (when %importing a file).
*/
static void push_imported() {
if (imported_depth == 0) {
Preprocessor_define("SWIGIMPORTED 1", 0);
}
++imported_depth;
}
static void pop_imported() {
--imported_depth;
if (imported_depth == 0) {
Preprocessor_undef("SWIGIMPORTED");
}
}
/* -----------------------------------------------------------------------------
* Preprocessor_parse()
*
* Parses the string s. Returns a new string containing the preprocessed version.
*
* Parsing rules :
* 1. Lines starting with # are C preprocessor directives
* 2. Macro expansion inside strings is not allowed
* 3. All code inside false conditionals is changed to blank lines
* 4. Code in %{, %} is not parsed because it may need to be
* included inline (with all preprocessor directives included).
* ----------------------------------------------------------------------------- */
String *Preprocessor_parse(String *s) {
String *ns; /* New string containing the preprocessed text */
String *chunk, *decl;
Hash *symbols;
String *id = 0, *value = 0, *comment = 0;
int i, state, e, c;
int start_line = 0;
int allow = 1;
int level = 0;
int dlevel = 0;
int mask = 0;
int start_level = 0;
int cpp_lines = 0;
int cond_lines[256];
/* Blow away all carriage returns */
Replace(s, "\015", "", DOH_REPLACE_ANY);
ns = NewStringEmpty(); /* Return result */
decl = NewStringEmpty();
id = NewStringEmpty();
value = NewStringEmpty();
comment = NewStringEmpty();
chunk = NewStringEmpty();
copy_location(s, chunk);
copy_location(s, ns);
symbols = Getattr(cpp, kpp_symbols);
state = 0;
while ((c = Getc(s)) != EOF) {
switch (state) {
case 0: /* Initial state - in first column */
/* Look for C preprocessor directives. Otherwise, go directly to state 1 */
if (c == '#') {
add_chunk(ns, chunk, allow);
copy_location(s, chunk);
cpp_lines = 1;
state = 40;
} else if (isspace(c)) {
Putc(c, chunk);
skip_whitespace(s, chunk);
} else {
state = 1;
Ungetc(c, s);
}
break;
case 1: /* Non-preprocessor directive */
/* Look for SWIG directives */
if (c == '%') {
state = 100;
break;
}
Putc(c, chunk);
if (c == '\n')
state = 0;
else if (c == '\"') {
start_line = Getline(s);
if (skip_tochar(s, '\"', chunk) < 0) {
Swig_error(Getfile(s), -1, "Unterminated string constant starting at line %d\n", start_line);
}
} else if (c == '\'') {
start_line = Getline(s);
if (skip_tochar(s, '\'', chunk) < 0) {
Swig_error(Getfile(s), -1, "Unterminated character constant starting at line %d\n", start_line);
}
} else if (c == '/')
state = 30; /* Comment */
break;
case 30: /* Possibly a comment string of some sort */
start_line = Getline(s);
Putc(c, chunk);
if (c == '/')
state = 31;
else if (c == '*')
state = 32;
else
state = 1;
break;
case 31:
Putc(c, chunk);
if (c == '\n')
state = 0;
break;
case 32:
Putc(c, chunk);
if (c == '*')
state = 33;
break;
case 33:
Putc(c, chunk);
if (c == '/')
state = 1;
else if (c != '*')
state = 32;
break;
case 40: /* Start of a C preprocessor directive */
if (c == '\n') {
Putc('\n', chunk);
state = 0;
} else if (isspace(c)) {
state = 40;
} else {
/* Got the start of a preprocessor directive */
Ungetc(c, s);
Clear(id);
copy_location(s, id);
state = 41;
}
break;
case 41: /* Build up the name of the preprocessor directive */
if ((isspace(c) || (!isalpha(c)))) {
Clear(value);
Clear(comment);
if (c == '\n') {
Ungetc(c, s);
state = 50;
} else {
state = 42;
if (!isspace(c)) {
Ungetc(c, s);
}
}
copy_location(s, value);
break;
}
Putc(c, id);
break;
case 42: /* Strip any leading space before preprocessor value */
if (isspace(c)) {
if (c == '\n') {
Ungetc(c, s);
state = 50;
}
break;
}
state = 43;
/* no break intended here */
case 43:
/* Get preprocessor value */
if (c == '\n') {
Ungetc(c, s);
state = 50;
} else if (c == '/') {
state = 45;
} else if (c == '\"') {
Putc(c, value);
skip_tochar(s, '\"', value);
} else if (c == '\'') {
Putc(c, value);
skip_tochar(s, '\'', value);
} else {
Putc(c, value);
if (c == '\\')
state = 44;
}
break;
case 44:
if (c == '\n') {
Putc(c, value);
cpp_lines++;
} else {
Ungetc(c, s);
}
state = 43;
break;
/* States 45-48 are used to remove, but retain comments from macro values. The comments
will be placed in the output in an alternative form */
case 45:
if (c == '/')
state = 46;
else if (c == '*')
state = 47;
else if (c == '\n') {
Putc('/', value);
Ungetc(c, s);
cpp_lines++;
state = 50;
} else {
Putc('/', value);
Putc(c, value);
state = 43;
}
break;
case 46:
if (c == '\n') {
Ungetc(c, s);
cpp_lines++;
state = 50;
} else
Putc(c, comment);
break;
case 47:
if (c == '*')
state = 48;
else
Putc(c, comment);
break;
case 48:
if (c == '/')
state = 43;
else if (c == '*')
Putc(c, comment);
else {
Putc('*', comment);
Putc(c, comment);
state = 47;
}
break;
case 50:
/* Check for various preprocessor directives */
Chop(value);
if (Equal(id, kpp_define)) {
if (allow) {
DOH *m, *v, *v1;
Seek(value, 0, SEEK_SET);
m = Preprocessor_define(value, 0);
if ((m) && !(Getattr(m, kpp_args))) {
v = Copy(Getattr(m, kpp_value));
if (Len(v)) {
Swig_error_silent(1);
v1 = Preprocessor_replace(v);
Swig_error_silent(0);
/* Printf(stdout,"checking '%s'\n", v1); */
if (!checkpp_id(v1)) {
if (Len(comment) == 0)
Printf(ns, "%%constant %s = %s;\n", Getattr(m, kpp_name), v1);
else
Printf(ns, "%%constant %s = %s; /*%s*/\n", Getattr(m, kpp_name), v1, comment);
cpp_lines--;
}
Delete(v1);
}
Delete(v);
}
}
} else if (Equal(id, kpp_undef)) {
if (allow)
Preprocessor_undef(value);
} else if (Equal(id, kpp_ifdef)) {
cond_lines[level] = Getline(id);
level++;
if (allow) {
start_level = level;
/* See if the identifier is in the hash table */
if (!Getattr(symbols, value))
allow = 0;
mask = 1;
}
} else if (Equal(id, kpp_ifndef)) {
cond_lines[level] = Getline(id);
level++;
if (allow) {
start_level = level;
/* See if the identifier is in the hash table */
if (Getattr(symbols, value))
allow = 0;
mask = 1;
}
} else if (Equal(id, kpp_else)) {
if (level <= 0) {
Swig_error(Getfile(s), Getline(id), "Misplaced #else.\n");
} else {
cond_lines[level - 1] = Getline(id);
if (allow) {
allow = 0;
mask = 0;
} else if (level == start_level) {
allow = 1 * mask;
}
}
} else if (Equal(id, kpp_endif)) {
level--;
if (level < 0) {
Swig_error(Getfile(id), Getline(id), "Extraneous #endif.\n");
level = 0;
} else {
if (level < start_level) {
allow = 1;
start_level--;
}
}
} else if (Equal(id, kpp_if)) {
cond_lines[level] = Getline(id);
level++;
if (allow) {
int val;
String *sval = Preprocessor_replace(value);
start_level = level;
Seek(sval, 0, SEEK_SET);
/* Printf(stdout,"Evaluating '%s'\n", sval); */
val = Preprocessor_expr(sval, &e);
if (e) {
char *msg = Preprocessor_expr_error();
Seek(value, 0, SEEK_SET);
Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Could not evaluate '%s'\n", value);
if (msg)
Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Error: '%s'\n", msg);
allow = 0;
} else {
if (val == 0)
allow = 0;
}
mask = 1;
}
} else if (Equal(id, kpp_elif)) {
if (level == 0) {
Swig_error(Getfile(s), Getline(id), "Misplaced #elif.\n");
} else {
cond_lines[level - 1] = Getline(id);
if (allow) {
allow = 0;
mask = 0;
} else if (level == start_level) {
int val;
String *sval = Preprocessor_replace(value);
Seek(sval, 0, SEEK_SET);
val = Preprocessor_expr(sval, &e);
if (e) {
char *msg = Preprocessor_expr_error();
Seek(value, 0, SEEK_SET);
Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Could not evaluate '%s'\n", value);
if (msg)
Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Error: '%s'\n", msg);
allow = 0;
} else {
if (val)
allow = 1 * mask;
else
allow = 0;
}
}
}
} else if (Equal(id, kpp_warning)) {
if (allow) {
Swig_warning(WARN_PP_CPP_WARNING, Getfile(s), Getline(id), "CPP #warning, %s\n", value);
}
} else if (Equal(id, kpp_error)) {
if (allow) {
if (error_as_warning) {
Swig_warning(WARN_PP_CPP_ERROR, Getfile(s), Getline(id), "CPP #error \"%s\".\n", value);
} else {
Swig_error(Getfile(s), Getline(id), "CPP #error \"%s\". Use the -cpperraswarn option to continue swig processing.\n", value);
}
}
} else if (Equal(id, kpp_line)) {
} else if (Equal(id, kpp_include)) {
if (((include_all) || (import_all)) && (allow)) {
String *s1, *s2, *fn;
char *dirname;
int sysfile = 0;
if (include_all && import_all) {
Swig_warning(WARN_PP_INCLUDEALL_IMPORTALL, Getfile(s), Getline(id), "Both includeall and importall are defined: using includeall\n");
import_all = 0;
}
Seek(value, 0, SEEK_SET);
fn = get_filename(value, &sysfile);
s1 = cpp_include(fn, sysfile);
if (s1) {
if (include_all)
Printf(ns, "%%includefile \"%s\" [\n", Swig_last_file());
else if (import_all) {
Printf(ns, "%%importfile \"%s\" [\n", Swig_last_file());
push_imported();
}
/* See if the filename has a directory component */
dirname = Swig_file_dirname(Swig_last_file());
if (sysfile || !strlen(dirname))
dirname = 0;
if (dirname) {
dirname[strlen(dirname) - 1] = 0; /* Kill trailing directory delimiter */
Swig_push_directory(dirname);
}
s2 = Preprocessor_parse(s1);
addline(ns, s2, allow);
Append(ns, "\n]");
if (dirname) {
Swig_pop_directory();
}
if (import_all) {
pop_imported();
}
Delete(s2);
}
Delete(s1);
Delete(fn);
}
} else if (Equal(id, kpp_pragma)) {
if (Strncmp(value, "SWIG ", 5) == 0) {
char *c = Char(value) + 5;
while (*c && (isspace((int) *c)))
c++;
if (*c) {
if (strncmp(c, "nowarn=", 7) == 0) {
String *val = NewString(c + 7);
String *nowarn = Preprocessor_replace(val);
Swig_warnfilter(nowarn, 1);
Delete(nowarn);
Delete(val);
} else if (strncmp(c, "cpperraswarn=", 13) == 0) {
error_as_warning = atoi(c + 13);
} else {
Swig_error(Getfile(s), Getline(id), "Unknown SWIG pragma: %s\n", c);
}
}
}
} else if (Equal(id, kpp_level)) {
Swig_error(Getfile(s), Getline(id), "cpp debug: level = %d, startlevel = %d\n", level, start_level);
}
for (i = 0; i < cpp_lines; i++)
Putc('\n', ns);
state = 0;
break;
/* Swig directives */
case 100:
/* %{,%} block */
if (c == '{') {
start_line = Getline(s);
add_chunk(ns, chunk, allow);
copy_location(s, chunk);
Putc('%', chunk);
Putc(c, chunk);
state = 105;
}
/* %#cpp - an embedded C preprocessor directive (we strip off the %) */
else if (c == '#') {
add_chunk(ns, chunk, allow);
Putc(c, chunk);
state = 107;
} else if (isidentifier(c)) {
Clear(decl);
Putc('%', decl);
Putc(c, decl);
state = 110;
} else {
Putc('%', chunk);
Putc(c, chunk);
state = 1;
}
break;
case 105:
Putc(c, chunk);
if (c == '%')
state = 106;
break;
case 106:
Putc(c, chunk);
if (c == '}') {
state = 1;
addline(ns, chunk, allow);
Clear(chunk);
copy_location(s, chunk);
} else {
state = 105;
}
break;
case 107:
Putc(c, chunk);
if (c == '\n') {
addline(ns, chunk, allow);
Clear(chunk);
state = 0;
} else if (c == '\\') {
state = 108;
}
break;
case 108:
Putc(c, chunk);
state = 107;
break;
case 110:
if (!isidchar(c)) {
Ungetc(c, s);
/* Look for common Swig directives */
if (Equal(decl, kpp_dinclude) || Equal(decl, kpp_dimport) || Equal(decl, kpp_dextern)) {
/* Got some kind of file inclusion directive */
if (allow) {
DOH *s1, *s2, *fn, *opt;
int sysfile = 0;
if (Equal(decl, kpp_dextern)) {
Swig_warning(WARN_DEPRECATED_EXTERN, Getfile(s), Getline(s), "%%extern is deprecated. Use %%import instead.\n");
Clear(decl);
Append(decl, "%%import");
}
opt = get_options(s);
fn = get_filename(s, &sysfile);
s1 = cpp_include(fn, sysfile);
if (s1) {
char *dirname;
add_chunk(ns, chunk, allow);
copy_location(s, chunk);
Printf(ns, "%sfile%s \"%s\" [\n", decl, opt, Swig_last_file());
if (Equal(decl, kpp_dimport)) {
push_imported();
}
dirname = Swig_file_dirname(Swig_last_file());
if (sysfile || !strlen(dirname))
dirname = 0;
if (dirname) {
dirname[strlen(dirname) - 1] = 0; /* Kill trailing directory delimiter */
Swig_push_directory(dirname);
}
s2 = Preprocessor_parse(s1);
if (dirname) {
Swig_pop_directory();
}
if (Equal(decl, kpp_dimport)) {
pop_imported();
}
addline(ns, s2, allow);
Append(ns, "\n]");
Delete(s2);
Delete(s1);
}
Delete(fn);
}
state = 1;
} else if (Equal(decl, kpp_dline)) {
/* Got a line directive */
state = 1;
} else if (Equal(decl, kpp_ddefine)) {
/* Got a define directive */
dlevel++;
add_chunk(ns, chunk, allow);
copy_location(s, chunk);
Clear(value);
copy_location(s, value);
state = 150;
} else {
Append(chunk, decl);
state = 1;
}
} else {
Putc(c, decl);
}
break;
/* Searching for the end of a %define statement */
case 150:
Putc(c, value);
if (c == '%') {
const char *ed = "enddef";
const char *df = "define";
char statement[7];
int i = 0;
for (i = 0; i < 6;) {
c = Getc(s);
Putc(c, value);
statement[i++] = (char)c;
if (strncmp(statement, ed, i) && strncmp(statement, df, i))
break;
}
c = Getc(s);
Ungetc(c, s);
if ((i == 6) && (isspace(c))) {
if (strncmp(statement, df, i) == 0) {
++dlevel;
} else {
if (strncmp(statement, ed, i) == 0) {
--dlevel;
if (!dlevel) {
/* Got the macro */
for (i = 0; i < 7; i++) {
Delitem(value, DOH_END);
}
if (allow) {
Seek(value, 0, SEEK_SET);
Preprocessor_define(value, 1);
}
/* Putc('\n',ns); */
addline(ns, value, 0);
state = 0;
}
}
}
}
}
break;
default:
Printf(stderr, "cpp: Invalid parser state %d\n", state);
abort();
break;
}
}
while (level > 0) {
Swig_error(Getfile(s), -1, "Missing #endif for conditional starting on line %d\n", cond_lines[level - 1]);
level--;
}
if (state == 150) {
Seek(value, 0, SEEK_SET);
Swig_error(Getfile(s), -1, "Missing %%enddef for macro starting on line %d\n", Getline(value));
}
if ((state >= 105) && (state < 107)) {
Swig_error(Getfile(s), -1, "Unterminated %%{ ... %%} block starting on line %d\n", start_line);
}
if ((state >= 30) && (state < 40)) {
Swig_error(Getfile(s), -1, "Unterminated comment starting on line %d\n", start_line);
}
add_chunk(ns, chunk, allow);
copy_location(s, chunk);
/* DelScope(scp); */
Delete(decl);
Delete(id);
Delete(value);
Delete(comment);
Delete(chunk);
/* fprintf(stderr,"cpp: %d\n", Len(Getattr(cpp,"symbols"))); */
return ns;
}