9506a12016-08-20Martin Nilsson /* -*- mode: c; encoding: utf-8; -*-
e576bb2002-10-11Martin Nilsson || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
24ddc71998-03-28Henrik Grubbström (Grubba) 
5740881998-01-01Fredrik Hübinette (Hubbe) #include "global.h" #include "stralloc.h" #include "module_support.h" #include "interpret.h" #include "svalue.h" #include "pike_macros.h" #include "program.h"
1420732017-02-08Henrik Grubbström (Grubba) #include "pike_compiler.h"
5740881998-01-01Fredrik Hübinette (Hubbe) #include "object.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
5740881998-01-01Fredrik Hübinette (Hubbe) #include "array.h" #include "mapping.h" #include "builtin_functions.h" #include "operators.h" #include "constants.h" #include "time.h"
f0950a1999-03-27Henrik Grubbström (Grubba) #include "version.h"
a0180b2003-11-14Martin Stjernholm #include "pike_types.h"
b964fd2004-04-16Martin Stjernholm #include "cpp.h"
bdd37a2004-11-02Martin Stjernholm #include "lex.h"
9d1f542017-01-25Henrik Grubbström (Grubba) #include "sprintf.h"
f0950a1999-03-27Henrik Grubbström (Grubba) 
5740881998-01-01Fredrik Hübinette (Hubbe) #include <ctype.h>
3b87412016-07-27Henrik Grubbström (Grubba) #define DEFAULT_CMOD_STORAGE
fbf6c92004-06-29Henrik Grubbström (Grubba) #define CPP_NO_OUTPUT 1 /* Inside false section of #if/#else */ #define CPP_EXPECT_ELSE 2 /* Expect #else/#elif/#elseif. */ #define CPP_EXPECT_ENDIF 4 /* Expect #endif */ #define CPP_REALLY_NO_OUTPUT 8 /* Entire preprocessor is in false section. */ #define CPP_END_AT_NEWLINE 16 /* Halt at end of line. */
5740881998-01-01Fredrik Hübinette (Hubbe) #define CPP_DO_IF 32
0d52dd1998-01-16Fredrik Hübinette (Hubbe) #define CPP_NO_EXPAND 64
5740881998-01-01Fredrik Hübinette (Hubbe)  #define OUTP() (!(flags & (CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT)))
d9ac331999-02-22Henrik Grubbström (Grubba) #define PUTNL() string_builder_putchar(&this->buf, '\n')
74966e2014-05-12Per Hedbor #define GOBBLE(X) (INDEX_PCHARP(data,pos)==(X)?++pos,1:0)
5740881998-01-01Fredrik Hübinette (Hubbe) #define PUTC(C) do { \
d9ac331999-02-22Henrik Grubbström (Grubba)  int c_=(C); if(OUTP() || c_=='\n') string_builder_putchar(&this->buf, c_); }while(0)
5740881998-01-01Fredrik Hübinette (Hubbe)  #define MAX_ARGS 255 #define DEF_ARG_STRINGIFY 0x100000 #define DEF_ARG_NOPRESPACE 0x200000 #define DEF_ARG_NOPOSTSPACE 0x400000
9b52e52011-10-24Tobias S. Josefowitz #define DEF_ARG_NEED_COMMA 0x800000
5740881998-01-01Fredrik Hübinette (Hubbe) #define DEF_ARG_MASK 0x0fffff
58efb82014-05-12Per Hedbor #ifdef __GNUC__ #pragma GCC optimize "-Os" #endif
7050b72014-02-25Per Hedbor  /* Return true if compat version is equal or less than MAJOR.MINOR */ #define CPP_TEST_COMPAT(THIS,MAJOR,MINOR) \ (THIS->compat_major < (MAJOR) || \ (THIS->compat_major == (MAJOR) && \ THIS->compat_minor <= (MINOR)))
fbf6c92004-06-29Henrik Grubbström (Grubba) #if 0 #define CALC_DUMPPOS(X) DUMPPOS(X) #else /* !0 */ #define CALC_DUMPPOS(X) #endif /* 0 */
5740881998-01-01Fredrik Hübinette (Hubbe) 
5164822004-11-14Martin Stjernholm static struct pike_string *efun_str; static struct pike_string *constant_str; static struct pike_string *defined_str;
5740881998-01-01Fredrik Hübinette (Hubbe) struct pike_predef_s { struct pike_predef_s *next; char *name; char *value; };
b584b12001-12-20Martin Stjernholm static int use_initial_predefs; static struct pike_predef_s *first_predef = NULL, *last_predef = NULL;
5740881998-01-01Fredrik Hübinette (Hubbe) struct define_argument {
2dc0091999-02-27Henrik Grubbström (Grubba)  PCHARP arg;
f49e472000-08-10Henrik Grubbström (Grubba)  ptrdiff_t len;
5740881998-01-01Fredrik Hübinette (Hubbe) };
6e2bb52018-01-05Henrik Grubbström (Grubba) struct CPP_struct;
7962c02016-09-01Henrik Grubbström (Grubba) struct define_struct;
6e2bb52018-01-05Henrik Grubbström (Grubba) typedef void (*magic_define_fun)(struct CPP_struct *,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *,
3d6a1d2016-08-21Martin Nilsson  struct pike_string *,
d9ac331999-02-22Henrik Grubbström (Grubba)  struct string_builder *);
5740881998-01-01Fredrik Hübinette (Hubbe) 
be65c52016-09-02Henrik Grubbström (Grubba) DECLARATIONS;
5740881998-01-01Fredrik Hübinette (Hubbe) 
7db6bc2016-09-08Henrik Grubbström (Grubba) #define CPP_MACRO_DISABLED 1 /* Don't expand. */ #define CPP_MACRO_IN_USE 2 /* In use. */
be65c52016-09-02Henrik Grubbström (Grubba) PIKECLASS define {
279a4f2016-09-03Henrik Grubbström (Grubba)  PIKEVAR string name flags ID_PRIVATE|ID_PROTECTED;
7a61202016-09-04Henrik Grubbström (Grubba)  PIKEVAR array(string|int) parts flags ID_PRIVATE|ID_PROTECTED;
be65c52016-09-02Henrik Grubbström (Grubba)  CVAR magic_define_fun magic; CVAR int args;
7db6bc2016-09-08Henrik Grubbström (Grubba)  CVAR short flags; /* CPP_MACRO_* */
be65c52016-09-02Henrik Grubbström (Grubba)  CVAR short varargs; DECLARE_STORAGE;
f8a6332016-09-02Henrik Grubbström (Grubba)  INIT {
b467522017-06-25Martin Nilsson  struct define_struct *def = (struct define_struct *)CURRENT_STORAGE;
f8a6332016-09-02Henrik Grubbström (Grubba)  def->args=-1;
b467522017-06-25Martin Nilsson #ifdef PIKE_NULL_IS_SPECIAL def->magic=0;
7db6bc2016-09-08Henrik Grubbström (Grubba)  def->flags = 0;
f8a6332016-09-02Henrik Grubbström (Grubba)  def->varargs=0;
b467522017-06-25Martin Nilsson #endif
f8a6332016-09-02Henrik Grubbström (Grubba)  }
be65c52016-09-02Henrik Grubbström (Grubba) }
5740881998-01-01Fredrik Hübinette (Hubbe) 
6e2bb52018-01-05Henrik Grubbström (Grubba) PIKECLASS CPP
5740881998-01-01Fredrik Hübinette (Hubbe) {
6e2bb52018-01-05Henrik Grubbström (Grubba)  PIKEVAR mapping(string:object(define)) defines flags ID_PRIVATE|ID_PROTECTED; PIKEVAR int current_line; PIKEVAR int compile_errors; PIKEVAR string current_file;
7cb5e22018-01-07Henrik Grubbström (Grubba)  PIKEVAR string charset;
6e2bb52018-01-05Henrik Grubbström (Grubba)  CVAR struct string_builder buf; PIKEVAR object handler; PIKEVAR object compat_handler; PIKEVAR int compat_major; PIKEVAR int compat_minor; /* NB: data is marked private to ensure that pike level code can't * remove its references while we hold pointers into it. */ PIKEVAR string data flags ID_PRIVATE|ID_PROTECTED; PIKEVAR string prefix; PIKEVAR int picky_cpp; PIKEVAR int keep_comments; PIKEVAR int dependencies_fail;
e19aca2018-01-06Henrik Grubbström (Grubba)  PIKEVAR int auto_convert;
6e2bb52018-01-05Henrik Grubbström (Grubba) 
86bc4e2018-01-12Henrik Grubbström (Grubba)  PIKEVAR mapping(string:function(string:string)) directives flags ID_PROTECTED;
6e2bb52018-01-05Henrik Grubbström (Grubba)  INIT { init_string_builder(&THIS->buf, 0); } EXIT { /* NOTE: Most of the fields are mapped, and thus freed automatically. */ if (THIS->buf.s) { free_string_builder(&THIS->buf); } }
5740881998-01-01Fredrik Hübinette (Hubbe) 
e442822016-08-31Henrik Grubbström (Grubba) #define FIND_DEFINE(N) find_define(this, (N))
6e2bb52018-01-05Henrik Grubbström (Grubba) static struct define_struct *find_define(struct CPP_struct *this, struct pike_string *n)
e442822016-08-31Henrik Grubbström (Grubba) { struct svalue *s; if (!this->defines) return NULL; if (!(s = low_mapping_string_lookup(this->defines, n))) return NULL; if (TYPEOF(*s) != T_OBJECT) return NULL;
7962c02016-09-01Henrik Grubbström (Grubba)  return (struct define_struct *)get_storage(s->u.object, define_program);
e442822016-08-31Henrik Grubbström (Grubba) }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_error(struct CPP_struct *this, const char *err) ATTRIBUTE((noinline)); static void cpp_error_vsprintf (struct CPP_struct *this, const char *fmt,
1ebec62014-05-13Martin Nilsson  va_list args) ATTRIBUTE((noinline));
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_error_sprintf(struct CPP_struct *this, const char *fmt, ...) ATTRIBUTE((noinline)); static void cpp_handle_exception(struct CPP_struct *this,
1ebec62014-05-13Martin Nilsson  const char *cpp_error_fmt, ...) ATTRIBUTE((noinline));
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_warning(struct CPP_struct *this, const char *cpp_warn_fmt, ...) ATTRIBUTE((noinline));
7962c02016-09-01Henrik Grubbström (Grubba) struct define_struct *defined_macro = NULL;
e442822016-08-31Henrik Grubbström (Grubba) static struct svalue defined_macro_sval;
fbf6c92004-06-29Henrik Grubbström (Grubba) 
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_error(struct CPP_struct *this, const char *err)
5740881998-01-01Fredrik Hübinette (Hubbe) { this->compile_errors++; if(this->compile_errors > 10) return;
739f9d1999-11-04Henrik Grubbström (Grubba)  if((this->handler && this->handler->prog) || get_master())
5740881998-01-01Fredrik Hübinette (Hubbe)  { ref_push_string(this->current_file); push_int(this->current_line); push_text(err);
9036e82001-08-16Martin Stjernholm  low_safe_apply_handler("compile_error", this->handler, this->compat_handler, 3);
5740881998-01-01Fredrik Hübinette (Hubbe)  pop_stack(); }else{
1154dc1998-05-05Fredrik Hübinette (Hubbe)  (void)fprintf(stderr, "%s:%ld: %s\n",
5740881998-01-01Fredrik Hübinette (Hubbe)  this->current_file->str, (long)this->current_line, err); fflush(stderr); } }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_error_vsprintf (struct CPP_struct *this, const char *fmt,
4045632004-06-29Martin Nilsson  va_list args)
9036e82001-08-16Martin Stjernholm {
b202842007-10-22Henrik Grubbström (Grubba)  struct string_builder s; struct pike_string *msg; this->compile_errors++; if (this->compile_errors > 10) return; init_string_builder(&s, 0); string_builder_vsprintf(&s, fmt, args); msg = finish_string_builder(&s); if((this->handler && this->handler->prog) || get_master()) { ref_push_string(this->current_file); push_int(this->current_line); push_string(msg); low_safe_apply_handler("compile_error", this->handler, this->compat_handler, 3); pop_stack(); return; } if (this->current_file->size_shift) { fprintf(stderr, "WIDE:%ld: ", (long)this->current_line); } else { fprintf(stderr, "%s:%ld: ", this->current_file->str, (long)this->current_line); } if (!msg->size_shift) { fprintf(stderr, "%s\n", msg->str); } else { fprintf(stderr, "WIDE (fmt: %s)\n", fmt); } free_string(msg); fflush(stderr);
37338b2003-11-14Martin Stjernholm }
9036e82001-08-16Martin Stjernholm 
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_error_sprintf(struct CPP_struct *this, const char *fmt, ...)
37338b2003-11-14Martin Stjernholm { va_list args;
9036e82001-08-16Martin Stjernholm  va_start(args,fmt);
37338b2003-11-14Martin Stjernholm  cpp_error_vsprintf (this, fmt, args);
9036e82001-08-16Martin Stjernholm  va_end(args); }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_handle_exception(struct CPP_struct *this,
4045632004-06-29Martin Nilsson  const char *cpp_error_fmt, ...)
9036e82001-08-16Martin Stjernholm {
37338b2003-11-14Martin Stjernholm  struct svalue thrown; move_svalue (&thrown, &throw_value);
1ab4ac2008-01-26Martin Stjernholm  mark_free_svalue (&throw_value);
37338b2003-11-14Martin Stjernholm  if (cpp_error_fmt) { va_list args; va_start (args, cpp_error_fmt); cpp_error_vsprintf (this, cpp_error_fmt, args); va_end (args);
9036e82001-08-16Martin Stjernholm  }
37338b2003-11-14Martin Stjernholm  push_svalue(&thrown);
38dfa02008-04-12Henrik Grubbström (Grubba)  low_safe_apply_handler("compile_exception", this->handler, this->compat_handler, 1);
37338b2003-11-14Martin Stjernholm 
19961b2017-04-08Martin Nilsson  if (SAFE_IS_ZERO(Pike_sp-1)) {
37338b2003-11-14Martin Stjernholm  struct pike_string *s = format_exception_for_error_msg (&thrown);
715e552003-11-14Martin Stjernholm  if (s) {
4045632004-06-29Martin Nilsson  cpp_error_sprintf(this, "%S", s);
715e552003-11-14Martin Stjernholm  free_string (s); }
9036e82001-08-16Martin Stjernholm  }
37338b2003-11-14Martin Stjernholm  pop_stack(); free_svalue(&thrown);
9036e82001-08-16Martin Stjernholm }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_warning(struct CPP_struct *this, const char *cpp_warn_fmt, ...)
fb59d22004-02-07Martin Nilsson {
0a5cb72011-03-19Martin Stjernholm  struct string_builder sb;
f6da7b2004-06-27Martin Nilsson  va_list args;
0a5cb72011-03-19Martin Stjernholm  init_string_builder (&sb, 0);
f6da7b2004-06-27Martin Nilsson  va_start(args, cpp_warn_fmt);
0a5cb72011-03-19Martin Stjernholm  string_builder_vsprintf (&sb, cpp_warn_fmt, args);
f6da7b2004-06-27Martin Nilsson  va_end(args);
fb59d22004-02-07Martin Nilsson  if((this->handler && this->handler->prog) || get_master()) { ref_push_string(this->current_file); push_int(this->current_line);
0a5cb72011-03-19Martin Stjernholm  push_string (finish_string_builder (&sb));
fb59d22004-02-07Martin Nilsson  low_safe_apply_handler("compile_warning", this->handler, this->compat_handler, 3); pop_stack(); }else{ (void)fprintf(stderr, "%s:%ld: %s\n", this->current_file->str, (long)this->current_line,
0a5cb72011-03-19Martin Stjernholm  sb.s->str);
fb59d22004-02-07Martin Nilsson  fflush(stderr);
0a5cb72011-03-19Martin Stjernholm  free_string_builder (&sb);
fb59d22004-02-07Martin Nilsson  } }
bbeddc2002-12-07Henrik Grubbström (Grubba) /*! @class MasterObject */ /*! @decl inherit CompilationHandler *! *! The master object acts as fallback compilation handler for *! @[compile()] and @[cpp()]. */ /*! @decl CompilationHandler get_compilation_handler(int major, int minor) *! *! Get compilation handler for simulation of Pike v@[major].@[minor]. *! *! This function is called by @[cpp()] when it encounters
cbe8c92003-04-07Martin Nilsson  *! @expr{#pike@} directives.
bbeddc2002-12-07Henrik Grubbström (Grubba)  *! *! @param major *! Major version. *! *! @param minor *! Minor version. *! *! @returns *! Returns a compilation handler for Pike >= @[major].@[minor]. */ /*! @decl string decode_charset(string raw, string charset) *! *! Convert @[raw] from encoding @[charset] to UNICODE. *! *! This function is called by @[cpp()] when it encounters
cbe8c92003-04-07Martin Nilsson  *! @expr{#charset@} directives.
bbeddc2002-12-07Henrik Grubbström (Grubba)  *! *! @param raw *! String to convert. *! *! @param charset *! Name of encoding that @[raw] uses. *! *! @returns
cbe8c92003-04-07Martin Nilsson  *! @[raw] decoded to UNICODE, or @expr{0@} (zero) if the decoding failed.
2ee3812002-12-08Henrik Grubbström (Grubba)  *! *! @seealso
0b8d2f2013-06-17Martin Nilsson  *! @[Charset]
bbeddc2002-12-07Henrik Grubbström (Grubba)  */ /*! @endclass */ /*! @class CompilationHandler
e290f32006-01-27Henrik Grubbström (Grubba)  *! *! Objects used by the compiler to handle references to global symbols, *! modules, external files, etc. *!
c0fa4e2006-03-25Henrik Grubbström (Grubba)  *! There can be up to three compilation handlers active at the same *! time during a compilation. They are in order of precedence:
e290f32006-01-27Henrik Grubbström (Grubba)  *! *! @ol
c0fa4e2006-03-25Henrik Grubbström (Grubba)  *! @item *! The error handler *!
e290f32006-01-27Henrik Grubbström (Grubba)  *! This is the object passed to @[compile()] as *! the second argument (if any). This object is returned by *! @[get_active_error_handler()] during a compilation. *!
c0fa4e2006-03-25Henrik Grubbström (Grubba)  *! @item *! The compatibility handler *!
e290f32006-01-27Henrik Grubbström (Grubba)  *! This is the object returned by *! @[master()->get_compilation_handler()] (if any), which *! the compiler calls when it sees @tt{#pike@}-directives, *! or expressions using the version scope *! (eg @expr{7.4::rusage@}). This object is returned by *! @[get_active_compilation_handler()] during a compilation. *!
c0fa4e2006-03-25Henrik Grubbström (Grubba)  *! @item *! The master object. *!
e290f32006-01-27Henrik Grubbström (Grubba)  *! This is returned by @[master()] at any time. *! @endol *! *! Any of the objects may implement a subset of the @[CompilationHandler] *! functions, and the first object that implements a function will be *! used. The error handler object can thus be used to block certain *! functionality (eg to restrict the number of available functions). *! *! @seealso *! @[master()->get_compilation_handler()], @[get_active_error_handler()], *! @[get_active_compilation_handler()], @[compile()]
bbeddc2002-12-07Henrik Grubbström (Grubba)  */
9c1e6f2002-12-08Henrik Grubbström (Grubba) /*! @decl void compile_error(string filename, int line, string msg)
bbeddc2002-12-07Henrik Grubbström (Grubba)  *! *! Called by @[compile()] and @[cpp()] when they encounter *! errors in the code they compile. *!
9c1e6f2002-12-08Henrik Grubbström (Grubba)  *! @param filename *! File where the error was detected.
bbeddc2002-12-07Henrik Grubbström (Grubba)  *! *! @param line *! Line where the error was detected. *!
9c1e6f2002-12-08Henrik Grubbström (Grubba)  *! @param msg *! Description of error.
bbeddc2002-12-07Henrik Grubbström (Grubba)  *! *! @seealso *! @[compile_warning()]. */ /*! @decl void compile_exception(mixed exception) *! *! Called by @[compile()] and @[cpp()] if they trigger *! exceptions. */ /*! @decl mapping(string:mixed) get_predefines() *!
bd537b2002-12-10Martin Stjernholm  *! Called by @[cpp()] to get the set of global symbols.
bbeddc2002-12-07Henrik Grubbström (Grubba)  *! *! @returns *! Returns a mapping from symbol name to symbol value. *! Returns zero on failure. *! *! @seealso
bd537b2002-12-10Martin Stjernholm  *! @[resolv()], @[get_default_module()]
bbeddc2002-12-07Henrik Grubbström (Grubba)  */ /*! @decl mixed resolv(string symbol, string filename, @ *! CompilationHandler handler) *! *! Called by @[compile()] and @[cpp()] to resolv *! module references. *! *! @returns *! Returns the resolved value, or @[UNDEFINED] on failure. *! *! @seealso *! @[get_predefines()] */ /*! @decl mixed handle_import(string path, string filename, @ *! CompilationHandler handler) *! *! Called by @[compile()] and @[cpp()] to handle import *! directives specifying specific paths. *! *! @returns *! Returns the resolved value, or @[UNDEFINED] on failure. */
915e532002-12-08Henrik Grubbström (Grubba) /*! @decl string handle_include(string header_file, string current_file, @ *! int(0..1) is_local_ref) *!
cbe8c92003-04-07Martin Nilsson  *! Called by @[cpp()] to resolv @expr{#include@} and @expr{#string@} *! directives.
915e532002-12-08Henrik Grubbström (Grubba)  *! *! @param header_file *! File that was requested for inclusion. *! *! @param current_file
5486522002-12-08Henrik Grubbström (Grubba)  *! File where the directive was found.
915e532002-12-08Henrik Grubbström (Grubba)  *! *! @param is_local_ref *! Specifies reference method. *! @int *! @value 0
cbe8c92003-04-07Martin Nilsson  *! Directive was @expr{#include <header_file>@}.
915e532002-12-08Henrik Grubbström (Grubba)  *! @value 1
cbe8c92003-04-07Martin Nilsson  *! Directive was @expr{#include "header_file"@}.
915e532002-12-08Henrik Grubbström (Grubba)  *! @endint *! *! @returns *! Returns the filename to pass to @[read_include()] if found,
cbe8c92003-04-07Martin Nilsson  *! and @expr{0@} (zero) on failure.
915e532002-12-08Henrik Grubbström (Grubba)  *! *! @seealso *! @[read_include()] */ /*! @decl string read_include(string filename) *! *! Called by @[cpp()] to read included files. *! *! @param filename *! Filename as returned by @[handle_include()]. *! *! @returns *! Returns a string with the content of the header file on success,
cbe8c92003-04-07Martin Nilsson  *! and @expr{0@} (zero) on failure.
915e532002-12-08Henrik Grubbström (Grubba)  *! *! @seealso *! @[handle_include()] */
bbeddc2002-12-07Henrik Grubbström (Grubba) /*! @endclass */
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @namespace predef:: */ /*! @decl import cpp:: */ /*! @endnamespace */
fbf6c92004-06-29Henrik Grubbström (Grubba) /* #pike handling. */
6e2bb52018-01-05Henrik Grubbström (Grubba) void cpp_change_compat(struct CPP_struct *this, int major, int minor)
ac87152000-09-25Fredrik Hübinette (Hubbe) { if(this->compat_major == major && this->compat_minor == minor) return; if(this->compat_handler) { free_object(this->compat_handler); this->compat_handler=0; } if((major == PIKE_MAJOR_VERSION && minor == PIKE_MINOR_VERSION) || major < 0) { this->compat_major=PIKE_MAJOR_VERSION; this->compat_minor=PIKE_MINOR_VERSION; return; /* Our work here is done */ } push_int(major); push_int(minor); SAFE_APPLY_MASTER("get_compilation_handler",2);
19961b2017-04-08Martin Nilsson  if(TYPEOF(Pike_sp[-1]) == T_OBJECT)
ac87152000-09-25Fredrik Hübinette (Hubbe)  {
19961b2017-04-08Martin Nilsson  if (SUBTYPEOF(Pike_sp[-1])) {
f54c782004-12-22Henrik Grubbström (Grubba)  cpp_error(this, "#pike: Subtyped compilation handlers are not supported yet."); }
19961b2017-04-08Martin Nilsson  this->compat_handler=Pike_sp[-1].u.object;
50ea682003-03-14Henrik Grubbström (Grubba)  dmalloc_touch_svalue(Pike_sp-1);
19961b2017-04-08Martin Nilsson  Pike_sp--;
ac87152000-09-25Fredrik Hübinette (Hubbe)  } this->compat_major=major; this->compat_minor=minor; }
fbf6c92004-06-29Henrik Grubbström (Grubba) /* #if macros and functions. */
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @namespace cpp:: *! *! Pike has a builtin C-style preprocessor. It works similar to the *! ANSI-C preprocessor but has a few extra features. These and the *! default set of preprocessor macros are described here. */ /*! @directive #! *! *! All lines beginning with @[#!] will be regarded as comments, *! to enable shell integration. It is recommended that Pike applications *! begin with the line @tt{"#! /usr/bin/env pike"@} for maximum cross *! platform compatibility. */ /*! @directive #charset *!
0b8d2f2013-06-17Martin Nilsson  *! Inform the preprocessor about which charset the file is encoded *! with. The Charset module is called with this string to decode *! the remainder of the file.
4fa6542012-03-24Henrik Grubbström (Grubba)  */ /*! @directive #if *! *! The @[#if] directive can evaluate simple expressions and, if *! the expression is evaluates to true, "activate" the code block that *! follows. The code block ends when an @[#endif], @[#else], *! @[#elseif] or @[#elif] block is encountered at the same *! nesting depth. *! *! The @[#if] expressions may include defines, integer, string *! and float constants, @tt{?:@}, @tt{||@} and @tt{&&@} operations, *! @tt{~@}, @tt{^@}, @tt{!@}, @tt{|@} and @tt{&@} operations, *! @tt{<@}, @tt{>@}, @tt{<=@}, @tt{>=@}, @tt{==@} and @tt{!=@} operations, *! @tt{+@}, @tt{-@}, @tt{*@}, @tt{/@}, @tt{<<@} and @tt{>>@} operations *! and paranthesis. *! *! Strings may also be indexed with the @tt{[]@} index operator. *! Finally there are three special "functions" available in @[#if] *! expressions; @[defined()], @[efun()] and @[constant()]. *! *! @seealso *! @[#ifdef], @[#ifndef], @[#elif], @[#else], @[#endif], *! @[defined()], @[constant()], @[efun()] */ /*! @directive #ifdef *! *! Check whether an identifier is a macro. *! *! The directive *! *! @tt{#ifdef @i{<identifier>@}@} *!
bf2c0d2018-01-12Stephen R. van den Berg  *! is equivalent to
4fa6542012-03-24Henrik Grubbström (Grubba)  *! *! @tt{#if @[defined](@i{<identifier>@})@} *! *! @seealso *! @[#if], @[#ifndef], @[defined] */ /*! @directive #ifndef *! *! Check whether an identifier is not a macro. *! *! This is the inverse of @[#ifdef]. *! *! The directive *! *! @tt{#ifndef @i{<identifier>@}@} *!
bf2c0d2018-01-12Stephen R. van den Berg  *! is equivalent to
4fa6542012-03-24Henrik Grubbström (Grubba)  *! *! @tt{#if !@[defined](@i{<identifier>@})@} *! *! @seealso *! @[#if], @[#ifdef], @[defined] */
9565132014-02-14Martin Nilsson /*! @directive #require *! *! If the directive evaluates to false, the source file will be *! considered to have failed dependencies, and will not be found by *! the resolver. In practical terms the @[cpp()] call will return *! zero. *! *! @seealso *! @[#if] */
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @directive #endif *! *! End a block opened with @[#if], @[#ifdef], @[#ifndef], *! @[#else], @[#elseif] or @[#elif]. *! *! @example *! @code *! #ifdef DEBUG *! do_debug_stuff(); *! #endif // DEBUG *! @endcode */ /*! @directive #else *! *! This directive is used to divide the current code block into another *! code block with inverse activation. *! *! @example *! @code *! #ifdef FAST_ALGORITHM *! do_fast_algorithm(); *! #elif defined(EXPERIMENTAL_ALGORITHM) *! do_experimental_algorithm(); *! #else *! do_default_algorithm(); *! #endif *! @endcode */ /*! @directive #elif *! @directive #elseif *! *! These work as a combined @[#else] and @[#if] without *! adding an extra level of nesting. *! *! @example *!
bf2c0d2018-01-12Stephen R. van den Berg  *! The following two are equivalent:
4fa6542012-03-24Henrik Grubbström (Grubba)  *! *! @code *! #ifdef A *! // Code for A. *! #else *! #ifdef B *! // Code for B. *! #else *! #ifdef C *! // Code for C. *! #else *! // Code for D. *! #endif *! #endif *! #endif *! @endcode *! *! And *! *! @code *! #ifdef A *! // Code for A. *! #elif defined(B) *! // Code for B. *! #elseif defined(C) *! // Code for C. *! #else *! // Code for D. *! #endif *! @endcode *! *! @seealso *! @[#if], @[#ifdef], @[#else], @[defined()], @[constant()] */ /*! @directive #error *! *! Throw an error during preprocessing. *! *! This directive causes a cpp error. It can be used to notify *! the user that certain functions are missing and similar things. *! *! @note *! Note that this directive will cause @[cpp()] to throw *! an error at the end of preprocessing, which will cause *! any compilation to fail. *! *! @example *! @code *! #if !constant(Yp) *! #error Support for NIS not available. *! #endif *! @endcode *! *! @seealso *! @[#warning] */
78b7962018-01-15Henrik Grubbström (Grubba)  PIKEFUN string(0..0) directive_error(int flags, string line) { struct CPP_struct *this = THIS; if (OUTP()) { cpp_error_sprintf(this, "%O", Pike_sp - 1); } push_empty_string(); }
4fa6542012-03-24Henrik Grubbström (Grubba)  /*! @directive #warning *! *! Generate a warning during preprocessing. *! *! This directive causes a cpp warning, it can be used to notify *! the user that certain functions are missing and similar things. *! *! @example *! @code *! #if !constant(Yp) *! #warning Support for NIS not available. Some features may not work. *! #endif *! @endcode *! *! @seealso *! @[#error] */
78b7962018-01-15Henrik Grubbström (Grubba)  PIKEFUN string(0..0) directive_warning(int flags, string line) { struct CPP_struct *this = THIS; if (OUTP()) { cpp_warning(this, "%O", Pike_sp - 1); } push_empty_string(); }
4fa6542012-03-24Henrik Grubbström (Grubba)  /*! @directive #include *! *! @[#include] is used to insert the contents of another file into *! the processed file at the place of the include directive. *! *! Files can be referenced either by absolute or relative path from the *! source file, or searched for in the include paths. *! *! To include a file with absolute or relative path, use double quotes, *! e.g. @tt{#include "constants.pike"@} or @tt{#include "../debug.h"@}. *! *! To include from the include paths, use less than and greater than, *! e.g. @tt{#include <profiling.h>@}. *! *! It is also possible to include a file whose path is defined in a *! preprocessor macro, e.g. @tt{#include USER_SETTINGS@}. */ /*! @directive #line *! @directive #<integer> *! *! A hash character followed by a number or by the string *! @tt{"line"@} and a number will make the preprocessor line counter *! set this number as the line number for the next line and adjust the *! following lines accordingly. *! *! All error messages from Pike will use these line numbers. *! *! Optionally the number may be followed by a file name, e.g. *! @tt{#line 1 "/home/pike/program.pike.in"@}. Then this *! filename will be used instead of the current file for error *! messages. */ /*! @directive #pike *! *! Set the Pike compiler backward compatibility level. *! *! This tells the compiler which version of Pike it should *! attempt to emulate from this point on in the current *! compilation unit. *! *! This is typically used to "quick-fix" old code to work *! with more recent versions of Pike. *! *! @example *! @code *! // This code was written for Pike 7.2, and depends on
640b822016-09-10Henrik Grubbström (Grubba)  *! // the old behaviour for @expr{7.2::dirname()@}.
4fa6542012-03-24Henrik Grubbström (Grubba)  *! #pike 7.2 *! *! // ... Code that uses @[dirname()] ... *! @endcode *! *! This directive is also needed for Pike modules that *! have been installed globally, and might be used by *! a Pike that has been started with the @tt{-V@} flag. *! *! @example *! @code *! // Pike modules that are bundled with Pike are *! // typically written for the same version of Pike. *! #pike __REAL_VERSION__ *! @endcode */ /*! @directive #"" *! If a string literal is opened with @tt{#"@} newlines in the *! string will end up in the string literal, instead of triggering a *! @tt{"newline in string"@} error. *! *! @note *! Newlines will be converted to @tt{\n@} characters in the string *! even if the newlines in the file are something else. *! *! This preprocessor directive may appear anywhere a string may *! appear. *! *! @seealso *! @[#string] */
d6d2e52016-06-10Martin Nilsson /*! @directive #(#) *! @directive #[#] *! @directive #{#} *! If a string literal is opened with @tt{#(@} all subsequent *! characters until the closing @tt{#)@} will be treated as *! literals, including newlines, @tt{\@}, @tt{"@} and @tt{'@}. *! *! There are three different pairs of start/end tokens for this *! type of literals, #( and #), #[ and #], and #{ and #}. *! *! @example *! @expr{#["\n\'##]@} is equivalent to @expr{"\"\\n\\'#"@}.
b6fef02016-06-10Martin Nilsson  */
d6d2e52016-06-10Martin Nilsson 
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @directive #string *! The preprocessor directive @[#string] will load the file in the *! string that follows and insert its contents as a string. This *! preprocessor directive may appear anywhere a string may appear. *! *! @example *! @code *! do_something(#string "the_file.wks"); *! @endcode *! *! @seealso *! @[#include] */ /*! @directive #pragma *! *! This is a generic directive for flags to the compiler. *! *! These are some of the flags that are available: *! @string *! @value "all_inline" *! This is the same as adding the modifier @tt{inline@} *! to all functions that follow. *! @value "all_final" *! Instructs the compiler to mark all symbols as @tt{final@}.
d3abb82015-02-10Henrik Grubbström (Grubba)  *! @value "deprecation_warnings" *! Enable warnings for use of deprecated symbols (default). *! @value "no_deprecation_warnings" *! Disable warnings for use of deprecated symbols. This is *! typically used in code that implements the deprecated *! symbols.
4fa6542012-03-24Henrik Grubbström (Grubba)  *! @value "save_parent" *! Cause nested classes to save a reference to their *! surrounding class even if not strictly needed. *! @value "dont_save_parent" *! Inverse of @tt{"save_parent"@}. This is needed to override *! if the global symbol @[predef::__pragma_save_parent__] *! has been set. *! @value "strict_types" *! Enable warnings for all cases where the compiler *! isn't certain that the types are correct.
d3abb82015-02-10Henrik Grubbström (Grubba)  *! @value "disassemble" *! Enable disassembly output for the code being compiled. *! Note that this option essentially has a function-level *! scope, so enabling it for just a few lines is usually *! a noop. This is similar to @[Debug.assembler_debug()]
fdde6b2017-01-16Henrik Grubbström (Grubba)  *! level @expr{3@}.
d3abb82015-02-10Henrik Grubbström (Grubba)  *! @value "no_disassemble" *! Disable disassembly output (default).
4fa6542012-03-24Henrik Grubbström (Grubba)  *! @endstring
dddfca2018-02-22Henrik Grubbström (Grubba)  */ PIKEFUN string(0..0) directive_pragma(int flags, string line) { struct CPP_struct *this = THIS; if (OUTP()) { /* FIXME: Prefix with this->prefix? */ string_builder_strcat(&this->buf, "#pragma "); ref_push_string(line);
ff70852018-02-23Henrik Grubbström (Grubba)  push_int(flags & ~CPP_EXPECT_ENDIF);
dddfca2018-02-22Henrik Grubbström (Grubba)  apply_current(f_CPP_low_cpp_fun_num, 2); pop_stack(); } push_empty_string(); }
4fa6542012-03-24Henrik Grubbström (Grubba)  /*! @decl int(0..1) defined(mixed identifier) *! *! Check whether an identifier is a cpp macro or not. *! *! @returns *! @[defined] returns true if the symbol given as argument *! is defined. *! *! @note
bf2c0d2018-01-12Stephen R. van den Berg  *! @tt{#if defined(MY_DEF)@} is equivalent to
4fa6542012-03-24Henrik Grubbström (Grubba)  *! @tt{#ifdef MY_DEF@}. *! *! @seealso *! @[#if], @[#ifdef], @[constant()] */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void check_defined(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *arg,
fbf6c92004-06-29Henrik Grubbström (Grubba)  struct string_builder *tmp) {
3d6a1d2016-08-21Martin Nilsson  if(arg && FIND_DEFINE(arg))
fbf6c92004-06-29Henrik Grubbström (Grubba)  string_builder_binary_strcat(tmp, " 1 ", 3);
6e52062014-05-12Martin Nilsson  else
fbf6c92004-06-29Henrik Grubbström (Grubba)  string_builder_binary_strcat(tmp, " 0 ", 3); }
6e2bb52018-01-05Henrik Grubbström (Grubba) static int do_safe_index_call(struct CPP_struct *this, struct pike_string *s)
fbf6c92004-06-29Henrik Grubbström (Grubba) { int res; JMP_BUF recovery; if(!s) return 0; if (SETJMP_SP(recovery, 1)) {
abe9fe2014-09-18Martin Nilsson  if(this->picky_cpp)
7b2a532004-06-29Martin Nilsson  cpp_warning (this, "Error indexing module with %S.", s);
fbf6c92004-06-29Henrik Grubbström (Grubba)  res = 0; push_undefined(); } else { ref_push_string(s); f_index(2);
13670c2015-05-25Martin Nilsson 
19961b2017-04-08Martin Nilsson  res=!(UNSAFE_IS_ZERO(Pike_sp-1) && SUBTYPEOF(Pike_sp[-1]) == NUMBER_UNDEFINED);
fbf6c92004-06-29Henrik Grubbström (Grubba)  } UNSETJMP(recovery); return res; }
d2ac222014-02-15Martin Nilsson /*! @decl int(0..1) constant(mixed identifier) *! @decl __deprecated__ int(0..1) efun(mixed identifier) *! *! Check whether the argument resolves to a constant or not. *! *! @seealso *! @[#if], @[defined()] */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void cpp_constant(struct CPP_struct *this, int value)
fbf6c92004-06-29Henrik Grubbström (Grubba) {
19961b2017-04-08Martin Nilsson  struct svalue *save_stack=Pike_sp;
fbf6c92004-06-29Henrik Grubbström (Grubba)  struct array *arr;
a1640e2010-09-18Marcus Comstedt  INT_TYPE res = 0;
fbf6c92004-06-29Henrik Grubbström (Grubba)  int n; /* FIXME: Protection against errors. */ /* Remove extra whitespace. */
75367d2014-08-22Arne Goedeke  push_static_text(" ");
fbf6c92004-06-29Henrik Grubbström (Grubba)  o_subtract();
75367d2014-08-22Arne Goedeke  push_static_text("\t");
fbf6c92004-06-29Henrik Grubbström (Grubba)  o_subtract(); /* Split on . */
75367d2014-08-22Arne Goedeke  push_static_text(".");
fbf6c92004-06-29Henrik Grubbström (Grubba)  o_divide(); #ifdef PIKE_DEBUG
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-1]) != T_ARRAY) {
fbf6c92004-06-29Henrik Grubbström (Grubba)  Pike_fatal("Bad result from division in constant(): %s " "(expected array(string)).\n",
017b572011-10-28Henrik Grubbström (Grubba)  get_name_of_type(TYPEOF(Pike_sp[-1])));
fbf6c92004-06-29Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */ arr = Pike_sp[-1].u.array; #ifdef PIKE_DEBUG if (!arr->size) { Pike_fatal("Got an empty array from division in constant().\n"); } if ((arr->type_field & ~BIT_STRING) && (array_fix_type_field(arr) & ~BIT_STRING)) { Pike_fatal("Bad result from division in constant(): type_field: 0x%08x " "(expected array(string)).\n", arr->type_field & ~BIT_STRING); } #endif /* PIKE_DEBUG */ if (arr->item[0].u.string->len) { struct pike_string *str = arr->item[0].u.string; struct svalue *sv; if((sv=low_mapping_string_lookup(get_builtin_constants(), str))) { /* efun */ push_svalue(sv); res=1; } else if(get_master()) { /* Module. */ ref_push_string(str); ref_push_string(this->current_file); if (this->handler) { ref_push_object(this->handler); } else { push_int(0); } if (safe_apply_handler("resolv", this->handler, this->compat_handler, 3, 0)) {
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(Pike_sp[-1]) == T_OBJECT &&
fbf6c92004-06-29Henrik Grubbström (Grubba)  Pike_sp[-1].u.object == placeholder_object) ||
017b572011-10-28Henrik Grubbström (Grubba)  (TYPEOF(Pike_sp[-1]) == T_PROGRAM &&
fbf6c92004-06-29Henrik Grubbström (Grubba)  Pike_sp[-1].u.program == placeholder_program)) {
89f5432004-06-29Martin Nilsson  cpp_error_sprintf (this, "Got placeholder %s (resolver problem) " "when resolving %S.",
017b572011-10-28Henrik Grubbström (Grubba)  get_name_of_type(TYPEOF(Pike_sp[-1])),
89f5432004-06-29Martin Nilsson  str);
fbf6c92004-06-29Henrik Grubbström (Grubba)  } else
19961b2017-04-08Martin Nilsson  res = !(SAFE_IS_ZERO(Pike_sp-1) && SUBTYPEOF(Pike_sp[-1]) == NUMBER_UNDEFINED);
fbf6c92004-06-29Henrik Grubbström (Grubba)  }
017b572011-10-28Henrik Grubbström (Grubba)  else if (TYPEOF(throw_value) == T_STRING &&
fbf6c92004-06-29Henrik Grubbström (Grubba)  !throw_value.u.string->size_shift) { cpp_error(this, throw_value.u.string->str); free_svalue(&throw_value);
1ab4ac2008-01-26Martin Stjernholm  mark_free_svalue (&throw_value);
fbf6c92004-06-29Henrik Grubbström (Grubba)  res = 0;
91a2f62004-11-05Martin Nilsson  } else if(this->picky_cpp) {
7b2a532004-06-29Martin Nilsson  cpp_warning (this, "Error resolving %S.", str); res = 0;
fbf6c92004-06-29Henrik Grubbström (Grubba)  } } } else { /* Handle constant(.foo) */
75367d2014-08-22Arne Goedeke  push_static_text(".");
fbf6c92004-06-29Henrik Grubbström (Grubba)  ref_push_string(this->current_file); if (this->handler) { ref_push_object(this->handler); } else { push_int(0); } if (safe_apply_handler("handle_import", this->handler, this->compat_handler, 3, BIT_MAPPING|BIT_OBJECT|BIT_PROGRAM))
19961b2017-04-08Martin Nilsson  res = !(SAFE_IS_ZERO(Pike_sp-1) && SUBTYPEOF(Pike_sp[-1]) == NUMBER_UNDEFINED);
fbf6c92004-06-29Henrik Grubbström (Grubba)  else { cpp_handle_exception (this, "Error importing '.'."); } } for (n = 1; res && (n < arr->size); n++) { res = do_safe_index_call(this, arr->item[n].u.string); }
a1640e2010-09-18Marcus Comstedt  if (value && res) {
19961b2017-04-08Martin Nilsson  if (TYPEOF(Pike_sp[-1]) == T_INT) res = Pike_sp[-1].u.integer;
a1640e2010-09-18Marcus Comstedt  else res = 0; }
19961b2017-04-08Martin Nilsson  pop_n_elems(1 + Pike_sp - save_stack);
fbf6c92004-06-29Henrik Grubbström (Grubba)  push_int(res); }
0ca86e2005-04-09Henrik Grubbström (Grubba) static struct mapping *initial_predefs_mapping(void)
b584b12001-12-20Martin Stjernholm { struct pike_predef_s *def; struct mapping *map = allocate_mapping (0); #ifdef PIKE_DEBUG
5aad932002-08-15Marcus Comstedt  if (!use_initial_predefs) Pike_fatal ("Initial predefs has been taken over.\n");
b584b12001-12-20Martin Stjernholm #endif
df91472016-10-21Henrik Grubbström (Grubba)  for (def = first_predef; def; def = def->next) { struct pike_string *name = make_shared_string(def->name); struct pike_string *value = make_shared_string(def->value); mapping_string_insert_string(map, name, value); free_string(value); free_string(name); }
b584b12001-12-20Martin Stjernholm  return map; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static p_wchar2 readchar( PCHARP data, ptrdiff_t *pos, struct CPP_struct *this )
1f57ef2014-05-10Per Hedbor { ptrdiff_t l; p_wchar2 C; INC_PCHARP(data,*pos); switch(parse_esc_seq_pcharp (data, &C, &l)) { case 0: *pos += l; break; case 1: C = '\r'; *pos += 1; break; case 3: /* The eof will get caught in the next round. */ C = 0; *pos += 1; break; case 4: case 5: case 6: cpp_error (this, "Too large character value in escape."); C = (int) MAX_UINT32; *pos += l; break; case 7: cpp_error (this, "Too few hex digits in \\u escape."); C = '\\'; break; case 8: cpp_error (this, "Too few hex digits in \\U escape."); C = '\\'; break;
6e52062014-05-12Martin Nilsson #ifdef PIKE_DEBUG case 2: Pike_fatal ("Not supposed to happen.\n"); default: Pike_fatal ("Unknown error from parse_esc_seq.\n"); #endif
1f57ef2014-05-10Per Hedbor  } return C; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t readstring( struct CPP_struct *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos,
1f57ef2014-05-10Per Hedbor  struct string_builder*nf, int nl_ok) { while(1) { pos++; if(pos>=len) { cpp_error(this,"End of file in string."); break; } switch(INDEX_PCHARP(data,pos)) { case '"': break; case '\\': { pos++; if(INDEX_PCHARP(data,pos)=='\n') { this->current_line++; PUTNL(); continue; } if(INDEX_PCHARP(data,pos)=='\r' && INDEX_PCHARP(data,pos+1)=='\n') { pos++; this->current_line++; PUTNL(); continue; } string_builder_putchar(nf, readchar(data,&pos,this)); pos--; continue; } case '\r': continue; /* ignored */ case '\n': this->current_line++; if( nl_ok ) PUTNL(); else cpp_error(this,"Newline in string.");
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
1f57ef2014-05-10Per Hedbor  default: string_builder_putchar(nf, INDEX_PCHARP(data,pos)); continue; } pos++; break; } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t readstring_lit( struct CPP_struct *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos,
2028f82014-07-21Per Hedbor  struct string_builder*nf, INT32 ec) { INT32 ch;
b9a2a92015-07-06Arne Goedeke  while(1) { if(++pos>=len) {
2028f82014-07-21Per Hedbor  cpp_error(this,"End of file in string.");
b9a2a92015-07-06Arne Goedeke  break; } if((ch=INDEX_PCHARP(data,pos)) == '#' && INDEX_PCHARP(data,pos+1)==ec)
2028f82014-07-21Per Hedbor  return pos + 2;
b9a2a92015-07-06Arne Goedeke  else { if (ch == '\n') { this->current_line++; PUTNL(); }
2028f82014-07-21Per Hedbor  string_builder_putchar(nf, ch);
b9a2a92015-07-06Arne Goedeke  } }
2028f82014-07-21Per Hedbor  return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t fixstring(struct CPP_struct *this, const PCHARP data, ptrdiff_t len,
efd97a2014-05-12Martin Nilsson  ptrdiff_t pos, struct string_builder *nf, int outp)
1f57ef2014-05-10Per Hedbor { int trailing_newlines=0; if(outp) string_builder_putchar(nf, '"'); while(1) { if(pos>=len) { cpp_error(this,"End of file in string."); break; } switch(INDEX_PCHARP(data,pos++)) { case '\n': cpp_error(this,"Newline in string."); this->current_line++; break; case '"': break; case '\\': if(INDEX_PCHARP(data,pos)=='\n') { pos++; trailing_newlines++; this->current_line++; continue; } if(INDEX_PCHARP(data,pos)=='\r' && INDEX_PCHARP(data,pos+1)=='\n') { pos+=2; trailing_newlines++; this->current_line++; continue; } if(outp) string_builder_putchar(nf, '\\'); pos++; /* Fall through. */ default: if(outp) string_builder_putchar(nf, INDEX_PCHARP(data,pos-1)); continue; } break; } if(outp) string_builder_putchar(nf, '"'); while(trailing_newlines--) PUTNL(); return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t find_end_of_line( struct CPP_struct *this, const PCHARP data,
efd97a2014-05-12Martin Nilsson  ptrdiff_t len, ptrdiff_t pos, int emit )
1f57ef2014-05-10Per Hedbor { while(pos < len) { switch (INDEX_PCHARP(data,pos++)) { case '\n': return pos-1; case '\\': if (INDEX_PCHARP(data,pos) == '\n') { pos+=2; } else if ((INDEX_PCHARP(data,pos) == '\r') && (INDEX_PCHARP(data,pos+1) == '\n')) { pos+=3; } else { pos++; continue; } this->current_line++; if( emit ) PUTNL(); } } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t find_end_of_comment( struct CPP_struct *this, const PCHARP data, ptrdiff_t len,
efd97a2014-05-12Martin Nilsson  ptrdiff_t pos, int emit)
1f57ef2014-05-10Per Hedbor { pos++; while(INDEX_PCHARP(data,pos)!='*' || INDEX_PCHARP(data,pos+1)!='/')
13670c2015-05-25Martin Nilsson  {
1f57ef2014-05-10Per Hedbor  if(pos+2>=len) { cpp_error(this,"End of file in comment."); break; } if(INDEX_PCHARP(data,pos)=='\n') { this->current_line++; if( emit )PUTNL(); } pos++; } return pos + 2; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t find_end_quote(struct CPP_struct *this, const PCHARP data,
fbd0412016-10-01Henrik Grubbström (Grubba)  ptrdiff_t len, ptrdiff_t pos, p_wchar2 quote, int flags)
1f57ef2014-05-10Per Hedbor { while(1) {
fbd0412016-10-01Henrik Grubbström (Grubba)  p_wchar2 c;
1f57ef2014-05-10Per Hedbor  if(pos>=len) {
fbd0412016-10-01Henrik Grubbström (Grubba)  if (quote == '\'') { cpp_error(this,"End of file in character constant."); } else { cpp_error(this,"End of file in string."); }
1f57ef2014-05-10Per Hedbor  break; }
fbd0412016-10-01Henrik Grubbström (Grubba)  switch((c = INDEX_PCHARP(data,pos++)))
1f57ef2014-05-10Per Hedbor  { case '\n':
1238cd2016-09-29Henrik Grubbström (Grubba)  if (flags & CPP_END_AT_NEWLINE) {
fbd0412016-10-01Henrik Grubbström (Grubba)  if (quote == '\'') { cpp_error(this,"Newline in char."); } else { cpp_error(this,"Newline in string."); }
1238cd2016-09-29Henrik Grubbström (Grubba)  }
1f57ef2014-05-10Per Hedbor  this->current_line++; PUTNL(); break;
fbd0412016-10-01Henrik Grubbström (Grubba)  default: if (c == quote) return pos;
1f57ef2014-05-10Per Hedbor  break; case '\\': if(INDEX_PCHARP(data,pos)=='\n') { this->current_line++; PUTNL(); }
fbd0412016-10-01Henrik Grubbström (Grubba)  else if ((INDEX_PCHARP(data,pos) == '\r') && (INDEX_PCHARP(data,pos+1) == '\n')) {
1f57ef2014-05-10Per Hedbor  this->current_line++; pos++; PUTNL(); } pos++; } } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t find_end_brace(struct CPP_struct *this,
1f57ef2014-05-10Per Hedbor  PCHARP data, ptrdiff_t len, ptrdiff_t pos);
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t find_end_parenthesis(struct CPP_struct *this,
1f57ef2014-05-10Per Hedbor  PCHARP data, ptrdiff_t len, ptrdiff_t pos) /* pos is after the open paren. Returns the position after the close paren. */ { INT_TYPE start_line = this->current_line; while(1) { if(pos+1>=len) { INT_TYPE save_line = this->current_line; this->current_line = start_line; cpp_error(this, "End of file while looking for end parenthesis."); this->current_line = save_line; return pos; } switch(INDEX_PCHARP(data,pos++)) { case '\n': PUTNL(); this->current_line++; break;
fbd0412016-10-01Henrik Grubbström (Grubba)  case '\'': pos=find_end_quote(this,data,len,pos,'\'',CPP_END_AT_NEWLINE); break; case '"': pos=find_end_quote(this,data,len,pos,'\"',CPP_END_AT_NEWLINE); break;
1f57ef2014-05-10Per Hedbor  case '(': pos=find_end_parenthesis(this, data, len, pos); break; case '{': pos=find_end_brace(this, data, len, pos); break; case ')': return pos; case '/': if (INDEX_PCHARP(data,pos) == '*') { pos = find_end_of_comment(this,data,len,pos+1,0); } else if (INDEX_PCHARP(data,pos) == '/') { pos = find_end_of_line(this,data,len,pos+1,0); } } } }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t find_end_brace(struct CPP_struct *this,
90e5e92014-05-13Martin Nilsson  const PCHARP data,
1f57ef2014-05-10Per Hedbor  ptrdiff_t len, ptrdiff_t pos) /* pos is after the open brace. Returns the position after the close brace. */ { INT_TYPE start_line = this->current_line; while(1) { if(pos+1>=len) { INT_TYPE save_line = this->current_line; this->current_line = start_line; cpp_error(this, "End of file while looking for end brace."); this->current_line = save_line; return pos; } switch(INDEX_PCHARP(data,pos++)) { case '\n': PUTNL(); this->current_line++; break;
fbd0412016-10-01Henrik Grubbström (Grubba)  case '\'': pos=find_end_quote(this,data,len,pos,'\'',CPP_END_AT_NEWLINE); break; case '"': pos=find_end_quote(this,data,len,pos,'\"',CPP_END_AT_NEWLINE); break;
1f57ef2014-05-10Per Hedbor  case '{': pos=find_end_brace(this, data, len, pos); break; case '}': return pos; case '/': if (INDEX_PCHARP(data,pos) == '*') { pos=find_end_of_comment(this,data,len,pos,0); } else if (INDEX_PCHARP(data,pos) == '/') { pos=find_end_of_line(this,data,len,pos,0); } } } }
6e2bb52018-01-05Henrik Grubbström (Grubba) static struct pike_string *gobble_identifier (struct CPP_struct *this, const PCHARP data, ptrdiff_t *pos)
1f57ef2014-05-10Per Hedbor { ptrdiff_t p = *pos; struct string_builder sb;
74966e2014-05-12Per Hedbor  p_wchar2 tmp; if( !wide_isidchar( tmp = INDEX_PCHARP(data,*pos)) && tmp != '\\' ) return NULL;
1f57ef2014-05-10Per Hedbor  init_string_builder (&sb, 0); /* in fact, 0 is more likely than data.shift */ while (1) { ptrdiff_t start = p;
13670c2015-05-25Martin Nilsson  while (wide_isidchar (INDEX_PCHARP(data,p)))
1f57ef2014-05-10Per Hedbor  p++; if (p != start) { PCHARP x = data; INC_PCHARP(x,start); string_builder_append(&sb,x, p - start); } if (INDEX_PCHARP(data,p) != '\\') goto past_identifier; switch (INDEX_PCHARP(data,p + 1)) { case '\r': if (INDEX_PCHARP(data,p + 2) != '\n') goto past_identifier; p++; /* Fall through */ case '\n': this->current_line++; PUTNL(); p += 2; break; case 'u': case 'U': { /* Note: Code dup in parse_esc_seq in lexer.h. */ /* Don't have to bother checking for an even number of * preceding backslashes since they aren't valid outside * string and char literals in the lexer input. */ unsigned INT32 c = 0; ptrdiff_t stop, q; if (INDEX_PCHARP(data,p + 2) == INDEX_PCHARP(data,p + 1)) /* A quoted \u escape means we got "\uxxxx" dequoted here, * and that can't be part of an identifier. */ goto past_identifier; if (INDEX_PCHARP(data,p + 1) == 'u') stop = p + 6; else stop = p + 10; for (q = p + 2; q < stop; q++) { int tmp; switch (tmp=INDEX_PCHARP(data,q)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c = 16 * c + tmp - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = 16 * c + tmp - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = 16 * c + tmp - 'A' + 10; break; default: cpp_error_sprintf (this, "Too few hex digits in \\%c escape.", INDEX_PCHARP(data,p + 1)); goto past_identifier; } }
1585cf2014-05-10Per Hedbor  if (!wide_isidchar (c)) goto past_identifier;
1f57ef2014-05-10Per Hedbor  string_builder_putchar (&sb, c); p = q; break; } default: goto past_identifier; } } past_identifier: if (p != *pos) { *pos = p; return finish_string_builder (&sb); } free_string_builder (&sb); return NULL; }
e442822016-08-31Henrik Grubbström (Grubba) /* The reference to the define is held by the stack on return. */
7a61202016-09-04Henrik Grubbström (Grubba) static struct define_struct *alloc_empty_define(struct pike_string *name)
5740881998-01-01Fredrik Hübinette (Hubbe) {
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *def;
e442822016-08-31Henrik Grubbström (Grubba)  struct object *o; push_object(o = clone_object(define_program, 0));
7962c02016-09-01Henrik Grubbström (Grubba)  def = (struct define_struct *)get_storage(o, define_program);
500d462016-09-06Henrik Grubbström (Grubba)  add_ref(def->name = name);
5740881998-01-01Fredrik Hübinette (Hubbe)  return def; }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @directive #undef *! @directive #undefine *! *! This removes the effect of a @[#define], all subsequent occurances of *! the undefined identifier will not be replaced by anything. *! *! @note *! Note that when undefining a macro, you just give the identifer, *! not the arguments. *! *! @example *! // Strip debug *! #define werror(X ...) 0 *! #include "/home/someone/experimental/stuff.h" *! #undef werror *! *! @seealso *! @[#define], @[defined()] */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void undefine(struct CPP_struct *this, struct pike_string *name)
5740881998-01-01Fredrik Hübinette (Hubbe) {
e442822016-08-31Henrik Grubbström (Grubba)  ref_push_string(name); push_int(0); map_delete_no_free(this->defines, Pike_sp - 2, Pike_sp - 1);
5740881998-01-01Fredrik Hübinette (Hubbe) 
e442822016-08-31Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-1]) == PIKE_T_OBJECT) { struct object *o = Pike_sp[-1].u.object;
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *def = (struct define_struct *)get_storage(o, define_program);
7db6bc2016-09-08Henrik Grubbström (Grubba)  if (def->flags & (CPP_MACRO_IN_USE | CPP_MACRO_DISABLED)) {
e442822016-08-31Henrik Grubbström (Grubba)  /* Restore the #define. */ mapping_insert(this->defines, Pike_sp - 2, Pike_sp - 1); cpp_error(this, "Illegal to undefine a macro during its expansion."); pop_n_elems(2); return; }
8538192001-05-29Henrik Grubbström (Grubba)  }
e442822016-08-31Henrik Grubbström (Grubba)  pop_n_elems(2);
5740881998-01-01Fredrik Hübinette (Hubbe) }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @directive #define *! *! This directive is used to define or redefine a cpp macro. *! *! The simplest way to use define is to write *! *! @code *! #define @b{@i{<identifier>@}@} @i{<replacement string>@} *! @endcode *! *! which will cause all subsequent occurances of @tt{@b{@i{<identifier@}@}@} *! to be replaced with the @tt{@i{<replacement string>@}@}. *! *! Define also has the capability to use arguments, thus a line like *! *! @code *! #define @b{@i{<identifier>@}@}(arg1, arg2) @i{<replacement string>@} *! @endcode *! *! would cause @tt{@b{@i{<identifer>@}@}@} to be a macro. All occurances of *! '@tt{@b{@i{<identifier>@}@}(something1,something2d)@}' would be replaced *! with the @tt{@i{<replacement string>@}@}. *! And in the @tt{@i{<replacement string>@}@}, @tt{arg1@} and @tt{arg2@} *! will be replaced with @tt{something1@} and @tt{something2@}. */
6e2bb52018-01-05Henrik Grubbström (Grubba) static struct pike_string *make_define_name(struct CPP_struct *this,
a8e54c2016-09-06Martin Nilsson  const char *name)
5740881998-01-01Fredrik Hübinette (Hubbe) {
16a6f72011-11-27Tobias S. Josefowitz  if (this->prefix) { struct string_builder s; init_string_builder(&s, 0); string_builder_append(&s, MKPCHARP_STR(this->prefix), this->prefix->len); string_builder_putchar(&s, '_');
75942b2018-01-12Martin Nilsson  string_builder_strcat(&s, name);
a8e54c2016-09-06Martin Nilsson  return finish_string_builder(&s); } return make_shared_string(name); }
6e2bb52018-01-05Henrik Grubbström (Grubba) static struct define_struct *do_magic_define(struct CPP_struct *this,
a8e54c2016-09-06Martin Nilsson  const char *name, magic_define_fun fun) { struct define_struct* def;
500d462016-09-06Henrik Grubbström (Grubba)  struct pike_string *name_str = make_define_name(this, name); def = alloc_empty_define(name_str); free_string(name_str);
5740881998-01-01Fredrik Hübinette (Hubbe)  def->magic=fun;
279a4f2016-09-03Henrik Grubbström (Grubba)  mapping_string_insert(this->defines, def->name, Pike_sp-1);
e442822016-08-31Henrik Grubbström (Grubba)  pop_stack();
3c8ee52011-12-28Henrik Grubbström (Grubba)  return def;
5740881998-01-01Fredrik Hübinette (Hubbe) }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void add_define(struct CPP_struct *this,
b584b12001-12-20Martin Stjernholm  struct pike_string *name, struct pike_string *what) {
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct* def;
7a61202016-09-04Henrik Grubbström (Grubba)  def=alloc_empty_define(name); ref_push_string(what); f_aggregate(1); def->parts = Pike_sp[-1].u.array; Pike_sp--;
279a4f2016-09-03Henrik Grubbström (Grubba)  mapping_string_insert(this->defines, def->name, Pike_sp-1);
e442822016-08-31Henrik Grubbström (Grubba)  pop_stack();
b584b12001-12-20Martin Stjernholm }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void simple_add_define(struct CPP_struct *this,
90e5e92014-05-13Martin Nilsson  const char *name, const char *what)
5740881998-01-01Fredrik Hübinette (Hubbe) {
500d462016-09-06Henrik Grubbström (Grubba)  struct pike_string *name_str = make_define_name(this, name);
90314c2016-09-09Henrik Grubbström (Grubba)  struct pike_string *what_str = make_shared_string(what); add_define(this, name_str, what_str); free_string(what_str);
500d462016-09-06Henrik Grubbström (Grubba)  free_string(name_str);
5740881998-01-01Fredrik Hübinette (Hubbe) }
6e2bb52018-01-05Henrik Grubbström (Grubba) static struct pike_string *recode_string(struct CPP_struct *this, struct pike_string *data)
1c8da51999-02-24Henrik Grubbström (Grubba) { /* Observations: * * * At least a prefix of two bytes need to be 7bit in a valid * Pike program. * * * NUL isn't valid in a Pike program. */ /* Heuristic: * * Index 0 | Index 1 | Interpretation * --------+---------+------------------------------------------ * 0 | 0 | 32bit wide string. * 0 | >0 | 16bit Unicode string. * >0 | 0 | 16bit Unicode string reverse byte order. * 0xfe | 0xff | 16bit Unicode string. * 0xff | 0xfe | 16bit Unicode string reverse byte order. * 0x7b | 0x83 | EBCDIC-US ("#c"). * 0x7b | 0x40 | EBCDIC-US ("# "). * 0x7b | 0x09 | EBCDIC-US ("#\t"). * --------+---------+------------------------------------------ * Other | Other | 8bit standard string. * * Note that the tests below are more lenient than the table above. * This shouldn't matter, since the other cases would be erroneus * anyway. */ /* Add an extra reference to data, since we may return it as is. */ add_ref(data); if ((!((unsigned char *)data->str)[0]) || (((unsigned char *)data->str)[0] == 0xfe) || (((unsigned char *)data->str)[0] == 0xff) || (!((unsigned char *)data->str)[1])) { /* Unicode */ if ((!((unsigned char *)data->str)[0]) && (!((unsigned char *)data->str)[1])) { /* 32bit Unicode (UCS4) */
bc861d1999-02-25Henrik Grubbström (Grubba)  struct pike_string *new_str;
d0ad0a2000-08-08Henrik Grubbström (Grubba)  ptrdiff_t len; ptrdiff_t i; ptrdiff_t j;
bc861d1999-02-25Henrik Grubbström (Grubba)  p_wchar0 *orig = STR0(data); p_wchar2 *dest; if (data->len & 3) { /* String len is not a multiple of 4 */ return data; } len = data->len/4; new_str = begin_wide_shared_string(len, 2); dest = STR2(new_str); j = 0; for(i=0; i<len; i++) { dest[i] = (orig[j]<<24) | (orig[j+1]<<16) | (orig[j+2]<<8) | orig[j+3]; j += 4; } free_string(data); return(end_shared_string(new_str));
1c8da51999-02-24Henrik Grubbström (Grubba)  } else {
9aa6ec1999-02-25Henrik Grubbström (Grubba)  /* 16bit Unicode (UCS2) */
bc861d1999-02-25Henrik Grubbström (Grubba)  if (data->len & 1) { /* String len is not a multiple of 2 */ return data; }
1c8da51999-02-24Henrik Grubbström (Grubba)  if ((!((unsigned char *)data->str)[1]) || (((unsigned char *)data->str)[1] == 0xfe)) { /* Reverse Byte-order */
371abe1999-02-26Henrik Grubbström (Grubba)  struct pike_string *new_str = begin_shared_string(data->len);
9aa6ec1999-02-25Henrik Grubbström (Grubba)  int i; for(i=0; i<data->len; i++) { new_str->str[i^1] = data->str[i]; } free_string(data);
bc861d1999-02-25Henrik Grubbström (Grubba)  data = end_shared_string(new_str);
1c8da51999-02-24Henrik Grubbström (Grubba)  }
9aa6ec1999-02-25Henrik Grubbström (Grubba)  /* Note: We lose the extra reference to data here. */
1c8da51999-02-24Henrik Grubbström (Grubba)  push_string(data); f_unicode_to_string(1);
19961b2017-04-08Martin Nilsson  add_ref(data = Pike_sp[-1].u.string);
1c8da51999-02-24Henrik Grubbström (Grubba)  pop_stack();
bc861d1999-02-25Henrik Grubbström (Grubba)  return data;
1c8da51999-02-24Henrik Grubbström (Grubba)  }
371abe1999-02-26Henrik Grubbström (Grubba)  } else if (data->str[0] == '{') {
1c8da51999-02-24Henrik Grubbström (Grubba)  /* EBCDIC */ /* Notes on EBCDIC: * * * EBCDIC conversion needs to first convert the first line * according to EBCDIC-US, and then the rest of the string * according to the encoding specified by the first line. *
a4a1722000-12-05Per Hedbor  * * It's an error for a program written in EBCDIC not to
1c8da51999-02-24Henrik Grubbström (Grubba)  * start with a #charset directive. * * Obfuscation note: * * * This still allows the rest of the file to be written in * another encoding than EBCDIC. */
371abe1999-02-26Henrik Grubbström (Grubba)  /* First split out the first line. * * Note that codes 0x00 - 0x1f are the same in ASCII and EBCDIC. */ struct pike_string *new_str; char *p = strchr(data->str, '\n'); char *p2;
d0ad0a2000-08-08Henrik Grubbström (Grubba)  size_t len;
371abe1999-02-26Henrik Grubbström (Grubba)  if (!p) { return data; } len = p - data->str; if (len < CONSTANT_STRLEN("#charset ")) { return data; } new_str = begin_shared_string(len);
59fc9e2014-09-03Martin Nilsson  memcpy(new_str->str, data->str, len);
371abe1999-02-26Henrik Grubbström (Grubba)  push_string(end_shared_string(new_str));
75367d2014-08-22Arne Goedeke  push_static_text("ebcdic-us");
371abe1999-02-26Henrik Grubbström (Grubba) 
715e552003-11-14Martin Stjernholm  if (safe_apply_handler ("decode_charset", this->handler, this->compat_handler, 2, BIT_STRING)) { /* Various consistency checks. */
19961b2017-04-08Martin Nilsson  if ((Pike_sp[-1].u.string->size_shift) || (((size_t)Pike_sp[-1].u.string->len) < CONSTANT_STRLEN("#charset")) || (Pike_sp[-1].u.string->str[0] != '#')) {
715e552003-11-14Martin Stjernholm  pop_stack(); return data; } } else { cpp_handle_exception (this, "Error decoding with charset 'ebcdic-us'");
371abe1999-02-26Henrik Grubbström (Grubba)  return data; } /* At this point the decoded first line is on the stack. */ /* Extract the charset name */
19961b2017-04-08Martin Nilsson  p = Pike_sp[-1].u.string->str + 1;
371abe1999-02-26Henrik Grubbström (Grubba)  while (*p && isspace(*((unsigned char *)p))) { p++; } if (strncmp(p, "charset", CONSTANT_STRLEN("charset")) || !isspace(((unsigned char *)p)[CONSTANT_STRLEN("charset")])) { pop_stack(); return data; }
7bfa4f1999-03-09Henrik Grubbström (Grubba)  p += CONSTANT_STRLEN("charset") + 1; while (*p && isspace(*((unsigned char *)p))) { p++; } if (!*p) { pop_stack(); return data; } /* Build a string of the trailing data * NOTE: * Keep the newline, so the linenumber info stays correct. */ new_str = begin_shared_string(data->len - len);
59fc9e2014-09-03Martin Nilsson  memcpy(new_str->str, data->str + len, data->len - len);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  push_string(end_shared_string(new_str)); stack_swap(); /* Build a string of the charset name */ p2 = p; while(*p2 && !isspace(*((unsigned char *)p2))) { p2++; } len = p2 - p; new_str = begin_shared_string(len);
59fc9e2014-09-03Martin Nilsson  memcpy(new_str->str, p, len);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  pop_stack();
20c0062004-06-30Henrik Grubbström (Grubba)  ref_push_string(new_str = end_shared_string(new_str));
b7df6e2014-05-12Per Hedbor 
7bfa4f1999-03-09Henrik Grubbström (Grubba)  /* Decode the string */
715e552003-11-14Martin Stjernholm  if (!safe_apply_handler ("decode_charset", this->handler, this->compat_handler, 2, BIT_STRING)) {
4045632004-06-29Martin Nilsson  cpp_handle_exception (this, "Error decoding with charset %S", new_str);
715e552003-11-14Martin Stjernholm  free_string (new_str);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  return data; }
715e552003-11-14Martin Stjernholm  free_string (new_str);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  /* Accept the new string */ free_string(data);
19961b2017-04-08Martin Nilsson  add_ref(data = Pike_sp[-1].u.string);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  pop_stack(); } return data; } static struct pike_string *filter_bom(struct pike_string *data) { /* More notes: * * * Character 0xfeff (ZERO WIDTH NO-BREAK SPACE = BYTE ORDER MARK = BOM) * needs to be filtered away before processing continues. */
7e16612000-08-10Henrik Grubbström (Grubba)  ptrdiff_t i; ptrdiff_t j = 0; ptrdiff_t len = data->len;
7bfa4f1999-03-09Henrik Grubbström (Grubba)  struct string_builder buf; /* Add an extra reference to data here, since we may return it as is. */ add_ref(data); if (!data->size_shift) { return(data); }
13670c2015-05-25Martin Nilsson 
7bfa4f1999-03-09Henrik Grubbström (Grubba)  init_string_builder(&buf, data->size_shift); if (data->size_shift == 1) { /* 16 bit string */ p_wchar1 *ptr = STR1(data); for(i = 0; i<len; i++) { if (ptr[i] == 0xfeff) { if (i != j) {
13d2d32004-11-14Martin Stjernholm  string_builder_binary_strcat1 (&buf, ptr + j, i - j);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  j = i+1; } } } if ((j) && (i != j)) { /* Add the trailing string */
13d2d32004-11-14Martin Stjernholm  string_builder_binary_strcat1 (&buf, ptr + j, i - j);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  free_string(data); data = finish_string_builder(&buf); } else { /* String didn't contain 0xfeff */ free_string_builder(&buf); } } else { /* 32 bit string */ p_wchar2 *ptr = STR2(data); for(i = 0; i<len; i++) { if (ptr[i] == 0xfeff) { if (i != j) {
13d2d32004-11-14Martin Stjernholm  string_builder_binary_strcat2 (&buf, ptr + j, i - j);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  j = i+1; } } } if ((j) && (i != j)) { /* Add the trailing string */
13d2d32004-11-14Martin Stjernholm  string_builder_binary_strcat2 (&buf, ptr + j, i - j);
7bfa4f1999-03-09Henrik Grubbström (Grubba)  free_string(data); data = finish_string_builder(&buf); } else { /* String didn't contain 0xfeff */ free_string_builder(&buf); } } return(data); }
7b73fb2014-05-10Per Hedbor #define PUSH_STRING0(X,Y,Z) add_quoted_string( X,Y,0,Z)
1585cf2014-05-10Per Hedbor #define PUSH_STRING_SHIFT(X,Y,Z,A) add_quoted_string(X,Y,Z,A)
48c4ef2016-12-17Martin Nilsson 
b7df6e2014-05-12Per Hedbor /* * Generic macros */
efd97a2014-05-12Martin Nilsson #define CHECK_WORD(X,LEN) (begins_with(X,ADD_PCHARP(data,pos),(LEN),len-pos,1)) #define GOBBLE_WORD(X) (CHECK_WORD(X,NELEM(X)) ? (pos+=NELEM(X)),1 : 0)
fbd0412016-10-01Henrik Grubbström (Grubba) #define FIND_END_OF_STRING(FLAGS) (pos=find_end_quote(this,data,len,pos,'\"',FLAGS)) #define FIND_END_OF_CHAR() (pos=find_end_quote(this,data,len,pos,'\'',CPP_END_AT_NEWLINE))
b7df6e2014-05-12Per Hedbor #define FIND_EOL_PRETEND() (pos=find_end_of_line(this,data,len,pos,0)) #define FIND_EOL() (pos=find_end_of_line(this,data,len,pos,1)) #define SKIPCOMMENT_INC_LINES() (pos=find_end_of_comment(this,data,len,pos,0)) #define SKIPCOMMENT() (pos=find_end_of_comment(this,data,len,pos,1)) #define FIND_EOS() (pos=find_eos(this,data,len,pos)) /* Skips horizontal whitespace and newlines. */ #define SKIPWHITE() (pos=skipwhite(this,data,pos)) /* Skips horizontal whitespace and escaped newlines. */ #define SKIPSPACE() (pos=skipspace(this,data,pos,1)) #define SKIPSPACE_PRETEND() (pos=skipspace(this,data,pos,0)) /* At entry pos points past the start quote. * At exit pos points past the end quote. */ #define READSTRING(nf) (pos=readstring(this,data,len,pos,&nf,0)) #define READSTRING2(nf) (pos=readstring(this,data,len,pos,&nf,1))
2028f82014-07-21Per Hedbor #define READSTRING3(nf,ec) (pos=readstring_lit(this,data,len,pos,&nf,ec))
b7df6e2014-05-12Per Hedbor #define FIXSTRING(nf,outp) (pos=fixstring(this,data,len,pos,&nf,outp)) /* Gobble an identifier at the current position. */ #define GOBBLE_IDENTIFIER() dmalloc_touch (struct pike_string *, gobble_identifier(this,data,&pos)) #define READCHAR(C) (C=readchar(data,&pos,this)) #define DATA(X) INDEX_PCHARP(data,X)
efd97a2014-05-12Martin Nilsson #define HAS_PREFIX(X) \
b7df6e2014-05-12Per Hedbor  ((begins_with(X,ADD_PCHARP(data,pos),sizeof(X),len-pos,0)) ? (pos += NELEM(X)),1 : 0)
1585cf2014-05-10Per Hedbor 
90e5e92014-05-13Martin Nilsson static void add_quoted_string( const void *str, ptrdiff_t len, int shift,
7b73fb2014-05-10Per Hedbor  struct string_builder *dst ) { struct pike_string *x = make_shared_binary_pcharp( MKPCHARP(str,shift), len ); string_builder_putchar( dst, '"' ); string_builder_quote_string( dst, x, 0, 0x7fffffff, 0 ); string_builder_putchar( dst, '"' ); free_string(x); }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t find_eos( struct CPP_struct *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos )
1585cf2014-05-10Per Hedbor { while(pos < len) {
b7df6e2014-05-12Per Hedbor  switch (DATA(pos++)) {
1585cf2014-05-10Per Hedbor  case '\n': break; case '/':
b7df6e2014-05-12Per Hedbor  if (DATA(pos) == '/') {
1585cf2014-05-10Per Hedbor  pos = find_end_of_line(this,data,len,pos,0); break;
b7df6e2014-05-12Per Hedbor  } else if (DATA(pos) == '*') {
1585cf2014-05-10Per Hedbor  pos = find_end_of_comment(this,data,len,pos,0); } continue; case '\\':
b7df6e2014-05-12Per Hedbor  if (DATA(pos) == '\n') {
1585cf2014-05-10Per Hedbor  pos+=1;
b7df6e2014-05-12Per Hedbor  } else if ((DATA(pos) == '\r') && (DATA(pos+1) == '\n')) {
1585cf2014-05-10Per Hedbor  pos+=2; } else { continue; } this->current_line++;
3595ea2018-02-12Marcus Comstedt  /* FALLTHRU */
1585cf2014-05-10Per Hedbor  default: continue; } this->current_line++; break; } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t skipwhite(struct CPP_struct *this, const PCHARP data, ptrdiff_t pos)
1585cf2014-05-10Per Hedbor {
13670c2015-05-25Martin Nilsson  do
1585cf2014-05-10Per Hedbor  { int c;
b7df6e2014-05-12Per Hedbor  if(!wide_isspace(c=DATA(pos)))
1585cf2014-05-10Per Hedbor  {
13670c2015-05-25Martin Nilsson  if (c == '\\')
1585cf2014-05-10Per Hedbor  {
13670c2015-05-25Martin Nilsson  if (DATA(pos+1) == '\n')
1585cf2014-05-10Per Hedbor  { pos += 2; PUTNL(); this->current_line++; continue;
b7df6e2014-05-12Per Hedbor  } else if ((DATA(pos+1) == '\r') && (DATA(pos+2) == '\n')) {
1585cf2014-05-10Per Hedbor  pos += 3; PUTNL(); this->current_line++; continue; } } break; }
13670c2015-05-25Martin Nilsson  else if(c=='\n') { PUTNL(); this->current_line++;
1585cf2014-05-10Per Hedbor  } pos++; } while(1); return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t skipspace(struct CPP_struct *this, const PCHARP data, ptrdiff_t pos, int emit)
1585cf2014-05-10Per Hedbor { do { int c;
b7df6e2014-05-12Per Hedbor  while (wide_isspace(c=DATA(pos)) && c!='\n') {
1585cf2014-05-10Per Hedbor  pos++; } if (c == '\\') {
b7df6e2014-05-12Per Hedbor  if (DATA(pos+1) == '\n') {
1585cf2014-05-10Per Hedbor  pos+=2;
b7df6e2014-05-12Per Hedbor  } else if ((DATA(pos+1) == '\r') && (DATA(pos+2) == '\n')) {
1585cf2014-05-10Per Hedbor  pos+=3; } else { break; } } else { break; } if( emit ) { PUTNL(); this->current_line++; } } while (1); return pos; } static const char eq_[] = { '=', '=' }; static const char ne_[] = { '!', '=' }; static const char land_[] = { '&', '&' }; static const char lor_[] = { '|', '|' }; static const char string_recur_[] = { 's', 't', 'r', 'i', 'n', 'g', '_', 'r', 'e', 'c', 'u', 'r' }; static const char include_recur_[] = { 'i', 'n', 'c', 'l', 'u', 'd', 'e', '_', 'r', 'e', 'c', 'u', 'r' }; static const char line_[] = { 'l', 'i', 'n', 'e' }; static const char string_[] = { 's', 't', 'r', 'i', 'n', 'g' }; static const char include_[] = { 'i', 'n', 'c', 'l', 'u', 'd', 'e' }; static const char if_[] = { 'i', 'f' }; static const char ifdef_[] = { 'i', 'f', 'd', 'e', 'f' }; static const char ifndef_[] = { 'i', 'f', 'n', 'd', 'e', 'f' }; static const char endif_[] = { 'e', 'n', 'd', 'i', 'f' }; static const char else_[] = { 'e', 'l', 's', 'e' }; static const char elseif_[] = { 'e', 'l', 's', 'e', 'i', 'f' }; static const char elif_[] = { 'e', 'l', 'i', 'f' }; static const char define_[] = { 'd', 'e', 'f', 'i', 'n', 'e' }; static const char undef_[] = { 'u', 'n', 'd', 'e', 'f' }; static const char undefine_[] = { 'u', 'n', 'd', 'e', 'f', 'i', 'n', 'e' }; static const char charset_[] = { 'c', 'h', 'a', 'r', 's', 'e', 't' }; static const char pragma_[] = { 'p', 'r', 'a', 'g', 'm', 'a' }; static const char pike_[] = { 'p', 'i', 'k', 'e' }; static const char require_[] = { 'r', 'e', 'q', 'u', 'i', 'r', 'e' }; static const char lsh_[] = { '<', '<' }; static const char rsh_[] = { '>', '>' };
90e5e92014-05-13Martin Nilsson static int begins_with( const char *prefix, const PCHARP stack, int len, int remain, int whole )
1585cf2014-05-10Per Hedbor { int i;
74966e2014-05-12Per Hedbor  if( len > remain ) return 0;
1585cf2014-05-10Per Hedbor  for( i=0; i<len; i++ ) if( INDEX_PCHARP(stack,i) != prefix[i] ) return 0;
74966e2014-05-12Per Hedbor  if( whole && len != remain && wide_isidchar(INDEX_PCHARP(stack,len)) ) return 0;
1585cf2014-05-10Per Hedbor  return 1; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t low_cpp(struct CPP_struct *this,
58efb82014-05-12Per Hedbor  PCHARP data, ptrdiff_t len, int flags, struct pike_string *charset);
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_callback_define(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *def,
3d6a1d2016-08-21Martin Nilsson  struct pike_string *arg,
75a9f62011-12-04Arne Goedeke  struct string_builder *tmp);
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_callback_define_no_args(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *def,
3d6a1d2016-08-21Martin Nilsson  struct pike_string *arg,
75a9f62011-12-04Arne Goedeke  struct string_builder *tmp);
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_pragma(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *def,
3d6a1d2016-08-21Martin Nilsson  struct pike_string *arg,
51d3f32011-12-28Henrik Grubbström (Grubba)  struct string_builder *tmp);
7b73fb2014-05-10Per Hedbor 
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc1(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags);
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calcC(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { SKIPWHITE(); CALC_DUMPPOS("calcC");
b7df6e2014-05-12Per Hedbor  switch(DATA(pos))
74966e2014-05-12Per Hedbor  { case '(': pos=calc1(this,data,len,pos+1,flags); SKIPWHITE(); if(!GOBBLE(')')) cpp_error(this, "Missing ')'"); break;
b7df6e2014-05-12Per Hedbor 
74966e2014-05-12Per Hedbor  case '0':
b7df6e2014-05-12Per Hedbor  if(DATA(pos+1)=='x' || DATA(pos+1)=='X')
74966e2014-05-12Per Hedbor  { PCHARP p = data; INC_PCHARP(p,pos + 2); push_int(0); safe_wide_string_to_svalue_inumber(Pike_sp-1, p.ptr, &p.ptr, 16, 0, p.shift); if(!OUTP()) pop_stack(); pos = SUBTRACT_PCHARP(p,data); break; }
3595ea2018-02-12Marcus Comstedt  /* FALLTHRU */
b7df6e2014-05-12Per Hedbor 
74966e2014-05-12Per Hedbor  case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { PCHARP p1,p2; PCHARP p; double f; long l; /* FIXME: Support bignums. */
b7df6e2014-05-12Per Hedbor 
74966e2014-05-12Per Hedbor  p = ADD_PCHARP(data,pos); f = STRTOD_PCHARP(p, &p1); l = STRTOL_PCHARP(p, &p2, 0); if(COMPARE_PCHARP(p1,>,p2)) { if(OUTP())
bd67392015-10-14Martin Nilsson  push_float((FLOAT_TYPE)f);
74966e2014-05-12Per Hedbor  pos = SUBTRACT_PCHARP(p1,data); }else{ if(OUTP()) push_int(l); pos = SUBTRACT_PCHARP(p2,data); } break; } case '\'': {
b7df6e2014-05-12Per Hedbor  p_wchar2 tmp = DATA(++pos);
74966e2014-05-12Per Hedbor  if (tmp == '\\') READCHAR(tmp); pos++; // FIXME: Multi char char constants here as well. if(!GOBBLE('\'')) cpp_error(this, "Missing end quote in character constant."); if(OUTP()) push_int(tmp); break; } case '"': { struct string_builder s; init_string_builder(&s, 0); READSTRING(s); if(OUTP()) push_string(finish_string_builder(&s)); else free_string_builder(&s); break; }
b7df6e2014-05-12Per Hedbor 
74966e2014-05-12Per Hedbor  default: { struct pike_string *func_name = gobble_identifier(this,data,&pos);
b7df6e2014-05-12Per Hedbor  if (func_name || DATA(pos) == '.') { /* NOTE: defined() can not be handled here,
74966e2014-05-12Per Hedbor  * since the argument must not be expanded. */ SKIPWHITE(); if ( (func_name==constant_str || func_name==efun_str) &&
b7df6e2014-05-12Per Hedbor  DATA(pos) == '(')
74966e2014-05-12Per Hedbor  { int start, end; int arg = 0; INT_TYPE start_line; if( func_name==efun_str && !CPP_TEST_COMPAT(this,7,9) ) cpp_warning(this, "Directive efun() deprecated."); pos++; /* GOBBLE('(') */ start_line = this->current_line; SKIPWHITE(); start = end = pos;
b7df6e2014-05-12Per Hedbor  while (DATA(pos) != ')') { switch(DATA(pos++)) {
74966e2014-05-12Per Hedbor  case '(': pos = find_end_parenthesis(this, data, len, pos); break; case ',': push_string(make_shared_binary_pcharp(ADD_PCHARP(data,start), end-start)); arg++; start = pos; break; case '/':
b7df6e2014-05-12Per Hedbor  if (DATA(pos) == '*') {
74966e2014-05-12Per Hedbor  pos++; if (this->keep_comments) { start = pos - 2; SKIPCOMMENT_INC_LINES();
13670c2015-05-25Martin Nilsson  } else
74966e2014-05-12Per Hedbor  SKIPCOMMENT();
b7df6e2014-05-12Per Hedbor  } else if (DATA(pos) == '/') {
74966e2014-05-12Per Hedbor  if (this->keep_comments) { start = pos - 1; FIND_EOL_PRETEND(); } else FIND_EOL(); } break; case '\0': if (pos > len) { INT_TYPE old_line = this->current_line; this->current_line = start_line; cpp_error_sprintf(this, "Missing ) in the meta function %S().", func_name); this->current_line = old_line; free_string (func_name); return pos-1; }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
74966e2014-05-12Per Hedbor  default:
a550902016-12-17Martin Nilsson  if (wide_isspace(DATA(pos-1))) {
74966e2014-05-12Per Hedbor  SKIPWHITE(); continue; } break; } end = pos; }
b7df6e2014-05-12Per Hedbor 
74966e2014-05-12Per Hedbor  if (start != end) { push_string(make_shared_binary_pcharp(ADD_PCHARP(data,start), end-start)); arg++; } if(!GOBBLE(')')) { INT_TYPE old_line = this->current_line; this->current_line = start_line; cpp_error_sprintf(this, "Missing ) in the meta function %S().", func_name); this->current_line = old_line; } /* NOTE: cpp_func MUST protect against errors. */ if(OUTP()) { if (arg != 1) { cpp_error_sprintf(this, "Bad number of arguments to %S().", func_name); pop_n_elems(arg); push_int(0); } else cpp_constant(this, 0); } else pop_n_elems(arg);
b7df6e2014-05-12Per Hedbor  } else if (DATA(pos) == '.') {
74966e2014-05-12Per Hedbor  if (func_name == NULL) add_ref((func_name = empty_pike_string)); while (GOBBLE('.')) { struct pike_string *ind_name; SKIPWHITE(); ind_name = gobble_identifier(this,data,&pos); if (ind_name == NULL) { cpp_error_sprintf(this, "Syntax error in #if missing identifier after '.'."); free_string (func_name); func_name = NULL; break; } if(OUTP()) { push_string (func_name);
5e9fc02015-08-18Per Hedbor  push_static_text (".");
74966e2014-05-12Per Hedbor  push_string (ind_name); f_add(3); func_name = Pike_sp[-1].u.string; --Pike_sp; } SKIPWHITE(); } if (func_name == NULL) break; if(OUTP()) { ref_push_string(func_name); cpp_constant(this, 1); } } else { if(OUTP()) push_int(0); } free_string (func_name); break; } cpp_error_sprintf(this, "Syntax error in #if bad character %c (%d).",
b7df6e2014-05-12Per Hedbor  DATA(pos), DATA(pos));
74966e2014-05-12Per Hedbor  break; } } SKIPWHITE(); while(GOBBLE('[')) { CALC_DUMPPOS("inside calcC"); pos=calc1(this,data,len,pos,flags); if(OUTP()) f_index(2); SKIPWHITE(); if(!GOBBLE(']')) cpp_error(this, "Missing ']'."); } CALC_DUMPPOS("after calcC"); return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calcB(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calcB"); SKIPWHITE();
b7df6e2014-05-12Per Hedbor  switch(DATA(pos))
74966e2014-05-12Per Hedbor  { case '-': pos++; pos=calcB(this,data,len,pos,flags); if(OUTP()) o_negate(); break; case '!': pos++; pos=calcB(this,data,len,pos,flags); if(OUTP()) o_not(); break; case '~': pos++; pos=calcB(this,data,len,pos,flags); if(OUTP()) o_compl(); break; default: pos=calcC(this,data,len,pos,flags); } CALC_DUMPPOS("after calcB"); return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calcA(struct CPP_struct *this,PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calcA"); pos=calcB(this,data,len,pos,flags); while(1) { CALC_DUMPPOS("inside calcA"); SKIPWHITE();
b7df6e2014-05-12Per Hedbor  switch(DATA(pos))
74966e2014-05-12Per Hedbor  { case '/':
b7df6e2014-05-12Per Hedbor  if(DATA(pos+1)=='/' || DATA(pos+1)=='*')
74966e2014-05-12Per Hedbor  return pos; pos++; pos=calcB(this,data,len,pos,flags); if(OUTP()) o_divide(); continue; case '*': pos++; pos=calcB(this,data,len,pos,flags); if(OUTP()) o_multiply(); continue; case '%': pos++; pos=calcB(this,data,len,pos,flags); if(OUTP()) o_mod(); continue; } break; } CALC_DUMPPOS("after calcA"); return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc9(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc9"); pos=calcA(this,data,len,pos,flags); while(1) { CALC_DUMPPOS("inside calc9"); SKIPWHITE();
b7df6e2014-05-12Per Hedbor  switch(DATA(pos))
74966e2014-05-12Per Hedbor  { case '+': pos++; pos=calcA(this,data,len,pos,flags); if(OUTP()) f_add(2); continue; case '-': pos++; pos=calcA(this,data,len,pos,flags); if(OUTP()) o_subtract(); continue; } break; } CALC_DUMPPOS("after calc9"); return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc8(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc8"); pos=calc9(this,data,len,pos,flags); while(1) { CALC_DUMPPOS("inside calc8"); SKIPWHITE();
efd97a2014-05-12Martin Nilsson  if(HAS_PREFIX(lsh_))
74966e2014-05-12Per Hedbor  { CALC_DUMPPOS("Found <<"); pos=calc9(this,data,len,pos,flags); if(OUTP()) o_lsh(); break; }
efd97a2014-05-12Martin Nilsson  if(HAS_PREFIX(rsh_))
74966e2014-05-12Per Hedbor  { CALC_DUMPPOS("Found >>"); pos=calc9(this,data,len,pos,flags); if(OUTP()) o_rsh(); break; } break; } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc7b(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc7b"); pos=calc8(this,data,len,pos,flags); while(1) { CALC_DUMPPOS("inside calc7b"); SKIPWHITE();
b7df6e2014-05-12Per Hedbor  switch(DATA(pos))
74966e2014-05-12Per Hedbor  { case '<':
b7df6e2014-05-12Per Hedbor  if(DATA(pos+1) == '<') break;
74966e2014-05-12Per Hedbor  pos++; if(GOBBLE('=')) { pos=calc8(this,data,len,pos,flags); if(OUTP()) f_le(2); }else{ pos=calc8(this,data,len,pos,flags); if(OUTP()) f_lt(2); } continue; case '>':
b7df6e2014-05-12Per Hedbor  if(DATA(pos+1) == '>') break;
74966e2014-05-12Per Hedbor  pos++; if(GOBBLE('=')) { pos=calc8(this,data,len,pos,flags); if(OUTP()) f_ge(2); }else{ pos=calc8(this,data,len,pos,flags); if(OUTP()) f_gt(2); } continue; } break; } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc7(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc7"); pos=calc7b(this,data,len,pos,flags); while(1) { CALC_DUMPPOS("inside calc7"); SKIPWHITE();
efd97a2014-05-12Martin Nilsson  if(HAS_PREFIX(eq_))
74966e2014-05-12Per Hedbor  { pos=calc7b(this,data,len,pos,flags); if(OUTP()) f_eq(2); continue; }
efd97a2014-05-12Martin Nilsson  if(HAS_PREFIX(ne_))
74966e2014-05-12Per Hedbor  { pos=calc7b(this,data,len,pos,flags); if(OUTP()) f_ne(2); continue; } break; } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc6(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc6"); pos=calc7(this,data,len,pos,flags); SKIPWHITE();
b7df6e2014-05-12Per Hedbor  while(DATA(pos) == '&' && DATA(pos+1)!='&')
74966e2014-05-12Per Hedbor  { CALC_DUMPPOS("inside calc6"); pos++; pos=calc7(this,data,len,pos,flags); if(OUTP()) o_and(); } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc5(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc5"); pos=calc6(this,data,len,pos,flags); SKIPWHITE(); while(GOBBLE('^')) { CALC_DUMPPOS("inside calc5"); pos=calc6(this,data,len,pos,flags); if(OUTP()) o_xor(); } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc4(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc4"); pos=calc5(this,data,len,pos,flags); SKIPWHITE();
b7df6e2014-05-12Per Hedbor  while(DATA(pos) == '|' && DATA(pos+1)!='|')
74966e2014-05-12Per Hedbor  { CALC_DUMPPOS("inside calc4"); pos++; pos=calc5(this,data,len,pos,flags); if(OUTP()) o_or(); } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc3(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc3"); pos=calc4(this,data,len,pos,flags); SKIPWHITE();
efd97a2014-05-12Martin Nilsson  while(HAS_PREFIX(land_))
74966e2014-05-12Per Hedbor  { CALC_DUMPPOS("inside calc3"); if(OUTP()) { check_destructed(Pike_sp-1); if(UNSAFE_IS_ZERO(Pike_sp-1)) { pos=calc4(this,data,len,pos,flags|CPP_REALLY_NO_OUTPUT); }else{ pop_stack(); pos=calc4(this,data,len,pos,flags); } } else pos=calc4(this,data,len,pos,flags); } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc2(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc2"); pos=calc3(this,data,len,pos,flags); SKIPWHITE();
efd97a2014-05-12Martin Nilsson  while(HAS_PREFIX(lor_))
74966e2014-05-12Per Hedbor  { CALC_DUMPPOS("inside calc2"); if(OUTP()) { check_destructed(Pike_sp-1); if(!UNSAFE_IS_ZERO(Pike_sp-1)) { pos=calc3(this,data,len,pos,flags|CPP_REALLY_NO_OUTPUT); }else{ pop_stack(); pos=calc3(this,data,len,pos,flags); } } else pos=calc3(this,data,len,pos,flags); } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc1(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t pos, int flags) { CALC_DUMPPOS("before calc1"); pos=calc2(this,data,len,pos,flags); SKIPWHITE(); if(GOBBLE('?')) { int select = -1; if(OUTP()) { check_destructed(Pike_sp-1); select = (UNSAFE_IS_ZERO(Pike_sp-1)?0:1); pop_stack(); } pos=calc1(this,data,len,pos,(select == 1? flags:(flags|CPP_REALLY_NO_OUTPUT))); if(!GOBBLE(':')) cpp_error(this, "Colon expected."); pos=calc1(this,data,len,pos,(select == 0? flags:(flags|CPP_REALLY_NO_OUTPUT))); } return pos; }
6e2bb52018-01-05Henrik Grubbström (Grubba) static ptrdiff_t calc(struct CPP_struct *this, PCHARP data, ptrdiff_t len,
74966e2014-05-12Per Hedbor  ptrdiff_t tmp, int flags) { JMP_BUF recovery; ptrdiff_t pos; CALC_DUMPPOS("Calculating"); if (SETJMP(recovery)) { cpp_handle_exception (this, "Error evaluating expression."); pos=tmp; FIND_EOL(); push_int(0); }else{ pos=calc1(this,data,len,tmp,flags); check_destructed(Pike_sp-1); } UNSETJMP(recovery); CALC_DUMPPOS("Done"); return pos; }
00c4a42016-09-25Henrik Grubbström (Grubba) static void string_builder_append_cpp_quoted_pcharp(struct string_builder *s, PCHARP a, size_t l) { size_t e; for(e=0; e<l;) {
a550902016-12-17Martin Nilsson  if (wide_isspace(INDEX_PCHARP(a, e)) ||
00c4a42016-09-25Henrik Grubbström (Grubba)  INDEX_PCHARP(a, e)=='"' || INDEX_PCHARP(a, e)=='\\') { if (e) { string_builder_append(s, a, e); } if (INDEX_PCHARP(a, e) == '"' || INDEX_PCHARP(a, e)=='\\') { /* String or quote. */ string_builder_putchar(s, '\\'); string_builder_putchar(s, INDEX_PCHARP(a, e)); if (INDEX_PCHARP(a, e) == '"') { for (e++; e < l; e++) { if (INDEX_PCHARP(a, e) == '"') { e++; break; } string_builder_putchar(s, INDEX_PCHARP(a, e)); if (INDEX_PCHARP(a, e) == '\\') { string_builder_putchar(s, '\\'); e++; if (INDEX_PCHARP(a, e) == '\\' || INDEX_PCHARP(a, e) == '"') { string_builder_putchar(s, '\\'); } string_builder_putchar(s, INDEX_PCHARP(a, e)); } } string_builder_putchar(s, '\\'); string_builder_putchar(s, '"'); } } else { /* White space. */
a550902016-12-17Martin Nilsson  while ((e < l) && wide_isspace(INDEX_PCHARP(a, e))) {
00c4a42016-09-25Henrik Grubbström (Grubba)  e++; } if (e != l) { string_builder_putchar(s, ' '); } } INC_PCHARP(a, e); l -= e; e = 0; } else { e++; } } if (l) { string_builder_append(s,a,l); } }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void apply_define(struct CPP_struct *this,
e0b7772016-09-21Henrik Grubbström (Grubba)  struct define_struct *d, struct define_argument *arguments,
e19aca2018-01-06Henrik Grubbström (Grubba)  short flags,
e0b7772016-09-21Henrik Grubbström (Grubba)  struct pike_string *charset) { struct string_builder tmp; init_string_builder(&tmp, 0); if(d->magic) { int i; struct pike_string *a = NULL; if (d->args > 0) { a = make_shared_binary_pcharp(arguments[0].arg, arguments[0].len); } d->magic(this, d, a, &tmp); /* FIXME: Popping the stack should be moved to * the magic functions. */ if (a) free_string(a); }else{ struct array *parts = d->parts; int e; for(e = 0; e < parts->size; e++) { PCHARP a; ptrdiff_t l; switch(TYPEOF(parts->item[e])) { case PIKE_T_INT: { int argument = parts->item[e].u.integer; if((argument & DEF_ARG_MASK) >= d->args) { cpp_error(this, "Macro not expanded correctly."); continue; } a = arguments[argument & DEF_ARG_MASK].arg; l = arguments[argument & DEF_ARG_MASK].len; if (argument & DEF_ARG_NEED_COMMA && !(d->varargs && d->args-1 == (argument & DEF_ARG_MASK) && l == 0)) { string_builder_putchar(&tmp, ','); string_builder_putchar(&tmp, ' '); } if(!(argument & DEF_ARG_NOPRESPACE)) string_builder_putchar(&tmp, ' '); if(argument & DEF_ARG_STRINGIFY) { /* NOTE: At entry a[0] is non white-space. */ string_builder_putchar(&tmp, '"');
00c4a42016-09-25Henrik Grubbström (Grubba)  string_builder_append_cpp_quoted_pcharp(&tmp, a, l);
e0b7772016-09-21Henrik Grubbström (Grubba)  string_builder_putchar(&tmp, '"'); }else{
a596ec2016-09-24Henrik Grubbström (Grubba)  /* Strip leading and trailing white-space. */
a550902016-12-17Martin Nilsson  while(l && wide_isspace(EXTRACT_PCHARP(a)))
a596ec2016-09-24Henrik Grubbström (Grubba)  INC_PCHARP(a,1),l--;
a550902016-12-17Martin Nilsson  while(l && wide_isspace(INDEX_PCHARP(a,l-1)))
a596ec2016-09-24Henrik Grubbström (Grubba)  l--;
e0b7772016-09-21Henrik Grubbström (Grubba)  if(argument & (DEF_ARG_NOPRESPACE | DEF_ARG_NOPOSTSPACE)) { string_builder_append( &tmp, a, l ); }else{ struct string_builder save; INT_TYPE line = this->current_line; /* FIXME: Shouldn't we save current_file too? */ save=this->buf; this->buf=tmp; d->flags = CPP_MACRO_IN_USE; low_cpp(this, a, l, flags & ~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE),
e19aca2018-01-06Henrik Grubbström (Grubba)  charset);
e0b7772016-09-21Henrik Grubbström (Grubba)  d->flags = flags; tmp=this->buf; this->buf=save; this->current_line=line; } } if(!(argument & DEF_ARG_NOPOSTSPACE)) string_builder_putchar(&tmp, ' '); } break; case PIKE_T_STRING: string_builder_shared_strcat(&tmp, parts->item[e].u.string); break; } } } /* Remove any newlines from the completed expression. */ if (!(d->magic == insert_callback_define || d->magic == insert_callback_define_no_args || d->magic == insert_pragma)) { int e; for(e=0; e< (ptrdiff_t)tmp.s->len; e++) if(index_shared_string(tmp.s,e)=='\n') SET_INDEX_CHARP(tmp.s->str,e,tmp.s->size_shift,' '); } d->flags = CPP_MACRO_DISABLED; /* FIXME: Ought to add a ref to d here. */ string_builder_putchar(&tmp, 0); tmp.s->len--; low_cpp(this, MKPCHARP_STR(tmp.s),tmp.s->len, flags & ~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE),
e19aca2018-01-06Henrik Grubbström (Grubba)  charset);
e0b7772016-09-21Henrik Grubbström (Grubba)  d->flags = flags; /* FIXME: Ought to free the ref to d here. */ free_string_builder(&tmp); }
e7bcc52018-01-11Henrik Grubbström (Grubba) /* * Preprocessor template. *
6710342018-02-21Henrik Grubbström (Grubba)  * NB: There are two basic cases where this function is called: * * * Either when switching to a new input data string * (eg macro expansion or #include). The result of * this is added to the current buffer. * * * Or parsing to the end of the line after a directive. * The result of this is added to a temporary buffer.
e7bcc52018-01-11Henrik Grubbström (Grubba)  */ static ptrdiff_t low_cpp(struct CPP_struct *this, PCHARP data, ptrdiff_t len, int flags, struct pike_string *charset) { ptrdiff_t pos, tmp, e; int include_mode; INT_TYPE first_line = this->current_line; /* FIXME: What about this->current_file? */ for(pos=0; pos<len;) { ptrdiff_t old_pos = pos; int c; /* fprintf(stderr,"%c",DATA(pos)); fflush(stderr); */ switch(c = DATA(pos++)) { case '\n': if(flags & CPP_END_AT_NEWLINE) return pos-1; /* fprintf(stderr,"CURRENT LINE: %d\n",this->current_line); */ this->current_line++; PUTNL(); goto do_skipwhite; case 0x1b: case 0x9b: /* ESC or CSI */ /* Assume ANSI/DEC escape sequence. * Format supported: * <ESC>[\040-\077]+[\100-\177] * or * <CSI>[\040-\077]*[\100-\177] */ /* FIXME: This place is far from enough to make these things * behave as whitespace. /mast */ while ((tmp = DATA(pos)) && (tmp == ((tmp & 0x1f)|0x20))) { pos++; } if (tmp == ((tmp & 0x3f)|0x40)) { pos++; } else { /* FIXME: Warning here? */ } PUTC(' '); break; case '\t': case ' ': case '\r': PUTC(' '); do_skipwhite: while( wide_isspace(c=DATA(pos)) && c != '\n' && c != '\r' ) pos++; break; /* Minor optimization */ case '<': case '=': case '>': if(DATA(pos)==c && DATA(pos+1)==c && DATA(pos+2)==c && DATA(pos+3)==c && DATA(pos+4)==c && DATA(pos+5)==c) { cpp_error(this, "Merge conflict detected."); PUTC(c); do { PUTC(c); } while (DATA(++pos) == c); continue; }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
e7bcc52018-01-11Henrik Grubbström (Grubba)  case '!': case '@': case '$': case '%': case '^': case '&': case '*': case '(': case ')': case '-': case '+': case '{': case '}': case ':': case '?': case '`': case ';': case ',': case '.': case '~': case '[': case ']': case '|': PUTC(DATA(pos-1)); break; case '\\': if(DATA(pos)=='\n') { pos++; this->current_line++; PUTNL(); goto do_skipwhite; } else if ((DATA(pos) == '\r') && (DATA(pos+1) == '\n')) { pos += 2; this->current_line++; PUTNL(); goto do_skipwhite; } /* Fall through - identifiers might begin with \uxxxx. */ default: if(OUTP()) { struct pike_string *s; struct define_struct *d = NULL; pos--; s = GOBBLE_IDENTIFIER(); if (!s) { PUTC (DATA(pos++)); break; } if(flags & CPP_DO_IF && s == defined_str) { /* NOTE: defined() must be handled here, since its argument * must not be macro expanded. */ d = defined_macro; }else{ d=FIND_DEFINE(s); } if(d && !(d->flags & CPP_MACRO_DISABLED)) { int arg=0; INT_TYPE start_line = this->current_line; struct string_builder tmp; struct define_argument arguments[ MAX_ARGS]; short flags = d->flags; if (d == defined_macro) { free_string (s); s = NULL; } if(d->args>=0) { SKIPWHITE(); if(!GOBBLE('(')) { if (s) { string_builder_shared_strcat(&this->buf,s); free_string(s); } /* Restore the post-whitespace. */ string_builder_putchar(&this->buf, ' '); break; } for(arg=0;arg<d->args;arg++) { if(arg && DATA(pos)==',') { pos++; SKIPWHITE(); }else{ SKIPWHITE(); if(DATA(pos)==')') { if((d->varargs && arg + 1 == d->args) || (!arg && (d->args == 1))) { /* Allow varargs to be left out. * * Allow a single argument to be left out. */ arguments[arg].arg = ADD_PCHARP(data,pos); arguments[arg].len=0; continue; }else{ cpp_error_sprintf(this, "Too few arguments to macro %S, expected %d.", d->name, d->args); break; } } } arguments[arg].arg = ADD_PCHARP(data,pos); while(1) { if(pos+1>len) { INT_TYPE save_line = this->current_line; this->current_line = start_line; cpp_error(this, "End of file in macro call."); this->current_line = save_line; break; } switch(DATA(pos++)) { case '\n': this->current_line++; PUTNL();
3595ea2018-02-12Marcus Comstedt  /* FALLTHRU */
e7bcc52018-01-11Henrik Grubbström (Grubba)  default: continue; case '"': /* Note: Strings may contain \-escaped newlines. * They must be removed on insertion to * avoid being counted twice. */ if(DATA(pos-2)!='#') { FIND_END_OF_STRING(CPP_END_AT_NEWLINE); }else{ FIND_END_OF_STRING(0); /* Newlines allowed */ } continue; case '\'': FIND_END_OF_CHAR(); continue; case '/': if (DATA(pos) == '*') { pos++; if (this->keep_comments) { SKIPCOMMENT_INC_LINES(); goto ADD_TO_BUFFER; } SKIPCOMMENT(); } else if (DATA(pos) == '/') { if (this->keep_comments) { FIND_EOL_PRETEND(); goto ADD_TO_BUFFER; } FIND_EOL(); } continue; case '(': pos=find_end_parenthesis(this, data, len, pos); continue; case '{': pos=find_end_brace(this, data, len, pos); continue; case ',': if(d->varargs && arg+1 == d->args) continue;
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
e7bcc52018-01-11Henrik Grubbström (Grubba)  case ')': pos--; break; } break; } arguments[arg].len = SUBTRACT_PCHARP(ADD_PCHARP(data,pos),arguments[arg].arg); } SKIPWHITE(); if(!GOBBLE(')')) { this->current_line = start_line; cpp_error_sprintf(this, "Missing ) in the macro %S.", d->name); } } if(d->args >= 0 && arg != d->args) cpp_error(this, "Wrong number of arguments to macro."); /* NB: If there have been errors in the loop above, arguments may * remain (partially) uninitialized. */ if (!this->compile_errors) { apply_define(this, d, arguments, flags, charset); } }else{ if (OUTP()) string_builder_shared_strcat (&this->buf, s); } if (s) { free_string(s); } } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': PUTC(DATA(pos-1)); while(DATA(pos)>='0' && DATA(pos)<='9') PUTC(DATA(pos++)); break; case '"': FIXSTRING(this->buf,OUTP()); break; case '\'': tmp=pos-1; FIND_END_OF_CHAR(); if(OUTP()) string_builder_append( &this->buf, ADD_PCHARP(data, tmp), pos - tmp); else for (; tmp < pos; tmp++) if (DATA(tmp) == '\n') string_builder_putchar (&this->buf, '\n'); break; case '/': if(DATA(pos)=='/') { if (this->keep_comments) { FIND_EOL_PRETEND(); goto ADD_TO_BUFFER; } FIND_EOL(); break; } if(DATA(pos)=='*') { if (this->keep_comments) { SKIPCOMMENT_INC_LINES(); goto ADD_TO_BUFFER; } else { PUTC(' '); SKIPCOMMENT(); } break; } PUTC(DATA(pos-1)); break; case '#': if(GOBBLE('!')) { FIND_EOL(); break; } SKIPSPACE(); if (!CHECK_WORD(string_recur_, NELEM(string_recur_)) && !CHECK_WORD(include_recur_, NELEM(include_recur_))) { if (this->prefix) { if( !begins_with( this->prefix->str, ADD_PCHARP(data,pos), this->prefix->len, len-pos, 0 ) || DATA(pos+this->prefix->len) != '_') { FIND_EOS(); goto ADD_TO_BUFFER; } pos += this->prefix->len + 1; } else { int i; for (i = pos; i < len; i++) { if (DATA(i) == '_') { FIND_EOS(); goto ADD_TO_BUFFER; } else if (!wide_isidchar(DATA(i))) break; } } } switch(DATA(pos)) { case 'l': { if(GOBBLE_WORD(line_)) { /* FIXME: Why not use SKIPSPACE()? */ /* Because SKIPSPACE skips newlines? - Hubbe */ /* Actually, no - Per */ while(DATA(pos)==' ' || DATA(pos)=='\t') pos++; }else{ goto unknown_preprocessor_directive; } }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
e7bcc52018-01-11Henrik Grubbström (Grubba)  case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { INT_TYPE new_lineno; PCHARP foo = ADD_PCHARP(data,pos); new_lineno=STRTOL_PCHARP(foo, &foo, 10)-1; if(OUTP()) { string_builder_binary_strcat(&this->buf, "#line ", 6); string_builder_append(&this->buf, ADD_PCHARP(data,pos), SUBTRACT_PCHARP(foo,ADD_PCHARP(data,pos))); } pos = SUBTRACT_PCHARP(foo,data); SKIPSPACE(); if(DATA(pos)=='"') { struct string_builder nf; init_string_builder(&nf, 0); READSTRING(nf); if(OUTP()) { free_string(this->current_file); this->current_file = finish_string_builder(&nf); string_builder_putchar(&this->buf, ' '); PUSH_STRING_SHIFT (this->current_file->str, this->current_file->len, this->current_file->size_shift, &this->buf); }else{ free_string_builder(&nf); } } if (OUTP()) this->current_line = new_lineno; FIND_EOL(); break; } case '"': { struct string_builder nf; char end; init_string_builder(&nf, 0); READSTRING2(nf); goto stringout; case '(': end = ')'; goto litstring; case '[': end = ']'; goto litstring; case '{': end = '}'; litstring: init_string_builder(&nf, 0); READSTRING3(nf,end); stringout: if(OUTP()) PUSH_STRING_SHIFT(nf.s->str, nf.s->len,nf.s->size_shift, &this->buf); free_string_builder(&nf); break; } case 's': { if(GOBBLE_WORD(string_)) { include_mode = 1; goto do_include; } if(GOBBLE_WORD(string_recur_)) { include_mode = 3; goto do_include; } } goto unknown_preprocessor_directive; case 'i': /* include, if, ifdef */ { int recur = 0; if(GOBBLE_WORD(include_) || (recur = GOBBLE_WORD(include_recur_))) { if (recur) { include_mode = 2; } else { include_mode = 0; } do_include: { struct svalue *save_sp=Pike_sp; SKIPSPACE(); check_stack(3); switch(DATA(pos++)) { case '"': { struct string_builder nf; init_string_builder(&nf, 0); pos--; READSTRING(nf); push_string(finish_string_builder(&nf)); /* In Pike 7.7 and later filenames belonging to Pike * are assumed to be encoded according to UTF-8. */ f_string_to_utf8(1); ref_push_string(this->current_file); push_int(1); break; } case '<': { ptrdiff_t tmp = pos; while(DATA(pos)!='>') { if(DATA(pos)=='\n') { cpp_error(this, "Expecting '>' in include."); break; } pos++; } push_string(make_shared_binary_pcharp(ADD_PCHARP(data,tmp), pos-tmp)); /* In Pike 7.7 and later filenames belonging to Pike * are assumed to be encoded according to UTF-8. */ f_string_to_utf8(1); ref_push_string(this->current_file); pos++; push_int(0); break; } default: if (include_mode & 2) { /* Macro expanding didn't help... */ cpp_error(this, "Expected file to include."); break; } else { /* Try macro expanding (Bug 2440). */ struct string_builder save = this->buf, tmp; INT_TYPE save_line = this->current_line; init_string_builder(&this->buf, 0); /* Prefix the buffer with the corresponding *_recur * directive, to avoid infinite loops. */ if (include_mode & 1) { string_builder_strcat(&this->buf, "#string_recur "); } else { string_builder_strcat(&this->buf, "#include_recur "); } pos--; pos += low_cpp(this, ADD_PCHARP(data,pos), len - pos, CPP_END_AT_NEWLINE, charset); string_builder_putchar(&this->buf, '\n'); tmp = this->buf; this->buf = save; /* We now have a #include-recur or #string-recur directive * in tmp. Preprocess it. */ /* We're processing the line twice. */ this->current_line = save_line; low_cpp(this, MKPCHARP_STR(tmp.s), tmp.s->len, flags, charset); free_string_builder(&tmp); this->current_line = save_line; string_builder_sprintf(&this->buf, "\n#line %ld ", (long)save_line); PUSH_STRING_SHIFT(this->current_file->str, this->current_file->len, this->current_file->size_shift, &this->buf); string_builder_putchar(&this->buf, '\n'); } break; } if(Pike_sp==save_sp) { break; } if(OUTP()) { struct pike_string *new_file; if (!safe_apply_handler ("handle_include", this->handler, this->compat_handler, 3, BIT_STRING) || !(new_file=Pike_sp[-1].u.string) ) { cpp_handle_exception (this, "Couldn't find include file."); pop_n_elems(Pike_sp-save_sp); break; } ref_push_string(new_file); if (!safe_apply_handler ("read_include", this->handler, this->compat_handler, 1, BIT_STRING|BIT_INT)) { cpp_handle_exception (this, "Couldn't read include file."); pop_n_elems(Pike_sp-save_sp); break; } else if (TYPEOF(Pike_sp[-1]) == PIKE_T_INT) { cpp_error_sprintf(this, "Couldn't read include file \"%S\".", new_file); pop_n_elems(Pike_sp-save_sp); break; } { struct pike_string *save_current_file; INT_TYPE save_current_line; save_current_file=this->current_file; save_current_line=this->current_line; copy_shared_string(this->current_file,new_file); this->current_line=1; string_builder_binary_strcat(&this->buf, "#line 1 ", 8); PUSH_STRING_SHIFT(new_file->str, new_file->len, new_file->size_shift, &this->buf); string_builder_putchar(&this->buf, '\n'); if(include_mode & 1) { /* #string */ struct pike_string *str = Pike_sp[-1].u.string; PUSH_STRING_SHIFT(str->str, str->len, str->size_shift, &this->buf); }else{ /* #include */ if (this->auto_convert) { struct pike_string *new_str = recode_string(this, Pike_sp[-1].u.string); free_string(Pike_sp[-1].u.string); Pike_sp[-1].u.string = new_str; } else if (charset) { ref_push_string(charset); if (!safe_apply_handler ("decode_charset", this->handler, this->compat_handler, 2, BIT_STRING)) { cpp_handle_exception (this, "Charset decoding failed for included file."); pop_n_elems(Pike_sp - save_sp); break; } } if (Pike_sp[-1].u.string->size_shift) { /* Get rid of any byte order marks (0xfeff) */ struct pike_string *new_str = filter_bom(Pike_sp[-1].u.string); free_string(Pike_sp[-1].u.string); Pike_sp[-1].u.string = new_str; } low_cpp(this, MKPCHARP_STR(Pike_sp[-1].u.string), Pike_sp[-1].u.string->len, flags&~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE), charset); } free_string(this->current_file); this->current_file=save_current_file; this->current_line=save_current_line;
75942b2018-01-12Martin Nilsson  string_builder_sprintf(&this->buf, "\n#line %ld ", (long)this->current_line);
e7bcc52018-01-11Henrik Grubbström (Grubba)  PUSH_STRING_SHIFT(this->current_file->str, this->current_file->len, this->current_file->size_shift, &this->buf); string_builder_putchar(&this->buf, '\n'); if ((include_mode & 2) && (pos < len)) { /* NOTE: The rest of the current buffer has already been * expanded once. */ string_builder_append(&this->buf, ADD_PCHARP(data, pos), len - pos); pos = len; } } } pop_n_elems(Pike_sp-save_sp); break; } } if(GOBBLE_WORD(if_)) { struct string_builder save, tmp; INT32 nflags = 0; if(!OUTP()) nflags = CPP_REALLY_NO_OUTPUT; save=this->buf; init_string_builder(&this->buf, 0); pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, nflags | CPP_END_AT_NEWLINE | CPP_DO_IF, charset); tmp=this->buf; this->buf=save; string_builder_putchar(&tmp, 0); tmp.s->len--; if (!nflags) { calc(this,MKPCHARP_STR(tmp.s),tmp.s->len,0,0); if(SAFE_IS_ZERO(Pike_sp-1)) nflags|=CPP_NO_OUTPUT; pop_stack(); } free_string_builder(&tmp); pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, nflags | CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF, charset); break; } if(GOBBLE_WORD(ifdef_)) { INT32 nflags; struct pike_string *s; SKIPSPACE(); s = GOBBLE_IDENTIFIER(); if(!s) cpp_error(this, "#ifdef what?"); nflags = CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF | CPP_NO_OUTPUT; if(!OUTP()) nflags|=CPP_REALLY_NO_OUTPUT; if (s) { if(FIND_DEFINE(s)) nflags&=~CPP_NO_OUTPUT; free_string (s); } pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, nflags, charset); break; } if(GOBBLE_WORD(ifndef_)) { INT32 nflags; struct pike_string *s; SKIPSPACE(); s = GOBBLE_IDENTIFIER(); if(!s) cpp_error(this, "#ifndef what?"); nflags=CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF; if(!OUTP()) nflags|=CPP_REALLY_NO_OUTPUT; if (s) { if(FIND_DEFINE(s)) nflags|=CPP_NO_OUTPUT; free_string (s); } pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, nflags, charset); break; } goto unknown_preprocessor_directive; } case 'e': /* endif, else, elif, error */ { if(GOBBLE_WORD(endif_)) { if(!(flags & CPP_EXPECT_ENDIF)) cpp_error(this, "Unmatched #endif."); return pos; } if(GOBBLE_WORD(else_)) { if(!(flags & CPP_EXPECT_ELSE)) cpp_error(this, "Unmatched #else."); flags&=~CPP_EXPECT_ELSE; flags|=CPP_EXPECT_ENDIF;
1fc5a92018-01-17Henrik Grubbström (Grubba)  flags ^= CPP_NO_OUTPUT;
e7bcc52018-01-11Henrik Grubbström (Grubba)  break; } if(GOBBLE_WORD(elif_) || GOBBLE_WORD(elseif_)) { if(!(flags & CPP_EXPECT_ELSE)) cpp_error(this, "Unmatched #elif."); flags|=CPP_EXPECT_ENDIF; if((flags & (CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT)) == CPP_NO_OUTPUT) { struct string_builder save,tmp; save=this->buf; init_string_builder(&this->buf, 0); pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, CPP_END_AT_NEWLINE | CPP_DO_IF, charset); tmp=this->buf; this->buf=save; string_builder_putchar(&tmp, 0); tmp.s->len--; calc(this,MKPCHARP_STR(tmp.s),tmp.s->len,0,0); free_string_builder(&tmp); if(!SAFE_IS_ZERO(Pike_sp-1)) flags&=~CPP_NO_OUTPUT; pop_stack(); } else { FIND_EOL(); flags |= CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT; } break; } } goto unknown_preprocessor_directive; case 'd': /* define */ { if(GOBBLE_WORD(define_)) { struct string_builder str; INT32 argno=-1; ptrdiff_t tmp3; struct pike_string *def_name; struct define_struct *def; struct svalue *partbase,*argbase=Pike_sp; int varargs=0; SKIPSPACE(); def_name = GOBBLE_IDENTIFIER(); if(!def_name) { cpp_error(this, "Define what?"); FIND_EOL(); break; } if(GOBBLE('(')) { argno=0; SKIPWHITE(); while(DATA(pos)!=')') { struct pike_string *arg_name; if(argno) { if(!GOBBLE(',')) cpp_error(this, "Expecting comma in macro definition."); SKIPWHITE(); } if(varargs) cpp_error(this,"Expected ) after ..."); arg_name = GOBBLE_IDENTIFIER(); if(!arg_name) { cpp_error(this, "Expected argument for macro."); break; } check_stack(1); push_string(arg_name); SKIPWHITE(); argno++; if(argno>=MAX_ARGS) { cpp_error(this, "Too many arguments in macro definition."); pop_stack(); argno--; } if(DATA(pos)=='.' && DATA(pos+1)=='.' && DATA(pos+2)=='.') { varargs=1; pos+=3; SKIPWHITE(); } } if(!GOBBLE(')')) cpp_error(this, "Missing ) in macro definition."); } SKIPSPACE(); partbase=Pike_sp; init_string_builder(&str, 0); while(1) { INT32 extra=0; ptrdiff_t old_pos = pos; switch(DATA(pos++)) { case '/': if(DATA(pos)=='/') { if (this->keep_comments) { FIND_EOL_PRETEND(); string_builder_append( &str, ADD_PCHARP(data, old_pos), pos-old_pos ); continue; } string_builder_putchar(&str, ' '); FIND_EOL(); continue; } if(DATA(pos)=='*') { if (this->keep_comments) { SKIPCOMMENT_INC_LINES(); string_builder_append( &str, ADD_PCHARP(data, old_pos), pos-old_pos ); continue; } PUTC(' '); SKIPCOMMENT(); continue; } string_builder_putchar(&str, '/'); continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': string_builder_putchar(&str, DATA(pos-1)); while(DATA(pos)>='0' && DATA(pos)<='9') string_builder_putchar(&str, DATA(pos++)); continue; case '\\': if(GOBBLE('\n')) { this->current_line++; PUTNL(); continue; } if (DATA(pos) == '\r' && DATA(pos+1) == '\n') { pos += 2; this->current_line++; PUTNL(); continue; } /* Identifiers might start with \uxxxx, so try to parse * an identifier now. */ goto gobble_identifier_in_define; case ',': { int oldpos; oldpos = pos; SKIPSPACE_PRETEND(); if (DATA(pos) == '#' && DATA(pos+1) == '#') { extra|= DEF_ARG_NEED_COMMA; pos += 2; goto concat_identifier; } else { pos = oldpos; goto gobble_identifier_in_define; } } case '#': if(GOBBLE('#')) { extra= (extra & DEF_ARG_NEED_COMMA) | DEF_ARG_NOPRESPACE; while(str.s->len && wide_isspace(index_shared_string(str.s,str.s->len-1))) str.s->len--; concat_identifier: if(!str.s->len && Pike_sp-partbase>1) { #ifdef PIKE_DEBUG if(TYPEOF(Pike_sp[-1]) != PIKE_T_INT) Pike_fatal("Internal error in CPP\n"); #endif Pike_sp[-1].u.integer|=DEF_ARG_NOPOSTSPACE; } }else{ extra=DEF_ARG_STRINGIFY; } SKIPSPACE(); pos++; /* fall through */ gobble_identifier_in_define: default: { struct pike_string *s; pos--; s = GOBBLE_IDENTIFIER(); if (s) { tmp3=pos-1; if(argno>0) { if (s->refs > 1) { for(e=0;e<argno;e++) { if(argbase[e].u.string == s) { check_stack(2); push_string(finish_string_builder(&str)); init_string_builder(&str, 0); push_int(e | extra); extra=0; break; } } if(e!=argno) { free_string (s); continue; } } } string_builder_shared_strcat (&str, s); free_string (s); }else{ string_builder_putchar(&str, DATA(pos++)); } extra=0; continue; } case '"': FIXSTRING(str, 1); continue; case '\'': tmp3=pos-1; FIND_END_OF_CHAR(); string_builder_append(&str, ADD_PCHARP(data, tmp3), pos - tmp3); continue; case '\n': PUTNL(); this->current_line++; /* Fallthrough */ case 0: break; } push_string(finish_string_builder(&str)); break; } if(OUTP()) { f_aggregate(Pike_sp - partbase); def = alloc_empty_define(def_name); def->args=argno; def->varargs=varargs; add_ref(def->parts = Pike_sp[-2].u.array); { struct define_struct *d; if ((d = FIND_DEFINE(def->name)) && (d->flags & (CPP_MACRO_IN_USE | CPP_MACRO_DISABLED))) { cpp_error(this, "Illegal to redefine a macro during its expansion."); } else { mapping_string_insert(this->defines, def->name, Pike_sp-1); } } } free_string (def_name); pop_n_elems(Pike_sp-argbase); break; } goto unknown_preprocessor_directive; } case 'u': /* undefine */ { /* NOTE: Reuses undefine_ for undef_ */ if(GOBBLE_WORD(undefine_) || GOBBLE_WORD(undef_)) { struct pike_string *s; SKIPSPACE(); s = GOBBLE_IDENTIFIER(); if(!s) { cpp_error(this, "Undefine what?"); break; } if(OUTP()) { undefine(this,s); } free_string (s); break; } goto unknown_preprocessor_directive; } case 'c': /* charset */ { if (GOBBLE_WORD(charset_)) { ptrdiff_t p; struct pike_string *s; if (flags & (CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE)) { /* Only allowed at the top-level */ cpp_error(this, "#charset directive inside #if/#endif."); /* Skip to end of line */ while (DATA(pos) && DATA(pos) != '\n') { pos++; } break; } SKIPSPACE(); p = pos; while(DATA(pos) && !wide_isspace(DATA(pos))) { pos++; } if (pos != p) { /* The rest of the string. */ push_string( make_shared_binary_pcharp( ADD_PCHARP(data,pos), len-pos ) ); /* The charset name */ push_string( make_shared_binary_pcharp( ADD_PCHARP(data,p),pos-p)); if (!safe_apply_handler ("decode_charset", this->handler, this->compat_handler, 2, BIT_STRING)) { cpp_handle_exception (this, NULL); } else { low_cpp(this, MKPCHARP_STR(Pike_sp[-1].u.string),Pike_sp[-1].u.string->len, flags, charset); pop_stack(); } /* FIXME: Is this the correct thing to return? */ return len; } else { cpp_error(this, "What charset?"); } break; } goto unknown_preprocessor_directive; } case 'p': /* pragma */ { if(GOBBLE_WORD(pike_)) { if(OUTP()) { int major, minor; ptrdiff_t tmp; PCHARP ptr; string_builder_strcat(&this->buf, "#pike"); tmp= this->buf.s->len; pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, CPP_END_AT_NEWLINE | CPP_DO_IF, charset); ptr=MKPCHARP_STR(this->buf.s); INC_PCHARP(ptr, tmp); /* Zero terminate the buffer contents here to make sure * that STRTOL_PCHARP does not read beyond the end of the * buffer */ string_builder_putchar(&this->buf, 0); this->buf.s->len--; major=STRTOL_PCHARP(ptr, &ptr, 10); if(INDEX_PCHARP(ptr,0) == '.') { INC_PCHARP(ptr, 1); minor=STRTOL_PCHARP(ptr, &ptr, 10); cpp_change_compat(this, major, minor); }else{ cpp_error(this, "Missing '.' in #pike."); this->compat_minor=0; } } else FIND_EOL(); break; } }
3595ea2018-02-12Marcus Comstedt  /* FALLTHRU */
e7bcc52018-01-11Henrik Grubbström (Grubba)  case 'r': /* require */ { if(GOBBLE_WORD(require_)) { struct string_builder save, tmp; save = this->buf; init_string_builder(&this->buf, 0); pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, CPP_END_AT_NEWLINE | CPP_DO_IF, charset); tmp = this->buf; this->buf = save; string_builder_putchar(&tmp, 0); tmp.s->len--; calc(this,MKPCHARP_STR(tmp.s),tmp.s->len,0,0); if(SAFE_IS_ZERO(Pike_sp-1)) this->dependencies_fail=1; pop_stack(); free_string_builder(&tmp); if(this->dependencies_fail) return pos; break; } goto unknown_preprocessor_directive; } default:
86bc4e2018-01-12Henrik Grubbström (Grubba)  unknown_preprocessor_directive: { struct pike_string *directive = GOBBLE_IDENTIFIER();
87fa592018-01-14Henrik Grubbström (Grubba)  if (directive) { struct svalue *fun = NULL; struct svalue sv; struct pike_string *directive_string = add_shared_strings(MK_STRING("directive_"), directive); int id = find_shared_string_identifier(directive_string, Pike_fp->current_object->prog); free_string(directive_string); if (id >= 0) { /* NB: This svalue holds no reference! */ SET_SVAL(sv, PIKE_T_FUNCTION, id, object, Pike_fp->current_object); fun = &sv; } if(!fun && this->directives) { /* Try a mapping lookup instead. */ fun = low_mapping_string_lookup(this->directives, directive); }
86bc4e2018-01-12Henrik Grubbström (Grubba)  if (fun) { ptrdiff_t foo;
8f942d2018-02-26Martin Nilsson  free_string(directive);
86bc4e2018-01-12Henrik Grubbström (Grubba) 
e0c30f2018-02-26Martin Nilsson  SKIPSPACE();
86bc4e2018-01-12Henrik Grubbström (Grubba)  foo = pos; FIND_EOL(); push_int(flags); push_string(make_shared_binary_pcharp(ADD_PCHARP(data,foo), pos-foo)); safe_apply_svalue(fun, 2, 1); if ((TYPEOF(Pike_sp[-1]) == PIKE_T_STRING) && Pike_sp[-1].u.string->len) { /* We need to recurse. */ low_cpp(this, MKPCHARP_STR(Pike_sp[-1].u.string), Pike_sp[-1].u.string->len, flags, charset); } pop_stack(); break; }
ee311a2018-02-26Martin Nilsson  } if(!OUTP() && !this->picky_cpp)
8f942d2018-02-26Martin Nilsson  { if(directive) free_string(directive);
ee311a2018-02-26Martin Nilsson  break;
8f942d2018-02-26Martin Nilsson  }
ee311a2018-02-26Martin Nilsson  if (directive) { cpp_error_sprintf(this, "Unknown preprocessor directive %S.", directive); free_string(directive); } else { cpp_error_sprintf(this, "Invalid preprocessor directive character at %d: '%c'.", pos, DATA(pos)); } }
e7bcc52018-01-11Henrik Grubbström (Grubba)  } } continue; ADD_TO_BUFFER: // keep line string_builder_append(&this->buf, ADD_PCHARP(data,old_pos), pos-old_pos); } if(flags & CPP_EXPECT_ENDIF) { INT_TYPE saved_line = this->current_line; this->current_line = first_line; cpp_error(this, "End of file while searching for #endif."); this->current_line = saved_line; } return pos; }
7bfa4f1999-03-09Henrik Grubbström (Grubba) 
6710342018-02-21Henrik Grubbström (Grubba)  PIKEFUN void low_cpp(string data, int flags)
6ae1862018-01-13Henrik Grubbström (Grubba)  { low_cpp(THIS, MKPCHARP_STR(data), data->len, flags, THIS->charset); }
6710342018-02-21Henrik Grubbström (Grubba)  PIKEFUN string cpp(string data, int flags) { struct CPP_struct *this = THIS; struct string_builder save_buf = this->buf; struct pike_string *save_file = this->current_file; INT_TYPE save_line = this->current_line; if (save_file) add_ref(save_file); init_string_builder(&this->buf, 0); low_cpp(this, MKPCHARP_STR(data), data->len, flags, THIS->charset); push_string(finish_string_builder(&this->buf)); this->buf = save_buf; if (this->current_file) free_string(this->current_file); this->current_file = save_file; this->current_line = save_line; }
7bfa4f1999-03-09Henrik Grubbström (Grubba) /*** Magic defines ***/
4fa6542012-03-24Henrik Grubbström (Grubba)  /*! @decl constant __LINE__ *! *! This define contains the current line number, represented as an *! integer, in the source file. */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_line(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
7bfa4f1999-03-09Henrik Grubbström (Grubba)  struct string_builder *tmp) {
c060b52004-11-14Henrik Grubbström (Grubba)  string_builder_sprintf(tmp, " %ld ", (long)this->current_line);
7bfa4f1999-03-09Henrik Grubbström (Grubba) }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @decl constant __FILE__ *! *! This define contains the file path and name of the source file. */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_file_as_string(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
7bfa4f1999-03-09Henrik Grubbström (Grubba)  struct string_builder *tmp) { PUSH_STRING_SHIFT(this->current_file->str, this->current_file->len, this->current_file->size_shift, tmp); }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @decl constant __DIR__ *! *! This define contains the directory path of the source file. */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_dir_as_string(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
15107c2008-06-12Martin Nilsson  struct string_builder *tmp) {
d85cc32008-06-13Henrik Grubbström (Grubba)  ref_push_string(this->current_file);
03b9902009-03-08Henrik Grubbström (Grubba)  /* FIXME: This isn't safe if the master hasn't been compiled yet. */
89b83e2008-06-29Marcus Comstedt  SAFE_APPLY_MASTER("dirname",1);
15107c2008-06-12Martin Nilsson  PUSH_STRING_SHIFT(Pike_sp[-1].u.string->str, Pike_sp[-1].u.string->len, Pike_sp[-1].u.string->size_shift, tmp); pop_stack(); }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @decl constant __TIME__ *! *! This define contains the current time at the time of compilation, *! e.g. "12:20:51". */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_time_as_string(struct CPP_struct *UNUSED(this),
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
7bfa4f1999-03-09Henrik Grubbström (Grubba)  struct string_builder *tmp) { /* FIXME: Is this code safe? */ time_t tmp2; char *buf; time(&tmp2); buf=ctime(&tmp2);
01a9572000-02-03Henrik Grubbström (Grubba)  PUSH_STRING0((p_wchar0 *)buf+11, 8, tmp);
7bfa4f1999-03-09Henrik Grubbström (Grubba) }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @decl constant __DATE__ *! *! This define contains the current date at the time of compilation, *! e.g. "Jul 28 2001". */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_date_as_string(struct CPP_struct *UNUSED(this),
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
7bfa4f1999-03-09Henrik Grubbström (Grubba)  struct string_builder *tmp) { /* FIXME: Is this code safe? */ time_t tmp2; char *buf; time(&tmp2); buf=ctime(&tmp2);
01a9572000-02-03Henrik Grubbström (Grubba)  PUSH_STRING0((p_wchar0 *)buf+4, 6, tmp);
e5fac42000-03-09Johan Sundström  PUSH_STRING0((p_wchar0 *)buf+19, 5, tmp);
7bfa4f1999-03-09Henrik Grubbström (Grubba) }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @decl constant __VERSION__ *! *! This define contains the current Pike version as a float. If *! another Pike version is emulated, this define is updated *! accordingly. *! *! @seealso *! @[__REAL_VERSION__] */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_version(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
a580e12000-09-27Fredrik Hübinette (Hubbe)  struct string_builder *tmp) {
c060b52004-11-14Henrik Grubbström (Grubba)  string_builder_sprintf(tmp, " %d.%d ", this->compat_major,
ce5d482004-11-14Martin Nilsson  this->compat_minor);
a580e12000-09-27Fredrik Hübinette (Hubbe) }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @decl constant __MINOR__ *! This define contains the minor part of the current Pike version, *! represented as an integer. If another Pike version is emulated, *! this define is updated accordingly. *! *! @seealso *! @[__REAL_MINOR__] */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_minor(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
a580e12000-09-27Fredrik Hübinette (Hubbe)  struct string_builder *tmp) {
c060b52004-11-14Henrik Grubbström (Grubba)  string_builder_sprintf(tmp, " %d ", this->compat_minor);
a580e12000-09-27Fredrik Hübinette (Hubbe) }
ce261a2014-08-26Per Hedbor /*! @decl int(1..) __COUNTER__ *! This define contains a unique counter (unless it has been expanded
6a59982016-04-27Chris Angelico  *! Int.NATIVE_MAX times) represented as an integer.
ce261a2014-08-26Per Hedbor  *! */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_counter(struct CPP_struct *UNUSED(this),
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
ce261a2014-08-26Per Hedbor  struct string_builder *tmp) { static int counter = 0; string_builder_sprintf(tmp, " %d ", ++counter); }
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @decl constant __MAJOR__ *! *! This define contains the major part of the current Pike version, *! represented as an integer. If another Pike version is emulated, *! this define is updated accordingly. *! *! @seealso *! @[__REAL_MAJOR__] */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_current_major(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
a580e12000-09-27Fredrik Hübinette (Hubbe)  struct string_builder *tmp) {
c060b52004-11-14Henrik Grubbström (Grubba)  string_builder_sprintf(tmp, " %d ", this->compat_major);
a580e12000-09-27Fredrik Hübinette (Hubbe) }
51d3f32011-12-28Henrik Grubbström (Grubba) /* _Pragma(STRING) */
4fa6542012-03-24Henrik Grubbström (Grubba) /*! @decl void _Pragma(string directive) *! *! This macro inserts the corresponding @[#pragma] @[directive] *! in the source. *! *! e.g. @expr{_Pragma("strict_types")@} is the same *! as @expr{#pragma strict_types@} . *! *! @seealso *! @[#pragma] */
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_pragma(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *UNUSED(def),
3d6a1d2016-08-21Martin Nilsson  struct pike_string *arg,
51d3f32011-12-28Henrik Grubbström (Grubba)  struct string_builder *tmp) { int i; int in_string = 0; /* Make some reasonable amount of space. */
3d6a1d2016-08-21Martin Nilsson  string_build_mkspace(tmp, arg->len + 20, arg->size_shift);
51d3f32011-12-28Henrik Grubbström (Grubba)  string_builder_strcat(tmp, "\n#pragma "); /* Destringize the argument. */
3d6a1d2016-08-21Martin Nilsson  for (i = 0; i < arg->len; i++) { p_wchar2 ch = index_shared_string(arg, i);
51d3f32011-12-28Henrik Grubbström (Grubba)  switch(ch) { case '\n': case '\r': ch = ' ';
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
51d3f32011-12-28Henrik Grubbström (Grubba)  case ' ': case '\t': if (in_string) { string_builder_putchar(tmp, ch); } break; case '\"': in_string = !in_string; break; case '\\': if (in_string) {
3d6a1d2016-08-21Martin Nilsson  ch = (++i < arg->len) ? index_shared_string(arg, i) : '\0';
51d3f32011-12-28Henrik Grubbström (Grubba)  if ((ch != '\\') && (ch != '\"')) { cpp_error(this, "Invalid \\-escape in _Pragma()."); break; } }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
51d3f32011-12-28Henrik Grubbström (Grubba)  default: if (in_string) { string_builder_putchar(tmp, ch); } else { cpp_error(this, "Invalid character outside of string."); } break; } } if (in_string) { cpp_error(this, "Unterminated string constant."); }
e82c172012-07-22Arne Goedeke  string_builder_sprintf(tmp, "\n#line %ld ", (long)this->current_line);
51d3f32011-12-28Henrik Grubbström (Grubba)  PUSH_STRING_SHIFT(this->current_file->str, this->current_file->len, this->current_file->size_shift, tmp); string_builder_putchar(tmp, '\n'); }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_callback_define(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *def,
3d6a1d2016-08-21Martin Nilsson  struct pike_string *arg,
080e3a2011-11-04Per Hedbor  struct string_builder *tmp) {
279a4f2016-09-03Henrik Grubbström (Grubba)  ref_push_string( def->name );
4431822016-08-24Henrik Grubbström (Grubba)  ref_push_string( arg );
8190042011-12-28Henrik Grubbström (Grubba)  if (safe_apply_handler( "evaluate_define", this->handler, this->compat_handler, 2, 0 ) &&
19961b2017-04-08Martin Nilsson  TYPEOF(Pike_sp[-1]) == T_STRING ) { string_builder_shared_strcat(tmp, Pike_sp[-1].u.string);
7e5b172014-04-10Per Hedbor  if( !this->prefix ){ int min;
19961b2017-04-08Martin Nilsson  check_string_range( Pike_sp[-1].u.string, 0, &min, 0 );
7e5b172014-04-10Per Hedbor  if( min < 32 ) { string_builder_sprintf(tmp, "\n#line %ld ", (long)this->current_line);
3d6a1d2016-08-21Martin Nilsson  insert_current_file_as_string( this,def,arg,tmp);
7e5b172014-04-10Per Hedbor  string_builder_putchar(tmp, '\n'); } }
75a9f62011-12-04Arne Goedeke  pop_stack(); }
080e3a2011-11-04Per Hedbor }
6e2bb52018-01-05Henrik Grubbström (Grubba) static void insert_callback_define_no_args(struct CPP_struct *this,
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *def,
3d6a1d2016-08-21Martin Nilsson  struct pike_string *UNUSED(arg),
080e3a2011-11-04Per Hedbor  struct string_builder *tmp) {
75a9f62011-12-04Arne Goedeke  struct svalue *save_sp = Pike_sp;
279a4f2016-09-03Henrik Grubbström (Grubba)  ref_push_string( def->name );
8190042011-12-28Henrik Grubbström (Grubba)  if (safe_apply_handler( "evaluate_define", this->handler, this->compat_handler, 1, 0 ) &&
19961b2017-04-08Martin Nilsson  TYPEOF(Pike_sp[-1]) == T_STRING ) string_builder_shared_strcat(tmp, Pike_sp[-1].u.string);
75a9f62011-12-04Arne Goedeke  if (Pike_sp > save_sp) pop_n_elems(Pike_sp-save_sp);
080e3a2011-11-04Per Hedbor }
a580e12000-09-27Fredrik Hübinette (Hubbe) 
676e412001-07-28Martin Nilsson  /*! @decl constant __REAL_VERSION__ *! *! This define always contains the version of the current Pike, *! represented as a float. *! *! @seealso *! @[__VERSION__] */ /*! @decl constant __REAL_MAJOR__ *! *! This define always contains the major part of the version of the *! current Pike, represented as an integer. *! *! @seealso *! @[__MAJOR__] */ /*! @decl constant __REAL_MINOR__ *! *! This define always contains the minor part of the version of the *! current Pike, represented as an integer. *! *! @seealso *! @[__MINOR__] */ /*! @decl constant __BUILD__ *! This constant contains the build number of the current Pike version, *! represented as an integer. If another Pike version is emulated, *! this constant remains unaltered. *! *! @seealso *! @[__REAL_MINOR__] */ /*! @decl constant __REAL_BUILD__ *! *! This define always contains the minor part of the version of the *! current Pike, represented as an integer. *! *! @seealso *! @[__BUILD__] */
aba09a2011-12-28Henrik Grubbström (Grubba) /*! @decl constant static_assert *! *! This define expands to the symbol @[_Static_assert]. *! *! It is the preferred way to perform static *! (ie compile-time) assertions. *! *! @note *! The macro can also be used to check for whether static assertions *! are supported. *! *! @seealso
2d5df62013-05-04Henrik Grubbström (Grubba)  *! @[predef::_Static_assert()]
aba09a2011-12-28Henrik Grubbström (Grubba)  */
676e412001-07-28Martin Nilsson /*! @decl constant __PIKE__ *! *! This define is always true. */ /*! @decl constant __AUTO_BIGNUM__ *! *! This define is defined when automatic bignum conversion is enabled. *! When enabled all integers will automatically be converted to *! bignums when they get bigger than what can be represented by *! an integer, hampering performance slightly instead of crashing
d6d2e52016-06-10Martin Nilsson  *! the program. This define is always set since Pike 8.0.
676e412001-07-28Martin Nilsson  */ /*! @decl constant __NT__ *! *! This define is defined when the Pike is running on a Microsoft Windows OS, *! not just Microsoft Windows NT, as the name implies. */
0c95942018-01-12Stephen R. van den Berg /*! @decl constant __amigaos__ *! *! This define is defined when the Pike is running on Amiga OS. */
5220422003-04-01Martin Nilsson /*! @endnamespace */
7cb5e22018-01-07Henrik Grubbström (Grubba)  PIKEFUN void create(mapping|string|void opts_or_file, int|string|void charset_sv, object|void handler, int|void compat_major_sv, int|void compat_minor_sv, int|void picky_cpp_sv) flags ID_PROTECTED; { struct CPP_struct *this = THIS; struct pike_string *prefix = NULL; struct pike_string *current_file = 0; struct pike_string *charset = NULL; int compat_major = compat_major_sv?compat_major_sv->u.integer:0; int compat_minor = compat_minor_sv?compat_minor_sv->u.integer:0; int picky_cpp = picky_cpp_sv?picky_cpp_sv->u.integer:0; this->prefix = NULL; this->current_line=1; this->compile_errors=0; this->defines = allocate_mapping(32); this->keep_comments = 0; this->dependencies_fail = 0; this->auto_convert = 0; if (opts_or_file) { if (TYPEOF(*opts_or_file) == PIKE_T_MAPPING) { struct svalue *tmp; struct mapping *m = opts_or_file->u.mapping; #define GET_TYPE(type, name) ((tmp = simple_mapping_string_lookup(m, name)) \ && (TYPEOF(*(tmp)) == PIKE_T_##type || (Pike_error("Expected type %s,"\ "got type %s for " name ".", get_name_of_type(PIKE_T_##type), get_name_of_type(TYPEOF(*tmp))), 0))) if (GET_TYPE(STRING, "current_file")) current_file = tmp->u.string; if (GET_TYPE(STRING, "charset")) charset_sv = tmp; if (GET_TYPE(OBJECT, "handler")) handler = tmp->u.object; if (GET_TYPE(INT, "compat_major")) compat_major = tmp->u.integer; if (GET_TYPE(INT, "compat_minor")) compat_minor = tmp->u.integer; if (GET_TYPE(INT, "picky")) picky_cpp = tmp->u.integer; if (GET_TYPE(STRING, "prefix")) prefix = tmp->u.string; if (GET_TYPE(INT, "keep_comments")) this->keep_comments = tmp->u.integer; #undef GET_TYPE } else if (TYPEOF(*opts_or_file) == PIKE_T_STRING) { current_file = opts_or_file->u.string; } } if(current_file) add_ref(current_file); else current_file = make_shared_string("-"); this->current_file = current_file; this->compat_major=PIKE_MAJOR_VERSION; this->compat_minor=PIKE_MINOR_VERSION; this->compat_handler = 0; this->handler = handler; if(handler) add_ref(handler); if (prefix) { int i; if (prefix->size_shift) { Pike_error("No widechars allowed in cpp prefix.\n"); } for (i = 0; i < prefix->len; i++) { if (!wide_isidchar(prefix->str[i])) { Pike_error("Invalid char in prefix.\n"); } } this->prefix = prefix; add_ref(prefix); } if(charset_sv) { if(TYPEOF(*charset_sv) == T_STRING) { this->charset = charset_sv->u.string; add_ref(this->charset); } else if(TYPEOF(*charset_sv) == T_INT) this->auto_convert = charset_sv->u.integer; else { SIMPLE_ARG_TYPE_ERROR("cpp", 3, "string|int"); } } if(compat_major) cpp_change_compat(this, compat_major, compat_minor); this->picky_cpp = picky_cpp;
3b25dd2018-01-12Martin Nilsson  pop_n_elems(args);
7cb5e22018-01-07Henrik Grubbström (Grubba)  }
8c8da92018-01-09Henrik Grubbström (Grubba)  PIKEFUN void define_ansi_macros() { struct CPP_struct *this = THIS; /* These attempt to be compatible with the C standard. */ do_magic_define(this,"__LINE__",insert_current_line); do_magic_define(this,"__FILE__",insert_current_file_as_string); do_magic_define(this,"__DATE__",insert_current_date_as_string); do_magic_define(this,"__TIME__",insert_current_time_as_string); /* These are from the 201x C standard. */ do_magic_define(this,"_Pragma",insert_pragma)->args = 1; simple_add_define(this, "static_assert", "_Static_assert"); } PIKEFUN void define_pike_macros() { struct CPP_struct *this = THIS; /* These are Pike extensions. */ do_magic_define(this,"__DIR__",insert_current_dir_as_string); do_magic_define(this,"__VERSION__",insert_current_version); do_magic_define(this,"__MAJOR__",insert_current_major); do_magic_define(this,"__MINOR__",insert_current_minor); simple_add_define(this, "__ARGS__", "__args__"); do_magic_define(this,"__COUNTER__",insert_current_counter); #if 0 /* Left in place for documentation reference purposes. */ struct define_struct *def = alloc_empty_define(make_shared_string("__deprecated__"), 1); def->args = 1; REF_MAKE_CONST_STRING(def->first, "__attribute__(\"deprecated\", "); def->parts[0].argument = 0; REF_MAKE_CONST_STRING(def->parts[0].postfix, ")"); mapping_string_insert(this->defines, def->name, Pike_sp-1); pop_stack(); #endif /* 0 */ simple_add_define(this, "__PIKE__", " 1 "); simple_add_define(this, "__REAL_VERSION__", " " DEFINETOSTR(PIKE_MAJOR_VERSION) "." DEFINETOSTR(PIKE_MINOR_VERSION) " "); simple_add_define(this, "__REAL_MAJOR__", " " DEFINETOSTR(PIKE_MAJOR_VERSION) " "); simple_add_define(this, "__REAL_MINOR__", " " DEFINETOSTR(PIKE_MINOR_VERSION) " "); simple_add_define(this, "__BUILD__", " " DEFINETOSTR(PIKE_BUILD_VERSION) " "); simple_add_define(this, "__REAL_BUILD__", " " DEFINETOSTR(PIKE_BUILD_VERSION) " "); simple_add_define(this, "__AUTO_BIGNUM__", " 1 "); #ifdef __NT__ simple_add_define(this, "__NT__", " 1 "); #endif
0c95942018-01-12Stephen R. van den Berg #ifdef __amigaos__ simple_add_define(this, "__amigaos__", " 1 "); #endif
8c8da92018-01-09Henrik Grubbström (Grubba) #ifdef __APPLE__ simple_add_define(this, "__APPLE__", " 1 "); #endif simple_add_define(this, "SIZEOF_INT", " " DEFINETOSTR(SIZEOF_INT) " "); simple_add_define(this, "SIZEOF_FLOAT", " " DEFINETOSTR(SIZEOF_FLOAT) " "); }
7cb5e22018-01-07Henrik Grubbström (Grubba) }
16a6f72011-11-27Tobias S. Josefowitz /*! @decl string cpp(string data, mapping|string|void current_file, @
7c0df72001-02-06Henrik Grubbström (Grubba)  *! int|string|void charset, object|void handler, @
f6da7b2004-06-27Martin Nilsson  *! void|int compat_major, void|int compat_minor, @
91a2f62004-11-05Martin Nilsson  *! void|int picky_cpp)
7c0df72001-02-06Henrik Grubbström (Grubba)  *! *! Run a string through the preprocessor. *! *! Preprocesses the string @[data] with Pike's builtin ANSI-C look-alike *! preprocessor. If the @[current_file] argument has not been specified,
cbe8c92003-04-07Martin Nilsson  *! it will default to @expr{"-"@}. @[charset] defaults to @expr{"ISO-10646"@}.
7c0df72001-02-06Henrik Grubbström (Grubba)  *!
16a6f72011-11-27Tobias S. Josefowitz  *! If the second argument is a mapping, no other arguments may follow. *! Instead, they have to be given as members of the mapping (if wanted). *! The following members are recognized: *! *! @mapping
6c3a6f2013-11-20Henrik Grubbström (Grubba)  *! @member string "current_file"
edd9722014-08-09Arne Goedeke  *! Name of the current file. It is used for generating *! #line directives and for locating include files.
6c3a6f2013-11-20Henrik Grubbström (Grubba)  *! @member int|string "charset"
edd9722014-08-09Arne Goedeke  *! Charset to use when processing @expr{data@}.
6c3a6f2013-11-20Henrik Grubbström (Grubba)  *! @member object "handler"
edd9722014-08-09Arne Goedeke  *! Compilation handler.
6c3a6f2013-11-20Henrik Grubbström (Grubba)  *! @member int "compat_major"
edd9722014-08-09Arne Goedeke  *! Sets the major pike version used for compat handling.
6c3a6f2013-11-20Henrik Grubbström (Grubba)  *! @member int "compat_minor"
edd9722014-08-09Arne Goedeke  *! Sets the minor pike version used for compat handling.
6c3a6f2013-11-20Henrik Grubbström (Grubba)  *! @member int "picky_cpp"
edd9722014-08-09Arne Goedeke  *! Generate more warnings.
6c3a6f2013-11-20Henrik Grubbström (Grubba)  *! @member int "keep_comments"
edd9722014-08-09Arne Goedeke  *! This option keeps @[cpp()] from removing comments.
6c3a6f2013-11-20Henrik Grubbström (Grubba)  *! Useful in combination with the prefix feature below. *! @member string "prefix"
16a6f72011-11-27Tobias S. Josefowitz  *! If a prefix is given, only prefixed directives will be *! processed. For example, if the prefix is @expr{"foo"@}, then *! @expr{#foo_ifdef COND@} and @expr{foo___LINE__@} would be *! processed, @expr{#ifdef COND@} and @expr{__LINE__@} would not. *! @endmapping *!
7c0df72001-02-06Henrik Grubbström (Grubba)  *! @seealso *! @[compile()]
739f9d1999-11-04Henrik Grubbström (Grubba)  */
e34dcf2004-05-22Martin Nilsson 
3b87412016-07-27Henrik Grubbström (Grubba) PIKEFUN string cpp(string data, mapping|string|void opts_or_file, int|string|void charset_sv, object|void handler, int|void compat_major_sv, int|void compat_minor_sv, int|void picky_cpp_sv) efun;
5740881998-01-01Fredrik Hübinette (Hubbe) {
7cb5e22018-01-07Henrik Grubbström (Grubba)  struct svalue *save_sp = Pike_sp - args; struct object *cpp_obj = clone_object(CPP_program, args-1);
6e2bb52018-01-05Henrik Grubbström (Grubba)  struct CPP_struct *this = (struct CPP_struct *)get_storage(cpp_obj, CPP_program);
e34dcf2004-05-22Martin Nilsson  struct mapping *predefs = NULL;
57cef71999-12-28Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG ONERROR tmp; #endif /* PIKE_DEBUG */
770b6d1999-02-23Henrik Grubbström (Grubba) 
6e2bb52018-01-05Henrik Grubbström (Grubba)  push_object(cpp_obj);
b584b12001-12-20Martin Stjernholm  if (use_initial_predefs) /* Typically compiling the master here. */ predefs = initial_predefs_mapping(); else {
6e2bb52018-01-05Henrik Grubbström (Grubba)  low_unsafe_apply_handler ("get_predefines", this->handler, this->compat_handler, 0);
19961b2017-04-08Martin Nilsson  if (!UNSAFE_IS_ZERO (Pike_sp - 1)) {
b584b12001-12-20Martin Stjernholm  struct keypair *k; int e, sprintf_args = 0;
19961b2017-04-08Martin Nilsson  if (TYPEOF(Pike_sp[-1]) != T_MAPPING) {
5e9fc02015-08-18Per Hedbor  push_static_text ("Invalid return value from get_predefines, got %O\n");
19961b2017-04-08Martin Nilsson  push_svalue (Pike_sp - 3);
b584b12001-12-20Martin Stjernholm  sprintf_args = 2; } else {
19961b2017-04-08Martin Nilsson  predefs = copy_mapping (Pike_sp[-1].u.mapping);
b584b12001-12-20Martin Stjernholm  NEW_MAPPING_LOOP (predefs->data) {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(k->ind) != T_STRING || !k->ind.u.string->len) {
5e9fc02015-08-18Per Hedbor  push_static_text ("Expected nonempty string as predefine name, got %O\n");
b584b12001-12-20Martin Stjernholm  push_svalue (&k->ind); sprintf_args = 2; free_mapping (predefs); predefs = NULL; goto predef_map_error;
75a9f62011-12-04Arne Goedeke  } else if (!(TYPEOF(k->val) == T_INT && !k->val.u.integer) && TYPEOF(k->val) != T_STRING && TYPEOF(k->val) != T_FUNCTION && TYPEOF(k->val) != T_OBJECT) {
5e9fc02015-08-18Per Hedbor  push_static_text ("expected zero, string or function value for"
75a9f62011-12-04Arne Goedeke  " predefine %O\n"); push_svalue (&k->ind); sprintf_args = 2; free_mapping (predefs); predefs = NULL; goto predef_map_error;
b584b12001-12-20Martin Stjernholm  } } } if (!predefs) { predef_map_error: f_sprintf (sprintf_args);
19961b2017-04-08Martin Nilsson  Pike_error("%S", Pike_sp[-1].u.string);
b584b12001-12-20Martin Stjernholm  } } pop_stack(); }
8c8da92018-01-09Henrik Grubbström (Grubba)  apply(cpp_obj, "define_ansi_macros", 0);
f0950a1999-03-27Henrik Grubbström (Grubba) 
8c8da92018-01-09Henrik Grubbström (Grubba)  apply(cpp_obj, "define_pike_macros", 0);
5740881998-01-01Fredrik Hübinette (Hubbe) 
b584b12001-12-20Martin Stjernholm  if (predefs) { struct keypair *k; int e; NEW_MAPPING_LOOP (predefs->data) {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(k->val) == T_STRING)
6e2bb52018-01-05Henrik Grubbström (Grubba)  add_define (this, k->ind.u.string, k->val.u.string);
75a9f62011-12-04Arne Goedeke  else if(TYPEOF(k->val) == T_FUNCTION || TYPEOF(k->val) == T_OBJECT)
080e3a2011-11-04Per Hedbor  {
7962c02016-09-01Henrik Grubbström (Grubba)  struct define_struct *def;
080e3a2011-11-04Per Hedbor  if( index_shared_string( k->ind.u.string, k->ind.u.string->len-1) == ')' ) { struct pike_string *s = string_slice( k->ind.u.string, 0, k->ind.u.string->len-2);
7a61202016-09-04Henrik Grubbström (Grubba)  def = alloc_empty_define(s);
500d462016-09-06Henrik Grubbström (Grubba)  free_string(s);
080e3a2011-11-04Per Hedbor  def->magic = insert_callback_define; def->varargs=1; def->args=1; } else {
7a61202016-09-04Henrik Grubbström (Grubba)  def = alloc_empty_define(k->ind.u.string);
080e3a2011-11-04Per Hedbor  def->magic = insert_callback_define_no_args; }
6e2bb52018-01-05Henrik Grubbström (Grubba)  mapping_string_insert(this->defines, def->name, Pike_sp-1);
e442822016-08-31Henrik Grubbström (Grubba)  pop_stack();
080e3a2011-11-04Per Hedbor  }
b584b12001-12-20Martin Stjernholm  else
6e2bb52018-01-05Henrik Grubbström (Grubba)  add_define (this, k->ind.u.string, empty_pike_string);
b584b12001-12-20Martin Stjernholm  } free_mapping (predefs); }
5740881998-01-01Fredrik Hübinette (Hubbe) 
7cb5e22018-01-07Henrik Grubbström (Grubba)  this->data = data; add_ref(data); if (this->charset) { push_string(data); this->data = data = NULL; ref_push_string(this->charset); if (!safe_apply_handler ("decode_charset", this->handler, this->compat_handler, 2, BIT_STRING)) { cpp_handle_exception (this, "Error decoding with charset %S", THIS->charset); Pike_error("Unknown charset.\n"); } this->data = data = Pike_sp[-1].u.string; Pike_sp--; dmalloc_touch_svalue(Pike_sp); } if (this->auto_convert && (!data->size_shift) && (data->len > 1)) { /* Try to determine if we need to recode the string */ struct pike_string *new_data = recode_string(this, data); free_string(data); this->data = data = new_data; } if (data->size_shift) { /* Get rid of any byte order marks (0xfeff) */ struct pike_string *new_data = filter_bom(data); free_string(data); this->data = data = new_data; }
6e2bb52018-01-05Henrik Grubbström (Grubba)  string_builder_binary_strcat(&this->buf, "#line 1 ", 8); PUSH_STRING_SHIFT(this->current_file->str, this->current_file->len, this->current_file->size_shift, &this->buf); string_builder_putchar(&this->buf, '\n');
5740881998-01-01Fredrik Hübinette (Hubbe) 
57cef71999-12-28Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG SET_ONERROR(tmp, fatal_on_error, "Preprocessor exited with longjump!\n"); #endif /* PIKE_DEBUG */
6ae1862018-01-13Henrik Grubbström (Grubba)  ref_push_string(data); /* data */ push_int(0); /* flags */
6710342018-02-21Henrik Grubbström (Grubba)  apply(cpp_obj, "low_cpp", 2);
57cef71999-12-28Henrik Grubbström (Grubba)  #ifdef PIKE_DEBUG UNSET_ONERROR(tmp); #endif /* PIKE_DEBUG */
6e2bb52018-01-05Henrik Grubbström (Grubba)  if(this->compile_errors)
5740881998-01-01Fredrik Hübinette (Hubbe)  {
ab53cf2018-02-24Martin Nilsson  throw_error_object(fast_clone_object(cpp_error_program), 0, 0,
010dc62001-08-16Martin Stjernholm  "Cpp() failed\n");
9565132014-02-14Martin Nilsson  }
6e2bb52018-01-05Henrik Grubbström (Grubba)  else if(this->dependencies_fail)
9565132014-02-14Martin Nilsson  { push_int(0); } else {
6e2bb52018-01-05Henrik Grubbström (Grubba)  push_string(finish_string_builder(&this->buf)); /* NB: Make sure the buffer isn't freed twice. */ this->buf.s = NULL;
5740881998-01-01Fredrik Hübinette (Hubbe)  }
6e2bb52018-01-05Henrik Grubbström (Grubba)  stack_pop_n_elems_keep_top((Pike_sp - save_sp) - 1);
5740881998-01-01Fredrik Hübinette (Hubbe) }
6c3a6f2013-11-20Henrik Grubbström (Grubba) /*! @module Builtin */ /*! @decl mapping(string:mixed) _take_over_initial_predefines()
4f395b2018-01-10Henrik Grubbström (Grubba)  *! *! Returns a mapping containing the set of predefined macros. *! These are typically the macros defined via the @tt{-D@} option *! when starting Pike. *! *! This function is typically called by the @[MasterObject] at *! initialization, and may only be called once. After it has been called, *! @[cpp()] will start calling @[CompilationHandler->get_predefines()] to *! retrieve the set of predefined macros. *! *! @seealso *! [cpp()], @[CompilationHandler->get_predefines()]
6c3a6f2013-11-20Henrik Grubbström (Grubba)  */
b584b12001-12-20Martin Stjernholm void f__take_over_initial_predefines (INT32 args) { pop_n_elems (args); if (use_initial_predefs) { struct pike_predef_s *tmp; push_mapping (initial_predefs_mapping()); use_initial_predefs = 0; while((tmp=first_predef)) { free(tmp->name); first_predef=tmp->next;
0ec7522014-04-27Martin Nilsson  free(tmp);
b584b12001-12-20Martin Stjernholm  } last_predef = 0; } else Pike_error ("Initial predefines already taken over.\n"); }
6c3a6f2013-11-20Henrik Grubbström (Grubba) /*! @endmodule */
5740881998-01-01Fredrik Hübinette (Hubbe) void init_cpp() {
b584b12001-12-20Martin Stjernholm  struct svalue s;
5164822004-11-14Martin Stjernholm  efun_str = make_shared_string ("efun"); constant_str = make_shared_string ("constant"); defined_str = make_shared_string ("defined");
b584b12001-12-20Martin Stjernholm  use_initial_predefs = 1;
3b87412016-07-27Henrik Grubbström (Grubba)  INIT;
b584b12001-12-20Martin Stjernholm 
500d462016-09-06Henrik Grubbström (Grubba)  defined_macro = alloc_empty_define(defined_str);
be65c52016-09-02Henrik Grubbström (Grubba)  defined_macro->magic=check_defined; defined_macro->args=1; defined_macro_sval = Pike_sp[-1]; Pike_sp--;
75a9f62011-12-04Arne Goedeke  ADD_INT_CONSTANT("__HAVE_CPP_PREFIX_SUPPORT__", 1, 0);
b584b12001-12-20Martin Stjernholm  /* Somewhat tricky to add a _constant_ function in _static_modules.Builtin. */
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(s, T_FUNCTION, FUNCTION_BUILTIN, efun, make_callable (f__take_over_initial_predefines, "_take_over_initial_predefines", "function(void:mapping(string:string))", OPT_SIDE_EFFECT, NULL, NULL));
b584b12001-12-20Martin Stjernholm  simple_add_constant ("_take_over_initial_predefines", &s, 0); free_svalue (&s);
5740881998-01-01Fredrik Hübinette (Hubbe) }
b678e32014-05-15Martin Nilsson void add_predefine(const char *s)
5740881998-01-01Fredrik Hübinette (Hubbe) { struct pike_predef_s *tmp=ALLOC_STRUCT(pike_predef_s);
282a8a2018-01-04Henrik Grubbström (Grubba)  size_t len = strlen(s); char *pos=strchr(s,'=');
5740881998-01-01Fredrik Hübinette (Hubbe)  if(pos) {
282a8a2018-01-04Henrik Grubbström (Grubba)  tmp->name = xalloc(len+1); memcpy(tmp->name, s, len+1);
5740881998-01-01Fredrik Hübinette (Hubbe)  tmp->name[pos-s]=0;
282a8a2018-01-04Henrik Grubbström (Grubba)  tmp->value = tmp->name + (pos-s) + 1;
5740881998-01-01Fredrik Hübinette (Hubbe)  }else{
282a8a2018-01-04Henrik Grubbström (Grubba)  tmp->name = xalloc(len + 1 + 4); memcpy(tmp->name,s,len + 1);
5740881998-01-01Fredrik Hübinette (Hubbe) 
282a8a2018-01-04Henrik Grubbström (Grubba)  tmp->value = tmp->name + len + 1;
59fc9e2014-09-03Martin Nilsson  memcpy(tmp->value," 1 ",4);
5740881998-01-01Fredrik Hübinette (Hubbe)  }
b584b12001-12-20Martin Stjernholm  tmp->next = NULL;
282a8a2018-01-04Henrik Grubbström (Grubba) 
b584b12001-12-20Martin Stjernholm  if (first_predef) { last_predef->next = tmp; last_predef = tmp; } else first_predef = last_predef = tmp;
5740881998-01-01Fredrik Hübinette (Hubbe) }
ae95031999-04-07Fredrik Hübinette (Hubbe) void exit_cpp(void)
5740881998-01-01Fredrik Hübinette (Hubbe) {
ae95031999-04-07Fredrik Hübinette (Hubbe) #ifdef DO_PIKE_CLEANUP
5740881998-01-01Fredrik Hübinette (Hubbe)  struct pike_predef_s *tmp;
3b87412016-07-27Henrik Grubbström (Grubba)  EXIT;
b584b12001-12-20Martin Stjernholm  while((tmp=first_predef))
5740881998-01-01Fredrik Hübinette (Hubbe)  { free(tmp->name);
b584b12001-12-20Martin Stjernholm  first_predef=tmp->next;
0ec7522014-04-27Martin Nilsson  free(tmp);
5740881998-01-01Fredrik Hübinette (Hubbe)  }
e442822016-08-31Henrik Grubbström (Grubba)  free_svalue(&defined_macro_sval);
5164822004-11-14Martin Stjernholm  free_string (efun_str); free_string (constant_str); free_string (defined_str);
e442822016-08-31Henrik Grubbström (Grubba) 
ae95031999-04-07Fredrik Hübinette (Hubbe) #endif
5740881998-01-01Fredrik Hübinette (Hubbe) }