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 "hashtable.h" #include "program.h" #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"
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
6ad2372002-05-11Martin Nilsson #define sp Pike_sp
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
7050b72014-02-25Per Hedbor struct define_part; struct define_argument; struct define; struct cpp;
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_part { int argument; struct pike_string *postfix; }; 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) }; struct cpp; struct define; typedef void (*magic_define_fun)(struct cpp *, struct define *, struct define_argument *,
d9ac331999-02-22Henrik Grubbström (Grubba)  struct string_builder *);
5740881998-01-01Fredrik Hübinette (Hubbe)  struct define { struct hash_entry link; /* must be first */ magic_define_fun magic; int args;
170b862000-08-10Henrik Grubbström (Grubba)  ptrdiff_t num_parts;
821bb92001-05-29Henrik Grubbström (Grubba)  short inside; /* 1 - Don't expand. 2 - In use. */
39dc6c2000-06-13Fredrik Hübinette (Hubbe)  short varargs;
5740881998-01-01Fredrik Hübinette (Hubbe)  struct pike_string *first; struct define_part parts[1]; };
efd97a2014-05-12Martin Nilsson #define FIND_DEFINE(N) \
5740881998-01-01Fredrik Hübinette (Hubbe)  (this->defines?BASEOF(hash_lookup(this->defines, N), define, link):0) struct cpp { struct hash_table *defines;
6fc2e72012-01-12Henrik Grubbström (Grubba)  INT_TYPE current_line;
5740881998-01-01Fredrik Hübinette (Hubbe)  INT32 compile_errors; struct pike_string *current_file;
d9ac331999-02-22Henrik Grubbström (Grubba)  struct string_builder buf;
739f9d1999-11-04Henrik Grubbström (Grubba)  struct object *handler;
ac87152000-09-25Fredrik Hübinette (Hubbe)  struct object *compat_handler;
16a6f72011-11-27Tobias S. Josefowitz  INT_TYPE compat_major; INT_TYPE compat_minor;
e34dcf2004-05-22Martin Nilsson  struct pike_string *data;
16a6f72011-11-27Tobias S. Josefowitz  struct pike_string *prefix;
9565132014-02-14Martin Nilsson  INT_TYPE picky_cpp, keep_comments, dependencies_fail;
5740881998-01-01Fredrik Hübinette (Hubbe) };
3b87412016-07-27Henrik Grubbström (Grubba) DECLARE_STORAGE;
1ebec62014-05-13Martin Nilsson static void cpp_error(struct cpp *this, const char *err) ATTRIBUTE((noinline));
7050b72014-02-25Per Hedbor static void cpp_error_vsprintf (struct cpp *this, const char *fmt,
1ebec62014-05-13Martin Nilsson  va_list args) ATTRIBUTE((noinline)); static void cpp_error_sprintf(struct cpp *this, const char *fmt, ...) ATTRIBUTE((noinline));
7050b72014-02-25Per Hedbor static void cpp_handle_exception(struct cpp *this,
1ebec62014-05-13Martin Nilsson  const char *cpp_error_fmt, ...) ATTRIBUTE((noinline)); static void cpp_warning(struct cpp *this, const char *cpp_warn_fmt, ...) ATTRIBUTE((noinline));
5740881998-01-01Fredrik Hübinette (Hubbe) struct define *defined_macro =0;
fbf6c92004-06-29Henrik Grubbström (Grubba) 
4045632004-06-29Martin Nilsson static void cpp_error(struct cpp *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); } }
4045632004-06-29Martin Nilsson static void cpp_error_vsprintf (struct cpp *this, const char *fmt, 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 
4045632004-06-29Martin Nilsson static void cpp_error_sprintf(struct cpp *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); }
4045632004-06-29Martin Nilsson static void cpp_handle_exception(struct cpp *this, 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  if (SAFE_IS_ZERO(sp-1)) { 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 }
f6da7b2004-06-27Martin Nilsson static void cpp_warning(struct cpp *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. */
ac87152000-09-25Fredrik Hübinette (Hubbe) void cpp_change_compat(struct cpp *this, int major, int minor) { 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);
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(sp[-1]) == T_OBJECT)
ac87152000-09-25Fredrik Hübinette (Hubbe)  {
017b572011-10-28Henrik Grubbström (Grubba)  if (SUBTYPEOF(sp[-1])) {
f54c782004-12-22Henrik Grubbström (Grubba)  cpp_error(this, "#pike: Subtyped compilation handlers are not supported yet."); }
ac87152000-09-25Fredrik Hübinette (Hubbe)  this->compat_handler=sp[-1].u.object;
50ea682003-03-14Henrik Grubbström (Grubba)  dmalloc_touch_svalue(Pike_sp-1);
ac87152000-09-25Fredrik Hübinette (Hubbe)  sp--; } 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>@}@} *! *! is equvivalent to *! *! @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>@}@} *! *! is equvivalent to *! *! @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 *! *! The following two are equvivalent: *! *! @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] */ /*! @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] */ /*! @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 *! // the old behaviour for @[7.2::dirname()]. *! #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()] *! level @expr{3@}. Note that this @tt{#pragma@} is a noop *! if Pike hasn't been compiled @tt{--with-debug@}. *! @value "no_disassemble" *! Disable disassembly output (default).
4fa6542012-03-24Henrik Grubbström (Grubba)  *! @endstring */ /*! @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 *! @tt{#if defined(MY_DEF)@} is equvivalent to *! @tt{#ifdef MY_DEF@}. *! *! @seealso *! @[#if], @[#ifdef], @[constant()] */
fbf6c92004-06-29Henrik Grubbström (Grubba) static void check_defined(struct cpp *this,
74dfe82012-12-30Jonas Walldén  struct define *UNUSED(def),
fbf6c92004-06-29Henrik Grubbström (Grubba)  struct define_argument *args, struct string_builder *tmp) {
9506a12016-08-20Martin Nilsson  struct pike_string *s = binary_findstring_wide( args[0].arg.ptr, args[0].arg.shift, args[0].len );
6e52062014-05-12Martin Nilsson 
efd97a2014-05-12Martin Nilsson  if(s && FIND_DEFINE(s))
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); } static int do_safe_index_call(struct cpp *this, struct pike_string *s) { 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 
017b572011-10-28Henrik Grubbström (Grubba)  res=!(UNSAFE_IS_ZERO(sp-1) && SUBTYPEOF(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()] */ static void cpp_constant(struct cpp *this, int value)
fbf6c92004-06-29Henrik Grubbström (Grubba) { struct svalue *save_stack=sp; 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
017b572011-10-28Henrik Grubbström (Grubba)  res = !(SAFE_IS_ZERO(sp-1) && SUBTYPEOF(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))
017b572011-10-28Henrik Grubbström (Grubba)  res = !(SAFE_IS_ZERO(sp-1) && SUBTYPEOF(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) {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-1]) == T_INT)
a1640e2010-09-18Marcus Comstedt  res = sp[-1].u.integer; else res = 0; } pop_n_elems(1 + 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 for (def = first_predef; def; def = def->next) {
2d1a3e2003-12-06Martin Nilsson  push_text (def->name); push_text (def->value);
b584b12001-12-20Martin Stjernholm  mapping_insert (map, sp - 2, sp - 1); pop_n_elems (2); } return map; }
1f57ef2014-05-10Per Hedbor static p_wchar2 readchar( PCHARP data, ptrdiff_t *pos, struct cpp *this ) { 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; }
efd97a2014-05-12Martin Nilsson static ptrdiff_t readstring( struct cpp *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.");
a22fe12015-04-23Henrik Grubbström (Grubba)  /* FALL_THROUGH */
1f57ef2014-05-10Per Hedbor  default: string_builder_putchar(nf, INDEX_PCHARP(data,pos)); continue; } pos++; break; } return pos; }
2028f82014-07-21Per Hedbor static ptrdiff_t readstring_lit( struct cpp *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos, 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; }
efd97a2014-05-12Martin Nilsson static ptrdiff_t fixstring(struct cpp *this, const PCHARP data, ptrdiff_t len, 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; }
efd97a2014-05-12Martin Nilsson static ptrdiff_t find_end_of_line( struct cpp *this, const PCHARP data, 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; }
efd97a2014-05-12Martin Nilsson static ptrdiff_t find_end_of_comment( struct cpp *this, const PCHARP data, ptrdiff_t len, 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; }
efd97a2014-05-12Martin Nilsson static ptrdiff_t find_end_of_string2( struct cpp *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos)
1585cf2014-05-10Per Hedbor { while(1) { if(pos>=len) { cpp_error(this,"End of file in string."); break; } switch(INDEX_PCHARP(data,pos++)) { case '\n': this->current_line++; PUTNL(); continue; case '"': return pos; case '\\': if(INDEX_PCHARP(data,pos)=='\n') { this->current_line++; PUTNL(); } else if ((INDEX_PCHARP(data,pos) == '\r') && (INDEX_PCHARP(data,pos+1) == '\n')) { this->current_line++; pos++; PUTNL(); } pos++; } } return pos; }
efd97a2014-05-12Martin Nilsson static ptrdiff_t find_end_of_string( struct cpp *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos)
1f57ef2014-05-10Per Hedbor { 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++; PUTNL(); break; case '"': return pos; case '\\': if(INDEX_PCHARP(data,pos)=='\n') { this->current_line++; PUTNL(); } else if ((INDEX_PCHARP(data,pos) == '\r') && (INDEX_PCHARP(data,pos+1) == '\n')) { this->current_line++; pos++; PUTNL(); } pos++; }
13670c2015-05-25Martin Nilsson  }
1f57ef2014-05-10Per Hedbor  return pos; }
efd97a2014-05-12Martin Nilsson static ptrdiff_t find_end_of_char( struct cpp *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos)
1f57ef2014-05-10Per Hedbor { int e=0; while(1) { if(pos>=len) { cpp_error(this,"End of file in character constant."); break; } switch(INDEX_PCHARP(data,pos++)) { case '\n': cpp_error(this,"Newline in char."); this->current_line++; PUTNL(); break;
13670c2015-05-25Martin Nilsson  case '\'':
1f57ef2014-05-10Per Hedbor  return pos; case '\\': if(INDEX_PCHARP(data,pos)=='\n') { this->current_line++; PUTNL(); } else if ((INDEX_PCHARP(data,pos) == '\r') && (INDEX_PCHARP(data,pos+1) == '\n')) { this->current_line++; pos++; PUTNL(); } pos++; } } return pos; } static ptrdiff_t find_end_brace(struct cpp *this, PCHARP data, ptrdiff_t len, ptrdiff_t pos); static ptrdiff_t find_end_parenthesis(struct cpp *this, 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; case '\'': pos=find_end_of_char(this,data,len,pos); break; case '"': pos=find_end_of_string(this,data,len,pos); break; 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); } } } } static ptrdiff_t find_end_brace(struct cpp *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; case '\'': pos=find_end_of_char(this,data,len,pos); break; case '"': pos=find_end_of_string(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,0); } else if (INDEX_PCHARP(data,pos) == '/') { pos=find_end_of_line(this,data,len,pos,0); } } } }
1585cf2014-05-10Per Hedbor  static inline int wide_isspace( int c ) { return WIDE_ISSPACE(c); } static inline int wide_isidchar( int c ) { return WIDE_ISIDCHAR(c); }
90e5e92014-05-13Martin Nilsson static struct pike_string *gobble_identifier (struct cpp *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; }
5740881998-01-01Fredrik Hübinette (Hubbe) /* devours one reference to 'name'! */
170b862000-08-10Henrik Grubbström (Grubba) static struct define *alloc_empty_define(struct pike_string *name, ptrdiff_t parts)
5740881998-01-01Fredrik Hübinette (Hubbe) { struct define *def;
dc8d022014-04-27Martin Nilsson  def=xalloc(sizeof(struct define)+ sizeof(struct define_part) * (parts -1));
5740881998-01-01Fredrik Hübinette (Hubbe)  def->magic=0; def->args=-1; def->inside=0;
39dc6c2000-06-13Fredrik Hübinette (Hubbe)  def->varargs=0;
5740881998-01-01Fredrik Hübinette (Hubbe)  def->num_parts=parts; def->first=0; def->link.s=name;
bef8672001-05-13Fredrik Hübinette (Hubbe)  debug_malloc_touch(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()] */
5740881998-01-01Fredrik Hübinette (Hubbe) static void undefine(struct cpp *this,
90e5e92014-05-13Martin Nilsson  const struct pike_string *name)
5740881998-01-01Fredrik Hübinette (Hubbe) { INT32 e; struct define *d;
efd97a2014-05-12Martin Nilsson  d=FIND_DEFINE(name);
5740881998-01-01Fredrik Hübinette (Hubbe)  if(!d) return;
8538192001-05-29Henrik Grubbström (Grubba)  if (d->inside) { cpp_error(this, "Illegal to undefine a macro during its expansion."); return; }
5740881998-01-01Fredrik Hübinette (Hubbe)  this->defines=hash_unlink(this->defines, & d->link); for(e=0;e<d->num_parts;e++) free_string(d->parts[e].postfix); free_string(d->link.s); if(d->first) free_string(d->first);
0ec7522014-04-27Martin Nilsson  free(d);
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@}. */
3c8ee52011-12-28Henrik Grubbström (Grubba) static struct define *do_magic_define(struct cpp *this,
90e5e92014-05-13Martin Nilsson  const char *name,
3c8ee52011-12-28Henrik Grubbström (Grubba)  magic_define_fun fun)
5740881998-01-01Fredrik Hübinette (Hubbe) {
16a6f72011-11-27Tobias S. Josefowitz  struct define* def; if (this->prefix) { struct string_builder s; int len = strlen(name); init_string_builder(&s, 0); string_builder_append(&s, MKPCHARP_STR(this->prefix), this->prefix->len); string_builder_putchar(&s, '_'); string_builder_binary_strcat(&s, name, len); def = alloc_empty_define(finish_string_builder(&s),0); } else def = alloc_empty_define(make_shared_string(name),0);
5740881998-01-01Fredrik Hübinette (Hubbe)  def->magic=fun; this->defines=hash_insert(this->defines, & def->link);
3c8ee52011-12-28Henrik Grubbström (Grubba)  return def;
5740881998-01-01Fredrik Hübinette (Hubbe) }
b584b12001-12-20Martin Stjernholm static void add_define(struct cpp *this, struct pike_string *name, struct pike_string *what) { struct define* def; add_ref (name); def=alloc_empty_define(name,0); add_ref (def->first = what); this->defines=hash_insert(this->defines, & def->link); }
5740881998-01-01Fredrik Hübinette (Hubbe) static void simple_add_define(struct cpp *this,
90e5e92014-05-13Martin Nilsson  const char *name, const char *what)
5740881998-01-01Fredrik Hübinette (Hubbe) {
16a6f72011-11-27Tobias S. Josefowitz  struct define* def; if (this->prefix) { struct string_builder s; int len = strlen(name); init_string_builder(&s, 0); string_builder_append(&s, MKPCHARP_STR(this->prefix), this->prefix->len); string_builder_putchar(&s, '_'); string_builder_binary_strcat(&s, name, len); def = alloc_empty_define(finish_string_builder(&s),0); } else def = alloc_empty_define(make_shared_string(name),0);
5740881998-01-01Fredrik Hübinette (Hubbe)  def->first=make_shared_string(what); this->defines=hash_insert(this->defines, & def->link); }
715e552003-11-14Martin Stjernholm static struct pike_string *recode_string(struct cpp *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); add_ref(data = sp[-1].u.string); 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. */ if ((sp[-1].u.string->size_shift) || (((size_t)sp[-1].u.string->len) < CONSTANT_STRLEN("#charset")) || (sp[-1].u.string->str[0] != '#')) { 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 */ p = sp[-1].u.string->str + 1; 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); add_ref(data = sp[-1].u.string); 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); }
7050b72014-02-25Per Hedbor static void free_one_define(struct hash_entry *h)
8538192001-05-29Henrik Grubbström (Grubba) { int e; struct define *d=BASEOF(h, define, link); for(e=0;e<d->num_parts;e++) free_string(d->parts[e].postfix); if(d->first) free_string(d->first);
0ec7522014-04-27Martin Nilsson  free(d);
8538192001-05-29Henrik Grubbström (Grubba) }
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) #define WC_ISSPACE wide_isspace #define WC_ISIDCHAR wide_isidchar
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)
b7df6e2014-05-12Per Hedbor #define FIND_END_OF_STRING() (pos=find_end_of_string(this,data,len,pos)) #define FIND_END_OF_STRING2() (pos=find_end_of_string2(this,data,len,pos)) #define FIND_END_OF_CHAR() (pos=find_end_of_char(this,data,len,pos)) #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); }
90e5e92014-05-13Martin Nilsson static ptrdiff_t find_eos( struct cpp *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++; default: continue; } this->current_line++; break; } return pos; }
90e5e92014-05-13Martin Nilsson static ptrdiff_t skipwhite(struct cpp *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; }
90e5e92014-05-13Martin Nilsson static ptrdiff_t skipspace(struct cpp *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 error_[] = { 'e', 'r', 'r', 'o', 'r' }; 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 warning_[] = { 'w', 'a', 'r', 'n', 'i', 'n', 'g' }; 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; }
58efb82014-05-12Per Hedbor static ptrdiff_t low_cpp(struct cpp *this, PCHARP data, ptrdiff_t len, int flags, int auto_convert, struct pike_string *charset);
75a9f62011-12-04Arne Goedeke static void insert_callback_define(struct cpp *this, struct define *def, struct define_argument *args, struct string_builder *tmp); static void insert_callback_define_no_args(struct cpp *this, struct define *def, struct define_argument *args, struct string_builder *tmp);
51d3f32011-12-28Henrik Grubbström (Grubba) static void insert_pragma(struct cpp *this, struct define *def, struct define_argument *args, struct string_builder *tmp);
7b73fb2014-05-10Per Hedbor 
74966e2014-05-12Per Hedbor static ptrdiff_t calc1(struct cpp *this, PCHARP data, ptrdiff_t len, ptrdiff_t pos, int flags); static ptrdiff_t calcC(struct cpp *this, PCHARP data, ptrdiff_t len, 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; }
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; } /* FALL_THROUGH */ default:
b7df6e2014-05-12Per Hedbor  if (WC_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; } static ptrdiff_t calcB(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calcA(struct cpp *this,PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc9(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc8(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc7b(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc7(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc6(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc5(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc4(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc3(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc2(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc1(struct cpp *this, PCHARP data, ptrdiff_t len, 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; } static ptrdiff_t calc(struct cpp *this, PCHARP data, ptrdiff_t len, 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; }
7bfa4f1999-03-09Henrik Grubbström (Grubba) #include "preprocessor.h" /*** 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. */
7bfa4f1999-03-09Henrik Grubbström (Grubba) static void insert_current_line(struct cpp *this,
74dfe82012-12-30Jonas Walldén  struct define *UNUSED(def), struct define_argument *UNUSED(args),
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. */
7bfa4f1999-03-09Henrik Grubbström (Grubba) static void insert_current_file_as_string(struct cpp *this,
74dfe82012-12-30Jonas Walldén  struct define *UNUSED(def), struct define_argument *UNUSED(args),
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. */
15107c2008-06-12Martin Nilsson static void insert_current_dir_as_string(struct cpp *this,
74dfe82012-12-30Jonas Walldén  struct define *UNUSED(def), struct define_argument *UNUSED(args),
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". */
74dfe82012-12-30Jonas Walldén static void insert_current_time_as_string(struct cpp *UNUSED(this), struct define *UNUSED(def), struct define_argument *UNUSED(args),
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". */
74dfe82012-12-30Jonas Walldén static void insert_current_date_as_string(struct cpp *UNUSED(this), struct define *UNUSED(def), struct define_argument *UNUSED(args),
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__] */
a580e12000-09-27Fredrik Hübinette (Hubbe) static void insert_current_version(struct cpp *this,
74dfe82012-12-30Jonas Walldén  struct define *UNUSED(def), struct define_argument *UNUSED(args),
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__] */
a580e12000-09-27Fredrik Hübinette (Hubbe) static void insert_current_minor(struct cpp *this,
74dfe82012-12-30Jonas Walldén  struct define *UNUSED(def), struct define_argument *UNUSED(args),
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  *! */ static void insert_current_counter(struct cpp *UNUSED(this), struct define *UNUSED(def), struct define_argument *UNUSED(args), 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__] */
a580e12000-09-27Fredrik Hübinette (Hubbe) static void insert_current_major(struct cpp *this,
74dfe82012-12-30Jonas Walldén  struct define *UNUSED(def), struct define_argument *UNUSED(args),
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] */
51d3f32011-12-28Henrik Grubbström (Grubba) static void insert_pragma(struct cpp *this,
74dfe82012-12-30Jonas Walldén  struct define *UNUSED(def),
51d3f32011-12-28Henrik Grubbström (Grubba)  struct define_argument *args, struct string_builder *tmp) { int i; int in_string = 0; PCHARP arg = args->arg; ptrdiff_t len = args->len; /* Make some reasonable amount of space. */ string_build_mkspace(tmp, len + 20, arg.shift); string_builder_strcat(tmp, "\n#pragma "); /* Destringize the argument. */ for (i = 0; i < len; i++) { p_wchar2 ch = INDEX_PCHARP(arg, i); switch(ch) { case '\n': case '\r': ch = ' '; /* FALL_THROUGH */ case ' ': case '\t': if (in_string) { string_builder_putchar(tmp, ch); } break; case '\"': in_string = !in_string; break; case '\\': if (in_string) { ch = (++i < len) ? INDEX_PCHARP(arg, i) : '\0'; if ((ch != '\\') && (ch != '\"')) { cpp_error(this, "Invalid \\-escape in _Pragma()."); break; } } /* FALL_THROUGH */ 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'); }
080e3a2011-11-04Per Hedbor static void insert_callback_define(struct cpp *this, struct define *def, struct define_argument *args, struct string_builder *tmp) { ref_push_string( def->link.s ); push_string( make_shared_binary_pcharp( args[0].arg, args[0].len ) );
8190042011-12-28Henrik Grubbström (Grubba)  if (safe_apply_handler( "evaluate_define", this->handler, this->compat_handler, 2, 0 ) && TYPEOF(sp[-1]) == T_STRING ) {
6d3ae72011-11-20Henrik Grubbström (Grubba)  string_builder_shared_strcat(tmp, sp[-1].u.string);
7e5b172014-04-10Per Hedbor  if( !this->prefix ){ int min; check_string_range( sp[-1].u.string, 0, &min, 0 ); if( min < 32 ) { string_builder_sprintf(tmp, "\n#line %ld ", (long)this->current_line); insert_current_file_as_string( this,def,args,tmp); string_builder_putchar(tmp, '\n'); } }
75a9f62011-12-04Arne Goedeke  pop_stack(); }
080e3a2011-11-04Per Hedbor } static void insert_callback_define_no_args(struct cpp *this, struct define *def,
74dfe82012-12-30Jonas Walldén  struct define_argument *UNUSED(args),
080e3a2011-11-04Per Hedbor  struct string_builder *tmp) {
75a9f62011-12-04Arne Goedeke  struct svalue *save_sp = Pike_sp;
080e3a2011-11-04Per Hedbor  ref_push_string( def->link.s );
8190042011-12-28Henrik Grubbström (Grubba)  if (safe_apply_handler( "evaluate_define", this->handler, this->compat_handler, 1, 0 ) && TYPEOF(sp[-1]) == T_STRING )
6d3ae72011-11-20Henrik Grubbström (Grubba)  string_builder_shared_strcat(tmp, 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. */ /*! @decl constant __amigaos__ *! *! This define is defined when the Pike is running on Amiga OS. */
ac87152000-09-25Fredrik Hübinette (Hubbe) 
9ace1e2013-03-16Chris Angelico /*! @decl constant __OS2__ *! *! This define is defined when the Pike is running on IBM OS/2. */
5220422003-04-01Martin Nilsson /*! @endnamespace */
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  /* Doesn't free string_builder buf! */ static void free_cpp(struct cpp *this) { if(this->defines) free_hashtable(this->defines, free_one_define); if(this->current_file) free_string(this->current_file); if(this->handler) { free_object(this->handler); this->handler = 0; } if(this->compat_handler) { free_object(this->compat_handler); this->compat_handler=0; } if(this->data) free_string(this->data);
16a6f72011-11-27Tobias S. Josefowitz  if(this->prefix) free_string(this->prefix);
e34dcf2004-05-22Martin Nilsson }
080e3a2011-11-04Per Hedbor 
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) { struct cpp this;
e34dcf2004-05-22Martin Nilsson  struct svalue *save_sp = sp - args; struct mapping *predefs = NULL;
3b87412016-07-27Henrik Grubbström (Grubba)  struct pike_string *prefix = NULL;
e34dcf2004-05-22Martin Nilsson  struct pike_string *current_file = 0;
770b6d1999-02-23Henrik Grubbström (Grubba)  int auto_convert = 0;
a9a8dd1999-03-09Henrik Grubbström (Grubba)  struct pike_string *charset = NULL;
ac87152000-09-25Fredrik Hübinette (Hubbe) 
3b87412016-07-27Henrik Grubbström (Grubba)  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;
e34dcf2004-05-22Martin Nilsson  ONERROR err;
57cef71999-12-28Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG ONERROR tmp; #endif /* PIKE_DEBUG */
770b6d1999-02-23Henrik Grubbström (Grubba) 
16a6f72011-11-27Tobias S. Josefowitz  this.prefix = NULL;
e34dcf2004-05-22Martin Nilsson  this.current_line=1; this.compile_errors=0; this.defines=0;
16a6f72011-11-27Tobias S. Josefowitz  this.keep_comments = 0;
9565132014-02-14Martin Nilsson  this.dependencies_fail = 0;
16a6f72011-11-27Tobias S. Josefowitz 
3b87412016-07-27Henrik Grubbström (Grubba)  if (opts_or_file) { if (TYPEOF(*opts_or_file) == PIKE_T_MAPPING) { struct svalue *tmp; struct mapping *m = opts_or_file->u.mapping;
16a6f72011-11-27Tobias S. Josefowitz #define GET_TYPE(type, name) ((tmp = simple_mapping_string_lookup(m, name)) \ && (TYPEOF(*(tmp)) == PIKE_T_##type || (Pike_error("Expected type %s,"\
b5b29e2016-07-27Henrik Grubbström (Grubba)  "got type %s for " name ".", get_name_of_type(PIKE_T_##type), get_name_of_type(TYPEOF(*tmp))), 0)))
16a6f72011-11-27Tobias S. Josefowitz 
3b87412016-07-27Henrik Grubbström (Grubba)  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;
16a6f72011-11-27Tobias S. Josefowitz #undef GET_TYPE
3b87412016-07-27Henrik Grubbström (Grubba)  } else if (TYPEOF(*opts_or_file) == PIKE_T_STRING) { current_file = opts_or_file->u.string; }
16a6f72011-11-27Tobias S. Josefowitz  }
10ddf61999-02-27Henrik Grubbström (Grubba) 
e34dcf2004-05-22Martin Nilsson  this.data = data;
739f9d1999-11-04Henrik Grubbström (Grubba)  add_ref(data);
e34dcf2004-05-22Martin Nilsson  if(current_file) add_ref(current_file); else current_file = make_shared_string("-"); this.current_file = current_file;
739f9d1999-11-04Henrik Grubbström (Grubba) 
e34dcf2004-05-22Martin Nilsson  this.compat_major=PIKE_MAJOR_VERSION; this.compat_minor=PIKE_MINOR_VERSION; this.compat_handler = 0; this.handler = handler; if(handler) add_ref(handler); /* Don't call free_cpp before all variables are cleared or set. */ SET_ONERROR(err, free_cpp, &this);
16a6f72011-11-27Tobias S. Josefowitz  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 (!isalnum(prefix->str[i])) { Pike_error("Invalid char in prefix.\n"); } } this.prefix = prefix; add_ref(prefix); }
e34dcf2004-05-22Martin Nilsson  if(charset_sv) {
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(*charset_sv) == T_STRING) {
e34dcf2004-05-22Martin Nilsson  charset = charset_sv->u.string; push_string(data);
18c0fa2011-12-01Tobias S. Josefowitz  this.data = data = NULL;
e34dcf2004-05-22Martin Nilsson  ref_push_string(charset); 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", charset);
e34dcf2004-05-22Martin Nilsson  Pike_error("Unknown charset.\n");
739f9d1999-11-04Henrik Grubbström (Grubba)  }
e34dcf2004-05-22Martin Nilsson  this.data = data = sp[-1].u.string; sp--; dmalloc_touch_svalue(sp); }
017b572011-10-28Henrik Grubbström (Grubba)  else if(TYPEOF(*charset_sv) == T_INT)
e34dcf2004-05-22Martin Nilsson  auto_convert = charset_sv->u.integer; else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("cpp", 3, "string|int");
770b6d1999-02-23Henrik Grubbström (Grubba)  }
5740881998-01-01Fredrik Hübinette (Hubbe)  }
55eb581999-02-22Henrik Grubbström (Grubba) 
ddc1a32010-07-27Martin Stjernholm  if(compat_major)
e34dcf2004-05-22Martin Nilsson  cpp_change_compat(&this, compat_major, compat_minor);
569e072004-07-01Martin Nilsson 
ddc1a32010-07-27Martin Stjernholm  this.picky_cpp = picky_cpp;
b584b12001-12-20Martin Stjernholm  if (use_initial_predefs) /* Typically compiling the master here. */ predefs = initial_predefs_mapping(); else {
e34dcf2004-05-22Martin Nilsson  low_unsafe_apply_handler ("get_predefines", this.handler, this.compat_handler, 0);
b584b12001-12-20Martin Stjernholm  if (!UNSAFE_IS_ZERO (sp - 1)) { struct keypair *k; int e, sprintf_args = 0;
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(sp[-1]) != T_MAPPING) {
5e9fc02015-08-18Per Hedbor  push_static_text ("Invalid return value from get_predefines, got %O\n");
b584b12001-12-20Martin Stjernholm  push_svalue (sp - 3); sprintf_args = 2; } else { predefs = copy_mapping (sp[-1].u.mapping); 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);
9606eb2004-11-12Henrik Grubbström (Grubba)  Pike_error("%S", sp[-1].u.string);
b584b12001-12-20Martin Stjernholm  } } pop_stack(); }
770b6d1999-02-23Henrik Grubbström (Grubba)  if (auto_convert && (!data->size_shift) && (data->len > 1)) {
55eb581999-02-22Henrik Grubbström (Grubba)  /* Try to determine if we need to recode the string */
715e552003-11-14Martin Stjernholm  struct pike_string *new_data = recode_string(&this, data);
1c8da51999-02-24Henrik Grubbström (Grubba)  free_string(data);
e34dcf2004-05-22Martin Nilsson  this.data = data = new_data;
55eb581999-02-22Henrik Grubbström (Grubba)  }
770b6d1999-02-23Henrik Grubbström (Grubba)  if (data->size_shift) {
1c8da51999-02-24Henrik Grubbström (Grubba)  /* Get rid of any byte order marks (0xfeff) */ struct pike_string *new_data = filter_bom(data); free_string(data);
e34dcf2004-05-22Martin Nilsson  this.data = data = new_data;
e7d3901999-02-23Henrik Grubbström (Grubba)  }
770b6d1999-02-23Henrik Grubbström (Grubba) 
d9ac331999-02-22Henrik Grubbström (Grubba)  init_string_builder(&this.buf, 0);
ac87152000-09-25Fredrik Hübinette (Hubbe) 
51d3f32011-12-28Henrik Grubbström (Grubba)  /* These attempt to be compatible with the C standard. */
5740881998-01-01Fredrik Hübinette (Hubbe)  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);
51d3f32011-12-28Henrik Grubbström (Grubba) 
aba09a2011-12-28Henrik Grubbström (Grubba)  /* These are from the 201x C standard. */
51d3f32011-12-28Henrik Grubbström (Grubba)  do_magic_define(&this,"_Pragma",insert_pragma)->args = 1;
aba09a2011-12-28Henrik Grubbström (Grubba)  simple_add_define(&this, "static_assert", "_Static_assert");
51d3f32011-12-28Henrik Grubbström (Grubba) 
ce261a2014-08-26Per Hedbor  do_magic_define(&this,"__COUNTER__",insert_current_counter);
51d3f32011-12-28Henrik Grubbström (Grubba)  /* These are Pike extensions. */ do_magic_define(&this,"__DIR__",insert_current_dir_as_string);
a580e12000-09-27Fredrik Hübinette (Hubbe)  do_magic_define(&this,"__VERSION__",insert_current_version); do_magic_define(&this,"__MAJOR__",insert_current_major);
0d36ca2001-02-09Henrik Grubbström (Grubba)  do_magic_define(&this,"__MINOR__",insert_current_minor);
b3cc131998-01-15Fredrik Hübinette (Hubbe) 
f0950a1999-03-27Henrik Grubbström (Grubba)  {
82c6602008-04-04Henrik Grubbström (Grubba) #if 0 /* Left in place for documentation reference purposes. */
ef56c12008-03-27Henrik Grubbström (Grubba)  struct define *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, ")"); this.defines = hash_insert(this.defines, &def->link);
82c6602008-04-04Henrik Grubbström (Grubba) #endif /* 0 */
ef56c12008-03-27Henrik Grubbström (Grubba) 
f0950a1999-03-27Henrik Grubbström (Grubba)  simple_add_define(&this, "__PIKE__", " 1 ");
a580e12000-09-27Fredrik Hübinette (Hubbe)  simple_add_define(&this, "__REAL_VERSION__",
6598251999-12-08Henrik Grubbström (Grubba)  " " DEFINETOSTR(PIKE_MAJOR_VERSION) "." DEFINETOSTR(PIKE_MINOR_VERSION) " ");
a580e12000-09-27Fredrik Hübinette (Hubbe)  simple_add_define(&this, "__REAL_MAJOR__",
6598251999-12-08Henrik Grubbström (Grubba)  " " DEFINETOSTR(PIKE_MAJOR_VERSION) " ");
a580e12000-09-27Fredrik Hübinette (Hubbe)  simple_add_define(&this, "__REAL_MINOR__",
6598251999-12-08Henrik Grubbström (Grubba)  " " DEFINETOSTR(PIKE_MINOR_VERSION) " "); simple_add_define(&this, "__BUILD__", " " DEFINETOSTR(PIKE_BUILD_VERSION) " ");
a580e12000-09-27Fredrik Hübinette (Hubbe)  simple_add_define(&this, "__REAL_BUILD__", " " DEFINETOSTR(PIKE_BUILD_VERSION) " ");
5997151999-10-16Fredrik Noring  simple_add_define(&this, "__AUTO_BIGNUM__", " 1 ");
b3cc131998-01-15Fredrik Hübinette (Hubbe) #ifdef __NT__
f0950a1999-03-27Henrik Grubbström (Grubba)  simple_add_define(&this, "__NT__", " 1 ");
b3cc131998-01-15Fredrik Hübinette (Hubbe) #endif
bf2b451998-11-23Marcus Comstedt #ifdef __amigaos__
f0950a1999-03-27Henrik Grubbström (Grubba)  simple_add_define(&this, "__amigaos__", " 1 ");
74bf1a2006-04-22Henrik Grubbström (Grubba) #endif
9ace1e2013-03-16Chris Angelico #ifdef __OS2__ simple_add_define(&this, "__OS2__", " 1 "); #endif
74bf1a2006-04-22Henrik Grubbström (Grubba) #ifdef __APPLE__ simple_add_define(&this, "__APPLE__", " 1 ");
bf2b451998-11-23Marcus Comstedt #endif
6659502003-09-20Martin Nilsson  simple_add_define(&this, "SIZEOF_INT", " " DEFINETOSTR(SIZEOF_INT) " "); simple_add_define(&this, "SIZEOF_FLOAT", " " DEFINETOSTR(SIZEOF_FLOAT) " ");
f0950a1999-03-27Henrik Grubbström (Grubba)  }
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)
b584b12001-12-20Martin Stjernholm  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  { struct define *def; 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); def = alloc_empty_define( s, 0 ); def->magic = insert_callback_define; def->varargs=1; def->args=1; } else { def = alloc_empty_define( k->ind.u.string, 0 ); k->ind.u.string->refs++; def->magic = insert_callback_define_no_args; } this.defines = hash_insert( this.defines, &def->link ); }
b584b12001-12-20Martin Stjernholm  else
4edb1a2002-09-11David Hedbor  add_define (&this, k->ind.u.string, empty_pike_string);
b584b12001-12-20Martin Stjernholm  } free_mapping (predefs); }
5740881998-01-01Fredrik Hübinette (Hubbe) 
38e2962012-07-22Arne Goedeke  string_builder_binary_strcat(&this.buf, "#line 1 ", 8);
2dc0091999-02-27Henrik Grubbström (Grubba)  PUSH_STRING_SHIFT(this.current_file->str, this.current_file->len, this.current_file->size_shift, &this.buf);
d9ac331999-02-22Henrik Grubbström (Grubba)  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 */
ac87152000-09-25Fredrik Hübinette (Hubbe) 
58efb82014-05-12Per Hedbor  low_cpp(&this, MKPCHARP_STR(data), data->len,
a9a8dd1999-03-09Henrik Grubbström (Grubba)  0, auto_convert, charset);
57cef71999-12-28Henrik Grubbström (Grubba)  #ifdef PIKE_DEBUG UNSET_ONERROR(tmp); #endif /* PIKE_DEBUG */
e34dcf2004-05-22Martin Nilsson  UNSET_ONERROR(err); free_cpp(&this);
1c8da51999-02-24Henrik Grubbström (Grubba) 
5740881998-01-01Fredrik Hübinette (Hubbe)  if(this.compile_errors) {
d9ac331999-02-22Henrik Grubbström (Grubba)  free_string_builder(&this.buf);
db14502008-05-27Henrik Grubbström (Grubba)  throw_error_object(fast_clone_object(cpp_error_program), 0, 0, 0,
010dc62001-08-16Martin Stjernholm  "Cpp() failed\n");
9565132014-02-14Martin Nilsson  } else if(this.dependencies_fail) { free_string_builder(&this.buf);
19e5162014-02-21Martin Nilsson  pop_n_elems(sp - save_sp);
9565132014-02-14Martin Nilsson  push_int(0); } else {
770b6d1999-02-23Henrik Grubbström (Grubba)  pop_n_elems(sp - save_sp);
d9ac331999-02-22Henrik Grubbström (Grubba)  push_string(finish_string_builder(&this.buf));
5740881998-01-01Fredrik Hübinette (Hubbe)  } }
6c3a6f2013-11-20Henrik Grubbström (Grubba) /*! @module Builtin */ /*! @decl mapping(string:mixed) _take_over_initial_predefines() */
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); free(tmp->value); 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;
5740881998-01-01Fredrik Hübinette (Hubbe)  defined_macro=alloc_empty_define(make_shared_string("defined"),0); defined_macro->magic=check_defined; defined_macro->args=1;
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 
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);
5aa54c2014-09-03Martin Nilsson  char * pos=strchr(s,'=');
5740881998-01-01Fredrik Hübinette (Hubbe)  if(pos) {
dc8d022014-04-27Martin Nilsson  tmp->name=xalloc(pos-s+1);
59fc9e2014-09-03Martin Nilsson  memcpy(tmp->name,s,pos-s);
5740881998-01-01Fredrik Hübinette (Hubbe)  tmp->name[pos-s]=0;
dc8d022014-04-27Martin Nilsson  tmp->value=xalloc(s+strlen(s)-pos);
59fc9e2014-09-03Martin Nilsson  memcpy(tmp->value,pos+1,s+strlen(s)-pos);
5740881998-01-01Fredrik Hübinette (Hubbe)  }else{
dc8d022014-04-27Martin Nilsson  tmp->name=xalloc(strlen(s)+1);
59fc9e2014-09-03Martin Nilsson  memcpy(tmp->name,s,strlen(s)+1);
5740881998-01-01Fredrik Hübinette (Hubbe) 
dc8d022014-04-27Martin Nilsson  tmp->value=xalloc(4);
59fc9e2014-09-03Martin Nilsson  memcpy(tmp->value," 1 ",4);
5740881998-01-01Fredrik Hübinette (Hubbe)  }
b584b12001-12-20Martin Stjernholm  tmp->next = NULL; 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); free(tmp->value);
b584b12001-12-20Martin Stjernholm  first_predef=tmp->next;
0ec7522014-04-27Martin Nilsson  free(tmp);
5740881998-01-01Fredrik Hübinette (Hubbe)  }
61e9a01998-01-25Fredrik Hübinette (Hubbe)  free_string(defined_macro->link.s);
0ec7522014-04-27Martin Nilsson  free(defined_macro);
5164822004-11-14Martin Stjernholm  free_string (efun_str); free_string (constant_str); free_string (defined_str);
ae95031999-04-07Fredrik Hübinette (Hubbe) #endif
5740881998-01-01Fredrik Hübinette (Hubbe) }