pike.git / src / cpp.cmod

version» Context lines:

pike.git/src/cpp.cmod:79:   };      static int use_initial_predefs;   static struct pike_predef_s *first_predef = NULL, *last_predef = NULL;      struct define_argument {    PCHARP arg;    ptrdiff_t len;   };    - struct cpp; + struct CPP_struct;   struct define_struct; - typedef void (*magic_define_fun)(struct cpp *, + typedef void (*magic_define_fun)(struct CPP_struct *,    struct define_struct *,    struct pike_string *,    struct string_builder *);      DECLARATIONS;      #define CPP_MACRO_DISABLED 1 /* Don't expand. */   #define CPP_MACRO_IN_USE 2 /* In use. */      PIKECLASS define
pike.git/src/cpp.cmod:114:    struct define_struct *def = (struct define_struct *)CURRENT_STORAGE;    def->args=-1;   #ifdef PIKE_NULL_IS_SPECIAL    def->magic=0;    def->flags = 0;    def->varargs=0;   #endif    }   }    - struct cpp + PIKECLASS CPP   { -  struct mapping *defines; -  INT_TYPE current_line; -  INT32 compile_errors; -  struct pike_string *current_file; -  struct string_builder buf; -  struct object *handler; -  struct object *compat_handler; -  INT_TYPE compat_major; -  INT_TYPE compat_minor; -  struct pike_string *data; -  struct pike_string *prefix; -  INT_TYPE picky_cpp, keep_comments, dependencies_fail; - }; +  PIKEVAR mapping(string:object(define)) defines flags ID_PRIVATE|ID_PROTECTED; +  PIKEVAR int current_line; +  PIKEVAR int compile_errors; +  PIKEVAR string current_file; +  PIKEVAR string charset; +  CVAR struct string_builder buf; +  PIKEVAR object handler; +  PIKEVAR object compat_handler; +  PIKEVAR int compat_major; +  PIKEVAR int compat_minor; +  /* NB: data is marked private to ensure that pike level code can't +  * remove its references while we hold pointers into it. +  */ +  PIKEVAR string data flags ID_PRIVATE|ID_PROTECTED; +  PIKEVAR string prefix; +  PIKEVAR int picky_cpp; +  PIKEVAR int keep_comments; +  PIKEVAR int dependencies_fail; +  PIKEVAR int auto_convert;    -  +  PIKEVAR mapping(string:function(string:string)) directives flags ID_PROTECTED; +  +  INIT +  { +  init_string_builder(&THIS->buf, 0); +  } +  +  EXIT +  { +  /* NOTE: Most of the fields are mapped, and thus freed automatically. */ +  +  if (THIS->buf.s) { +  free_string_builder(&THIS->buf); +  } +  } +    #define FIND_DEFINE(N) find_define(this, (N))    - static struct define_struct *find_define(struct cpp *this, struct pike_string *n) + static struct define_struct *find_define(struct CPP_struct *this, struct pike_string *n)   {    struct svalue *s;    if (!this->defines) return NULL;    if (!(s = low_mapping_string_lookup(this->defines, n))) return NULL;    if (TYPEOF(*s) != T_OBJECT) return NULL;    return (struct define_struct *)get_storage(s->u.object, define_program);   }    - static void cpp_error(struct cpp *this, const char *err) ATTRIBUTE((noinline)); - static void cpp_error_vsprintf (struct cpp *this, const char *fmt, + static void cpp_error(struct CPP_struct *this, const char *err) ATTRIBUTE((noinline)); + static void cpp_error_vsprintf (struct CPP_struct *this, const char *fmt,    va_list args) ATTRIBUTE((noinline)); - static void cpp_error_sprintf(struct cpp *this, const char *fmt, ...) ATTRIBUTE((noinline)); - static void cpp_handle_exception(struct cpp *this, + static void cpp_error_sprintf(struct CPP_struct *this, const char *fmt, ...) ATTRIBUTE((noinline)); + static void cpp_handle_exception(struct CPP_struct *this,    const char *cpp_error_fmt, ...) ATTRIBUTE((noinline)); - static void cpp_warning(struct cpp *this, const char *cpp_warn_fmt, ...) ATTRIBUTE((noinline)); + static void cpp_warning(struct CPP_struct *this, const char *cpp_warn_fmt, ...) ATTRIBUTE((noinline));   struct define_struct *defined_macro = NULL;   static struct svalue defined_macro_sval;    - static void cpp_error(struct cpp *this, const char *err) + static void cpp_error(struct CPP_struct *this, const char *err)   {    this->compile_errors++;    if(this->compile_errors > 10) return;    if((this->handler && this->handler->prog) || get_master())    {    ref_push_string(this->current_file);    push_int(this->current_line);    push_text(err);    low_safe_apply_handler("compile_error", this->handler,    this->compat_handler, 3);    pop_stack();    }else{    (void)fprintf(stderr, "%s:%ld: %s\n",    this->current_file->str,    (long)this->current_line,    err);    fflush(stderr);    }   }    - static void cpp_error_vsprintf (struct cpp *this, const char *fmt, + static void cpp_error_vsprintf (struct CPP_struct *this, const char *fmt,    va_list args)   {    struct string_builder s;    struct pike_string *msg;       this->compile_errors++;    if (this->compile_errors > 10) return;       init_string_builder(&s, 0);   
pike.git/src/cpp.cmod:214:       if (!msg->size_shift) {    fprintf(stderr, "%s\n", msg->str);    } else {    fprintf(stderr, "WIDE (fmt: %s)\n", fmt);    }    free_string(msg);    fflush(stderr);   }    - static void cpp_error_sprintf(struct cpp *this, const char *fmt, ...) + static void cpp_error_sprintf(struct CPP_struct *this, const char *fmt, ...)   {    va_list args;    va_start(args,fmt);    cpp_error_vsprintf (this, fmt, args);    va_end(args);   }    - static void cpp_handle_exception(struct cpp *this, + static void cpp_handle_exception(struct CPP_struct *this,    const char *cpp_error_fmt, ...)   {    struct svalue thrown;    move_svalue (&thrown, &throw_value);    mark_free_svalue (&throw_value);       if (cpp_error_fmt) {    va_list args;    va_start (args, cpp_error_fmt);    cpp_error_vsprintf (this, cpp_error_fmt, args);
pike.git/src/cpp.cmod:252:    if (s) {    cpp_error_sprintf(this, "%S", s);    free_string (s);    }    }       pop_stack();    free_svalue(&thrown);   }    - static void cpp_warning(struct cpp *this, const char *cpp_warn_fmt, ...) + static void cpp_warning(struct CPP_struct *this, const char *cpp_warn_fmt, ...)   {    struct string_builder sb;    va_list args;       init_string_builder (&sb, 0);    va_start(args, cpp_warn_fmt);    string_builder_vsprintf (&sb, cpp_warn_fmt, args);    va_end(args);       if((this->handler && this->handler->prog) || get_master())
pike.git/src/cpp.cmod:483:      /*! @endclass    */      /*! @namespace predef:: */   /*! @decl import cpp:: */   /*! @endnamespace */      /* #pike handling. */    - void cpp_change_compat(struct cpp *this, int major, int minor) + void cpp_change_compat(struct CPP_struct *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 &&
pike.git/src/cpp.cmod:574:    */      /*! @directive #ifdef    *!    *! Check whether an identifier is a macro.    *!    *! The directive    *!    *! @tt{#ifdef @i{<identifier>@}@}    *! -  *! is equvivalent to +  *! is equivalent 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 +  *! is equivalent to    *!    *! @tt{#if !@[defined](@i{<identifier>@})@}    *!    *! @seealso    *! @[#if], @[#ifdef], @[defined]    */      /*! @directive #require    *!    *! If the directive evaluates to false, the source file will be
pike.git/src/cpp.cmod:649:    */      /*! @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: +  *! The following two are equivalent:    *!    *! @code    *! #ifdef A    *! // Code for A.    *! #else    *! #ifdef B    *! // Code for B.    *! #else    *! #ifdef C    *! // Code for C.
pike.git/src/cpp.cmod:707:    *! @example    *! @code    *! #if !constant(Yp)    *! #error Support for NIS not available.    *! #endif    *! @endcode    *!    *! @seealso    *! @[#warning]    */ +  PIKEFUN string(0..0) directive_error(int flags, string line) +  { +  struct CPP_struct *this = THIS;    -  +  if (OUTP()) { +  cpp_error_sprintf(this, "%O", Pike_sp - 1); +  } +  push_empty_string(); +  } +    /*! @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]    */ -  +  PIKEFUN string(0..0) directive_warning(int flags, string line) +  { +  struct CPP_struct *this = THIS;    -  +  if (OUTP()) { +  cpp_warning(this, "%O", Pike_sp - 1); +  } +  push_empty_string(); +  } +    /*! @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"@}.
pike.git/src/cpp.cmod:883:      /*! @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{#if defined(MY_DEF)@} is equivalent to    *! @tt{#ifdef MY_DEF@}.    *!    *! @seealso    *! @[#if], @[#ifdef], @[constant()]    */ - static void check_defined(struct cpp *this, + static void check_defined(struct CPP_struct *this,    struct define_struct *UNUSED(def),    struct pike_string *arg,    struct string_builder *tmp)   {    if(arg && FIND_DEFINE(arg))    string_builder_binary_strcat(tmp, " 1 ", 3);    else    string_builder_binary_strcat(tmp, " 0 ", 3);   }    - static int do_safe_index_call(struct cpp *this, struct pike_string *s) + static int do_safe_index_call(struct CPP_struct *this, struct pike_string *s)   {    int res;    JMP_BUF recovery;    if(!s) return 0;       if (SETJMP_SP(recovery, 1)) {    if(this->picky_cpp)    cpp_warning (this, "Error indexing module with %S.", s);    res = 0;    push_undefined();
pike.git/src/cpp.cmod:929:   }      /*! @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) + static void cpp_constant(struct CPP_struct *this, int value)   {    struct svalue *save_stack=Pike_sp;    struct array *arr;    INT_TYPE res = 0;    int n;       /* FIXME: Protection against errors. */    /* Remove extra whitespace. */    push_static_text(" ");    o_subtract();
pike.git/src/cpp.cmod:1060:    for (def = first_predef; def; def = def->next) {    struct pike_string *name = make_shared_string(def->name);    struct pike_string *value = make_shared_string(def->value);    mapping_string_insert_string(map, name, value);    free_string(value);    free_string(name);    }    return map;   }    - static p_wchar2 readchar( PCHARP data, ptrdiff_t *pos, struct cpp *this ) + static p_wchar2 readchar( PCHARP data, ptrdiff_t *pos, struct CPP_struct *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:
pike.git/src/cpp.cmod:1101:    break;   #ifdef PIKE_DEBUG    case 2: Pike_fatal ("Not supposed to happen.\n");    default: Pike_fatal ("Unknown error from parse_esc_seq.\n");   #endif    }    return C;   }       - static ptrdiff_t readstring( struct cpp *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos, + static ptrdiff_t readstring( struct CPP_struct *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos,    struct string_builder*nf, int nl_ok)   {    while(1)    {    pos++;    if(pos>=len)    {    cpp_error(this,"End of file in string.");    break;    }
pike.git/src/cpp.cmod:1154:    default:    string_builder_putchar(nf, INDEX_PCHARP(data,pos));    continue;    }    pos++;    break;    }    return pos;   }    - static ptrdiff_t readstring_lit( struct cpp *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos, + static ptrdiff_t readstring_lit( struct CPP_struct *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos,    struct string_builder*nf, INT32 ec)   {    INT32 ch;    while(1) {    if(++pos>=len) {    cpp_error(this,"End of file in string.");    break;    }    if((ch=INDEX_PCHARP(data,pos)) == '#' && INDEX_PCHARP(data,pos+1)==ec)    return pos + 2;
pike.git/src/cpp.cmod:1176:    if (ch == '\n') {    this->current_line++;    PUTNL();    }    string_builder_putchar(nf, ch);    }    }    return pos;   }    - static ptrdiff_t fixstring(struct cpp *this, const PCHARP data, ptrdiff_t len, + static ptrdiff_t fixstring(struct CPP_struct *this, const PCHARP data, ptrdiff_t len,    ptrdiff_t pos, struct string_builder *nf, int outp)   {    int trailing_newlines=0;    if(outp) string_builder_putchar(nf, '"');    while(1)    {    if(pos>=len)    {    cpp_error(this,"End of file in string.");    break;
pike.git/src/cpp.cmod:1225:    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;   }    - static ptrdiff_t find_end_of_line( struct cpp *this, const PCHARP data, + static ptrdiff_t find_end_of_line( struct CPP_struct *this, const PCHARP data,    ptrdiff_t len, ptrdiff_t pos, int emit )   {    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') &&
pike.git/src/cpp.cmod:1250:    continue;    }    this->current_line++;    if( emit ) PUTNL();    }    }    return pos;   }       - static ptrdiff_t find_end_of_comment( struct cpp *this, const PCHARP data, ptrdiff_t len, + static ptrdiff_t find_end_of_comment( struct CPP_struct *this, const PCHARP data, ptrdiff_t len,    ptrdiff_t pos, int emit)   {    pos++;       while(INDEX_PCHARP(data,pos)!='*' || INDEX_PCHARP(data,pos+1)!='/')    {    if(pos+2>=len)    {    cpp_error(this,"End of file in comment.");    break;
pike.git/src/cpp.cmod:1273:    if(INDEX_PCHARP(data,pos)=='\n')    {    this->current_line++;    if( emit )PUTNL();    }    pos++;    }    return pos + 2;   }    - static ptrdiff_t find_end_quote(struct cpp *this, const PCHARP data, + static ptrdiff_t find_end_quote(struct CPP_struct *this, const PCHARP data,    ptrdiff_t len, ptrdiff_t pos,    p_wchar2 quote, int flags)   {    while(1)    {    p_wchar2 c;       if(pos>=len)    {    if (quote == '\'') {
pike.git/src/cpp.cmod:1323:    pos++;    PUTNL();    }    pos++;    }    }    return pos;   }       - static ptrdiff_t find_end_brace(struct cpp *this, + static ptrdiff_t find_end_brace(struct CPP_struct *this,    PCHARP data,    ptrdiff_t len,    ptrdiff_t pos);    - static ptrdiff_t find_end_parenthesis(struct cpp *this, + static ptrdiff_t find_end_parenthesis(struct CPP_struct *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)    {
pike.git/src/cpp.cmod:1365:    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, + static ptrdiff_t find_end_brace(struct CPP_struct *this,    const PCHARP data,    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)    {
pike.git/src/cpp.cmod:1400:    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);    }    }    }   }    - static struct pike_string *gobble_identifier (struct cpp *this, const PCHARP data, ptrdiff_t *pos) + static struct pike_string *gobble_identifier (struct CPP_struct *this, const PCHARP data, ptrdiff_t *pos)   {    ptrdiff_t p = *pos;    struct string_builder sb;    p_wchar2 tmp;    if( !wide_isidchar( tmp = INDEX_PCHARP(data,*pos)) && tmp != '\\' )    return NULL;       init_string_builder (&sb, 0); /* in fact, 0 is more likely than data.shift */       while (1) {
pike.git/src/cpp.cmod:1521:    *!    *! @example    *! // Strip debug    *! #define werror(X ...) 0    *! #include "/home/someone/experimental/stuff.h"    *! #undef werror    *!    *! @seealso    *! @[#define], @[defined()]    */ - static void undefine(struct cpp *this, struct pike_string *name) + static void undefine(struct CPP_struct *this, struct pike_string *name)   {    ref_push_string(name);    push_int(0);    map_delete_no_free(this->defines, Pike_sp - 2, Pike_sp - 1);       if (TYPEOF(Pike_sp[-1]) == PIKE_T_OBJECT) {    struct object *o = Pike_sp[-1].u.object;    struct define_struct *def = (struct define_struct *)get_storage(o, define_program);    if (def->flags & (CPP_MACRO_IN_USE | CPP_MACRO_DISABLED)) {    /* Restore the #define. */
pike.git/src/cpp.cmod:1568:    *! #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@}.    */    - static struct pike_string *make_define_name(struct cpp *this, + static struct pike_string *make_define_name(struct CPP_struct *this,    const char *name)   {    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); +  string_builder_strcat(&s, name);    return finish_string_builder(&s);    }    return make_shared_string(name);   }    - static struct define_struct *do_magic_define(struct cpp *this, + static struct define_struct *do_magic_define(struct CPP_struct *this,    const char *name,    magic_define_fun fun)   {    struct define_struct* def;    struct pike_string *name_str = make_define_name(this, name);    def = alloc_empty_define(name_str);    free_string(name_str);    def->magic=fun;    mapping_string_insert(this->defines, def->name, Pike_sp-1);    pop_stack();    return def;   }    - static void add_define(struct cpp *this, + static void add_define(struct CPP_struct *this,    struct pike_string *name,    struct pike_string *what)   {    struct define_struct* def;    def=alloc_empty_define(name);    ref_push_string(what);    f_aggregate(1);    def->parts = Pike_sp[-1].u.array;    Pike_sp--;    mapping_string_insert(this->defines, def->name, Pike_sp-1);    pop_stack();   }    - static void simple_add_define(struct cpp *this, + static void simple_add_define(struct CPP_struct *this,    const char *name,    const char *what)   {       struct pike_string *name_str = make_define_name(this, name);    struct pike_string *what_str = make_shared_string(what);    add_define(this, name_str, what_str);    free_string(what_str);    free_string(name_str);   }    - static struct pike_string *recode_string(struct cpp *this, struct pike_string *data) + static struct pike_string *recode_string(struct CPP_struct *this, struct pike_string *data)   {    /* 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:    *
pike.git/src/cpp.cmod:1960:   static void add_quoted_string( const void *str, ptrdiff_t len, int shift,    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);   }    - static ptrdiff_t find_eos( struct cpp *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos ) + static ptrdiff_t find_eos( struct CPP_struct *this, const PCHARP data, ptrdiff_t len, ptrdiff_t pos )   {    while(pos < len)    {    switch (DATA(pos++)) {    case '\n':    break;    case '/':    if (DATA(pos) == '/') {    pos = find_end_of_line(this,data,len,pos,0);    break;
pike.git/src/cpp.cmod:1994:    this->current_line++;    default:    continue;    }    this->current_line++;    break;    }    return pos;   }    - static ptrdiff_t skipwhite(struct cpp *this, const PCHARP data, ptrdiff_t pos) + static ptrdiff_t skipwhite(struct CPP_struct *this, const PCHARP data, ptrdiff_t pos)   {    do    {    int c;    if(!wide_isspace(c=DATA(pos)))    {    if (c == '\\')    {    if (DATA(pos+1) == '\n')    {
pike.git/src/cpp.cmod:2028:    }    else if(c=='\n')    {    PUTNL(); this->current_line++;    }    pos++;    } while(1);    return pos;   }    - static ptrdiff_t skipspace(struct cpp *this, const PCHARP data, ptrdiff_t pos, int emit) + static ptrdiff_t skipspace(struct CPP_struct *this, const PCHARP data, ptrdiff_t pos, int emit)   {    do {    int c;    while (wide_isspace(c=DATA(pos)) && c!='\n') {    pos++;    }    if (c == '\\') {    if (DATA(pos+1) == '\n') {    pos+=2;    } else if ((DATA(pos+1) == '\r') &&
pike.git/src/cpp.cmod:2074:   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_[] = { '>', '>' };      static int begins_with( const char *prefix, const PCHARP stack, int len, int remain, int whole )   {    int i;    if( len > remain )    return 0;       for( i=0; i<len; i++ )    if( INDEX_PCHARP(stack,i) != prefix[i] )    return 0;       if( whole && len != remain && wide_isidchar(INDEX_PCHARP(stack,len)) )    return 0;       return 1;   }    - static ptrdiff_t low_cpp(struct cpp *this, + static ptrdiff_t low_cpp(struct CPP_struct *this,    PCHARP data,    ptrdiff_t len,    int flags, -  int auto_convert, +     struct pike_string *charset); - static void insert_callback_define(struct cpp *this, + static void insert_callback_define(struct CPP_struct *this,    struct define_struct *def,    struct pike_string *arg,    struct string_builder *tmp); - static void insert_callback_define_no_args(struct cpp *this, + static void insert_callback_define_no_args(struct CPP_struct *this,    struct define_struct *def,    struct pike_string *arg,    struct string_builder *tmp); - static void insert_pragma(struct cpp *this, + static void insert_pragma(struct CPP_struct *this,    struct define_struct *def,    struct pike_string *arg,    struct string_builder *tmp);    - static ptrdiff_t calc1(struct cpp *this, PCHARP data, ptrdiff_t len, + static ptrdiff_t calc1(struct CPP_struct *this, PCHARP data, ptrdiff_t len,    ptrdiff_t pos, int flags);    - static ptrdiff_t calcC(struct cpp *this, PCHARP data, ptrdiff_t len, + static ptrdiff_t calcC(struct CPP_struct *this, PCHARP data, ptrdiff_t len,    ptrdiff_t pos, int flags)   {    SKIPWHITE();       CALC_DUMPPOS("calcC");       switch(DATA(pos))    {    case '(':    pos=calc1(this,data,len,pos+1,flags);
pike.git/src/cpp.cmod:2362:    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, + static ptrdiff_t calcB(struct CPP_struct *this, PCHARP data, ptrdiff_t len,    ptrdiff_t pos, int flags)   {    CALC_DUMPPOS("before calcB");       SKIPWHITE();    switch(DATA(pos))    {    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, + static ptrdiff_t calcA(struct CPP_struct *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();    switch(DATA(pos))
pike.git/src/cpp.cmod:2424:    if(OUTP())    o_mod();    continue;    }    break;    }    CALC_DUMPPOS("after calcA");    return pos;   }    - static ptrdiff_t calc9(struct cpp *this, PCHARP data, ptrdiff_t len, + static ptrdiff_t calc9(struct CPP_struct *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();
pike.git/src/cpp.cmod:2458:    o_subtract();    continue;    }    break;    }       CALC_DUMPPOS("after calc9");    return pos;   }    - static ptrdiff_t calc8(struct cpp *this, PCHARP data, ptrdiff_t len, + static ptrdiff_t calc8(struct CPP_struct *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();
pike.git/src/cpp.cmod:2492:    if(OUTP())    o_rsh();    break;    }       break;    }    return pos;   }    - static ptrdiff_t calc7b(struct cpp *this, PCHARP data, ptrdiff_t len, + static ptrdiff_t calc7b(struct CPP_struct *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");   
pike.git/src/cpp.cmod:2542:    if(OUTP())    f_gt(2);    }    continue;    }    break;    }    return pos;   }    - static ptrdiff_t calc7(struct cpp *this, PCHARP data, ptrdiff_t len, + static ptrdiff_t calc7(struct CPP_struct *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");   
pike.git/src/cpp.cmod:2575:    if(OUTP())    f_ne(2);    continue;    }       break;    }    return pos;   }    - static ptrdiff_t calc6(struct cpp *this, PCHARP data, ptrdiff_t len, + static ptrdiff_t calc6(struct CPP_struct *this, PCHARP data, ptrdiff_t len,    ptrdiff_t pos, int flags)   {    CALC_DUMPPOS("before calc6");       pos=calc7(this,data,len,pos,flags);       SKIPWHITE();    while(DATA(pos) == '&' && DATA(pos+1)!='&')    {    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, + static ptrdiff_t calc5(struct CPP_struct *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, + static ptrdiff_t calc4(struct CPP_struct *this, PCHARP data, ptrdiff_t len,    ptrdiff_t pos, int flags)   {    CALC_DUMPPOS("before calc4");       pos=calc5(this,data,len,pos,flags);       SKIPWHITE();    while(DATA(pos) == '|' && DATA(pos+1)!='|')    {    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, + static ptrdiff_t calc3(struct CPP_struct *this, PCHARP data, ptrdiff_t len,    ptrdiff_t pos, int flags)   {       CALC_DUMPPOS("before calc3");       pos=calc4(this,data,len,pos,flags);       SKIPWHITE();    while(HAS_PREFIX(land_))    {
pike.git/src/cpp.cmod:2661:    }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, + static ptrdiff_t calc2(struct CPP_struct *this, PCHARP data, ptrdiff_t len,    ptrdiff_t pos, int flags)   {       CALC_DUMPPOS("before calc2");       pos=calc3(this,data,len,pos,flags);       SKIPWHITE();    while(HAS_PREFIX(lor_))    {
pike.git/src/cpp.cmod:2689:    }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, + static ptrdiff_t calc1(struct CPP_struct *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('?'))    {
pike.git/src/cpp.cmod:2714:    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, + static ptrdiff_t calc(struct CPP_struct *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.");
pike.git/src/cpp.cmod:2795:    e = 0;    } else {    e++;    }    }    if (l) {    string_builder_append(s,a,l);    }   }    - static void apply_define(struct cpp *this, + static void apply_define(struct CPP_struct *this,    struct define_struct *d,    struct define_argument *arguments, -  short flags, short auto_convert, +  short flags,    struct pike_string *charset)   {    struct string_builder tmp;       init_string_builder(&tmp, 0);    if(d->magic)    {    int i;    struct pike_string *a = NULL;    if (d->args > 0) {
pike.git/src/cpp.cmod:2873:    string_builder_append( &tmp, a, l );    }else{    struct string_builder save;    INT_TYPE line = this->current_line;    /* FIXME: Shouldn't we save current_file too? */    save=this->buf;    this->buf=tmp;    d->flags = CPP_MACRO_IN_USE;    low_cpp(this, a, l,    flags & ~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE), -  auto_convert, charset); +  charset);    d->flags = flags;    tmp=this->buf;    this->buf=save;    this->current_line=line;    }    }       if(!(argument & DEF_ARG_NOPOSTSPACE))    string_builder_putchar(&tmp, ' ');    }
pike.git/src/cpp.cmod:2910:    SET_INDEX_CHARP(tmp.s->str,e,tmp.s->size_shift,' ');    }       d->flags = CPP_MACRO_DISABLED;    /* FIXME: Ought to add a ref to d here. */       string_builder_putchar(&tmp, 0);    tmp.s->len--;    low_cpp(this, MKPCHARP_STR(tmp.s),tmp.s->len,    flags & ~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE), -  auto_convert, charset); +  charset);       d->flags = flags;    /* FIXME: Ought to free the ref to d here. */       free_string_builder(&tmp);   }    - #include "preprocessor.h" + /* +  * Preprocessor template. +  * +  */ + static ptrdiff_t low_cpp(struct CPP_struct *this, +  PCHARP data, +  ptrdiff_t len, +  int flags, +  struct pike_string *charset) + { +  ptrdiff_t pos, tmp, e; +  int include_mode; +  INT_TYPE first_line = this->current_line; +  /* FIXME: What about this->current_file? */    -  +  for(pos=0; pos<len;) +  { +  ptrdiff_t old_pos = pos; +  int c; + /* fprintf(stderr,"%c",DATA(pos)); +  fflush(stderr); */ +  +  switch(c = DATA(pos++)) +  { +  case '\n': +  if(flags & CPP_END_AT_NEWLINE) return pos-1; +  + /* fprintf(stderr,"CURRENT LINE: %d\n",this->current_line); */ +  this->current_line++; +  PUTNL(); +  goto do_skipwhite; +  +  case 0x1b: case 0x9b: /* ESC or CSI */ +  /* Assume ANSI/DEC escape sequence. +  * Format supported: +  * <ESC>[\040-\077]+[\100-\177] +  * or +  * <CSI>[\040-\077]*[\100-\177] +  */ +  /* FIXME: This place is far from enough to make these things +  * behave as whitespace. /mast */ +  while ((tmp = DATA(pos)) && (tmp == ((tmp & 0x1f)|0x20))) { +  pos++; +  } +  if (tmp == ((tmp & 0x3f)|0x40)) { +  pos++; +  } else { +  /* FIXME: Warning here? */ +  } +  +  PUTC(' '); +  break; +  +  case '\t': +  case ' ': +  case '\r': +  PUTC(' '); +  +  do_skipwhite: +  while( wide_isspace(c=DATA(pos)) && c != '\n' && c != '\r' ) +  pos++; +  break; +  +  /* Minor optimization */ +  case '<': case '=': case '>': +  if(DATA(pos)==c && +  DATA(pos+1)==c && +  DATA(pos+2)==c && +  DATA(pos+3)==c && +  DATA(pos+4)==c && +  DATA(pos+5)==c) { +  cpp_error(this, "Merge conflict detected."); +  PUTC(c); +  do { +  PUTC(c); +  } while (DATA(++pos) == c); +  continue; +  } +  /* FALL_THROUGH */ +  +  case '!': case '@': case '$': case '%': case '^': case '&': +  case '*': case '(': case ')': case '-': case '+': +  case '{': case '}': case ':': case '?': case '`': case ';': +  case ',': case '.': case '~': case '[': case ']': case '|': +  PUTC(DATA(pos-1)); +  break; +  +  case '\\': +  if(DATA(pos)=='\n') { +  pos++; +  this->current_line++; +  PUTNL(); +  goto do_skipwhite; +  } +  else if ((DATA(pos) == '\r') && (DATA(pos+1) == '\n')) { +  pos += 2; +  this->current_line++; +  PUTNL(); +  goto do_skipwhite; +  } +  /* Fall through - identifiers might begin with \uxxxx. */ +  +  default: +  if(OUTP()) +  { +  struct pike_string *s; +  struct define_struct *d = NULL; +  +  pos--; +  s = GOBBLE_IDENTIFIER(); +  if (!s) { +  PUTC (DATA(pos++)); +  break; +  } +  +  if(flags & CPP_DO_IF && s == defined_str) +  { +  /* NOTE: defined() must be handled here, since its argument +  * must not be macro expanded. +  */ +  d = defined_macro; +  }else{ +  d=FIND_DEFINE(s); +  } +  +  if(d && !(d->flags & CPP_MACRO_DISABLED)) +  { +  int arg=0; +  INT_TYPE start_line = this->current_line; +  struct string_builder tmp; +  struct define_argument arguments[ MAX_ARGS]; +  short flags = d->flags; +  +  if (d == defined_macro) { +  free_string (s); +  s = NULL; +  } +  +  if(d->args>=0) +  { +  SKIPWHITE(); +  +  if(!GOBBLE('(')) +  { +  if (s) { +  string_builder_shared_strcat(&this->buf,s); +  free_string(s); +  } +  /* Restore the post-whitespace. */ +  string_builder_putchar(&this->buf, ' '); +  break; +  } +  +  for(arg=0;arg<d->args;arg++) +  { +  if(arg && DATA(pos)==',') +  { +  pos++; +  SKIPWHITE(); +  }else{ +  SKIPWHITE(); +  if(DATA(pos)==')') +  { +  if((d->varargs && arg + 1 == d->args) || +  (!arg && (d->args == 1))) { +  /* Allow varargs to be left out. +  * +  * Allow a single argument to be left out. +  */ +  arguments[arg].arg = ADD_PCHARP(data,pos); +  arguments[arg].len=0; +  continue; +  }else{ +  cpp_error_sprintf(this, +  "Too few arguments to macro %S, expected %d.", +  d->name, d->args); +  break; +  } +  } +  } +  arguments[arg].arg = ADD_PCHARP(data,pos); +  +  while(1) +  { +  if(pos+1>len) +  { +  INT_TYPE save_line = this->current_line; +  this->current_line = start_line; +  cpp_error(this, "End of file in macro call."); +  this->current_line = save_line; +  break; +  } +  +  switch(DATA(pos++)) +  { +  case '\n': +  this->current_line++; +  PUTNL(); +  default: continue; +  +  case '"': +  /* Note: Strings may contain \-escaped newlines. +  * They must be removed on insertion to +  * avoid being counted twice. +  */ +  if(DATA(pos-2)!='#') { +  FIND_END_OF_STRING(CPP_END_AT_NEWLINE); +  }else{ +  FIND_END_OF_STRING(0); /* Newlines allowed */ +  } +  continue; +  +  case '\'': +  FIND_END_OF_CHAR(); +  continue; +  +  case '/': +  if (DATA(pos) == '*') { +  pos++; +  if (this->keep_comments) { +  SKIPCOMMENT_INC_LINES(); +  goto ADD_TO_BUFFER; +  } +  SKIPCOMMENT(); +  } else if (DATA(pos) == '/') { +  if (this->keep_comments) { +  FIND_EOL_PRETEND(); +  goto ADD_TO_BUFFER; +  } +  FIND_EOL(); +  } +  continue; +  +  case '(': +  pos=find_end_parenthesis(this, data, len, pos); +  continue; +  +  case '{': +  pos=find_end_brace(this, data, len, pos); +  continue; +  +  case ',': +  if(d->varargs && arg+1 == d->args) continue; +  /* FALL_THROUGH */ +  +  case ')': +  pos--; +  break; +  } +  break; +  } +  arguments[arg].len = SUBTRACT_PCHARP(ADD_PCHARP(data,pos),arguments[arg].arg); +  } +  SKIPWHITE(); +  if(!GOBBLE(')')) { +  this->current_line = start_line; +  cpp_error_sprintf(this, "Missing ) in the macro %S.", d->name); +  } +  } +  +  if(d->args >= 0 && arg != d->args) +  cpp_error(this, "Wrong number of arguments to macro."); +  +  /* NB: If there have been errors in the loop above, arguments may +  * remain (partially) uninitialized. +  */ +  if (!this->compile_errors) { +  apply_define(this, d, arguments, flags, charset); +  } +  }else{ +  if (OUTP()) +  string_builder_shared_strcat (&this->buf, s); +  } +  if (s) { +  free_string(s); +  } +  } +  break; +  +  case '0': case '1': case '2': case '3': case '4': +  case '5': case '6': case '7': case '8': case '9': +  PUTC(DATA(pos-1)); +  while(DATA(pos)>='0' && DATA(pos)<='9') PUTC(DATA(pos++)); +  break; +  +  case '"': +  FIXSTRING(this->buf,OUTP()); +  break; +  +  case '\'': +  tmp=pos-1; +  FIND_END_OF_CHAR(); +  if(OUTP()) +  string_builder_append( &this->buf, ADD_PCHARP(data, tmp), pos - tmp); +  else +  for (; tmp < pos; tmp++) +  if (DATA(tmp) == '\n') +  string_builder_putchar (&this->buf, '\n'); +  break; +  +  case '/': +  if(DATA(pos)=='/') +  { +  if (this->keep_comments) { +  FIND_EOL_PRETEND(); +  goto ADD_TO_BUFFER; +  } +  +  FIND_EOL(); +  break; +  } +  +  if(DATA(pos)=='*') +  { +  if (this->keep_comments) { +  SKIPCOMMENT_INC_LINES(); +  goto ADD_TO_BUFFER; +  } else { +  PUTC(' '); +  SKIPCOMMENT(); +  } +  break; +  } +  +  PUTC(DATA(pos-1)); +  break; +  +  case '#': +  if(GOBBLE('!')) +  { +  FIND_EOL(); +  break; +  } +  SKIPSPACE(); +  +  if (!CHECK_WORD(string_recur_, NELEM(string_recur_)) +  && !CHECK_WORD(include_recur_, NELEM(include_recur_))) +  { +  if (this->prefix) +  { +  if( !begins_with( this->prefix->str, ADD_PCHARP(data,pos), this->prefix->len, len-pos, 0 ) || +  DATA(pos+this->prefix->len) != '_') +  { +  FIND_EOS(); +  goto ADD_TO_BUFFER; +  } +  pos += this->prefix->len + 1; +  } else { +  int i; +  +  for (i = pos; i < len; i++) { +  if (DATA(i) == '_') { +  FIND_EOS(); +  goto ADD_TO_BUFFER; +  } else if (!wide_isidchar(DATA(i))) +  break; +  } +  } +  } +  +  switch(DATA(pos)) +  { +  case 'l': +  { +  if(GOBBLE_WORD(line_)) +  { +  /* FIXME: Why not use SKIPSPACE()? */ +  /* Because SKIPSPACE skips newlines? - Hubbe */ +  /* Actually, no - Per */ +  while(DATA(pos)==' ' || DATA(pos)=='\t') pos++; +  }else{ +  goto unknown_preprocessor_directive; +  } +  /* Fall through */ +  } +  case '0': case '1': case '2': case '3': case '4': +  case '5': case '6': case '7': case '8': case '9': +  { +  INT_TYPE new_lineno; +  PCHARP foo = ADD_PCHARP(data,pos); +  new_lineno=STRTOL_PCHARP(foo, &foo, 10)-1; +  if(OUTP()) +  { +  string_builder_binary_strcat(&this->buf, "#line ", 6); +  string_builder_append(&this->buf, ADD_PCHARP(data,pos), +  SUBTRACT_PCHARP(foo,ADD_PCHARP(data,pos))); +  } +  pos = SUBTRACT_PCHARP(foo,data); +  SKIPSPACE(); +  +  if(DATA(pos)=='"') +  { +  struct string_builder nf; +  init_string_builder(&nf, 0); +  +  READSTRING(nf); +  +  if(OUTP()) +  { +  free_string(this->current_file); +  this->current_file = finish_string_builder(&nf); +  +  string_builder_putchar(&this->buf, ' '); +  PUSH_STRING_SHIFT (this->current_file->str, this->current_file->len, +  this->current_file->size_shift, &this->buf); +  }else{ +  free_string_builder(&nf); +  } +  } +  +  if (OUTP()) +  this->current_line = new_lineno; +  +  FIND_EOL(); +  break; +  } +  +  case '"': +  { +  struct string_builder nf; +  char end; +  init_string_builder(&nf, 0); +  READSTRING2(nf); +  goto stringout; +  case '(': end = ')'; goto litstring; +  case '[': end = ']'; goto litstring; +  case '{': end = '}'; +  litstring: +  init_string_builder(&nf, 0); +  READSTRING3(nf,end); +  stringout: +  if(OUTP()) +  PUSH_STRING_SHIFT(nf.s->str, nf.s->len,nf.s->size_shift, &this->buf); +  free_string_builder(&nf); +  break; +  } +  +  case 's': +  { +  if(GOBBLE_WORD(string_)) +  { +  include_mode = 1; +  goto do_include; +  } +  if(GOBBLE_WORD(string_recur_)) +  { +  include_mode = 3; +  goto do_include; +  } +  } +  goto unknown_preprocessor_directive; +  +  case 'i': /* include, if, ifdef */ +  { +  int recur = 0; +  +  if(GOBBLE_WORD(include_) || (recur = GOBBLE_WORD(include_recur_))) +  { +  if (recur) { +  include_mode = 2; +  } else { +  include_mode = 0; +  } +  do_include: +  { +  struct svalue *save_sp=Pike_sp; +  SKIPSPACE(); +  +  check_stack(3); +  +  switch(DATA(pos++)) +  { +  case '"': +  { +  struct string_builder nf; +  init_string_builder(&nf, 0); +  pos--; +  READSTRING(nf); +  push_string(finish_string_builder(&nf)); +  /* In Pike 7.7 and later filenames belonging to Pike +  * are assumed to be encoded according to UTF-8. +  */ +  f_string_to_utf8(1); +  ref_push_string(this->current_file); +  push_int(1); +  break; +  } +  +  case '<': +  { +  ptrdiff_t tmp = pos; +  while(DATA(pos)!='>') +  { +  if(DATA(pos)=='\n') +  { +  cpp_error(this, "Expecting '>' in include."); +  break; +  } +  pos++; +  } +  push_string(make_shared_binary_pcharp(ADD_PCHARP(data,tmp), pos-tmp)); +  /* In Pike 7.7 and later filenames belonging to Pike +  * are assumed to be encoded according to UTF-8. +  */ +  f_string_to_utf8(1); +  ref_push_string(this->current_file); +  pos++; +  push_int(0); +  break; +  } +  +  default: +  if (include_mode & 2) { +  /* Macro expanding didn't help... */ +  cpp_error(this, "Expected file to include."); +  break; +  } else { +  /* Try macro expanding (Bug 2440). */ +  struct string_builder save = this->buf, tmp; +  INT_TYPE save_line = this->current_line; +  init_string_builder(&this->buf, 0); +  +  /* Prefix the buffer with the corresponding *_recur +  * directive, to avoid infinite loops. +  */ +  if (include_mode & 1) { +  string_builder_strcat(&this->buf, "#string_recur "); +  } else { +  string_builder_strcat(&this->buf, "#include_recur "); +  } +  +  pos--; +  pos += low_cpp(this, ADD_PCHARP(data,pos), len - pos, +  CPP_END_AT_NEWLINE, +  charset); +  +  string_builder_putchar(&this->buf, '\n'); +  +  tmp = this->buf; +  this->buf = save; +  +  /* We now have a #include-recur or #string-recur directive +  * in tmp. Preprocess it. +  */ +  +  /* We're processing the line twice. */ +  this->current_line = save_line; +  low_cpp(this, MKPCHARP_STR(tmp.s), tmp.s->len, +  flags, charset); +  free_string_builder(&tmp); +  +  this->current_line = save_line; +  string_builder_sprintf(&this->buf, "\n#line %ld ", +  (long)save_line); +  PUSH_STRING_SHIFT(this->current_file->str, +  this->current_file->len, +  this->current_file->size_shift, +  &this->buf); +  string_builder_putchar(&this->buf, '\n'); +  } +  break; +  } +  +  if(Pike_sp==save_sp) { +  break; +  } +  +  if(OUTP()) +  { +  struct pike_string *new_file; +  +  if (!safe_apply_handler ("handle_include", +  this->handler, this->compat_handler, +  3, BIT_STRING) || +  !(new_file=Pike_sp[-1].u.string) ) { +  cpp_handle_exception (this, "Couldn't find include file."); +  pop_n_elems(Pike_sp-save_sp); +  break; +  } +  +  ref_push_string(new_file); +  +  if (!safe_apply_handler ("read_include", +  this->handler, this->compat_handler, +  1, BIT_STRING|BIT_INT)) { +  cpp_handle_exception (this, "Couldn't read include file."); +  pop_n_elems(Pike_sp-save_sp); +  break; +  } else if (TYPEOF(Pike_sp[-1]) == PIKE_T_INT) { +  cpp_error_sprintf(this, "Couldn't read include file \"%S\".", +  new_file); +  pop_n_elems(Pike_sp-save_sp); +  break; +  } +  +  { +  struct pike_string *save_current_file; +  INT_TYPE save_current_line; +  +  save_current_file=this->current_file; +  save_current_line=this->current_line; +  copy_shared_string(this->current_file,new_file); +  this->current_line=1; +  +  string_builder_binary_strcat(&this->buf, "#line 1 ", 8); +  PUSH_STRING_SHIFT(new_file->str, new_file->len, +  new_file->size_shift, &this->buf); +  string_builder_putchar(&this->buf, '\n'); +  if(include_mode & 1) +  { +  /* #string */ +  struct pike_string *str = Pike_sp[-1].u.string; +  PUSH_STRING_SHIFT(str->str, str->len, str->size_shift, +  &this->buf); +  }else{ +  /* #include */ +  if (this->auto_convert) { +  struct pike_string *new_str = +  recode_string(this, Pike_sp[-1].u.string); +  free_string(Pike_sp[-1].u.string); +  Pike_sp[-1].u.string = new_str; +  } else if (charset) { +  ref_push_string(charset); +  if (!safe_apply_handler ("decode_charset", +  this->handler, this->compat_handler, +  2, BIT_STRING)) { +  cpp_handle_exception (this, +  "Charset decoding failed for included file."); +  pop_n_elems(Pike_sp - save_sp); +  break; +  } +  } +  if (Pike_sp[-1].u.string->size_shift) { +  /* Get rid of any byte order marks (0xfeff) */ +  struct pike_string *new_str = filter_bom(Pike_sp[-1].u.string); +  free_string(Pike_sp[-1].u.string); +  Pike_sp[-1].u.string = new_str; +  } +  low_cpp(this, +  MKPCHARP_STR(Pike_sp[-1].u.string), +  Pike_sp[-1].u.string->len, +  flags&~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE), +  charset); +  } +  +  free_string(this->current_file); +  this->current_file=save_current_file; +  this->current_line=save_current_line; +  +  string_builder_sprintf(&this->buf, "\n#line %ld ", (long)this->current_line); +  PUSH_STRING_SHIFT(this->current_file->str, +  this->current_file->len, +  this->current_file->size_shift, +  &this->buf); +  string_builder_putchar(&this->buf, '\n'); +  if ((include_mode & 2) && (pos < len)) { +  /* NOTE: The rest of the current buffer has already been +  * expanded once. +  */ +  string_builder_append(&this->buf, ADD_PCHARP(data, pos), len - pos); +  pos = len; +  } +  } +  } +  +  pop_n_elems(Pike_sp-save_sp); +  break; +  } +  } +  +  if(GOBBLE_WORD(if_)) +  { +  struct string_builder save, tmp; +  INT32 nflags = 0; +  +  if(!OUTP()) +  nflags = CPP_REALLY_NO_OUTPUT; +  +  save=this->buf; +  init_string_builder(&this->buf, 0); +  pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, +  nflags | CPP_END_AT_NEWLINE | CPP_DO_IF, +  charset); +  tmp=this->buf; +  this->buf=save; +  +  string_builder_putchar(&tmp, 0); +  tmp.s->len--; +  +  if (!nflags) { +  calc(this,MKPCHARP_STR(tmp.s),tmp.s->len,0,0); +  if(SAFE_IS_ZERO(Pike_sp-1)) nflags|=CPP_NO_OUTPUT; +  pop_stack(); +  } +  free_string_builder(&tmp); +  pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, +  nflags | CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF, +  charset); +  break; +  } +  +  if(GOBBLE_WORD(ifdef_)) +  { +  INT32 nflags; +  struct pike_string *s; +  SKIPSPACE(); +  +  s = GOBBLE_IDENTIFIER(); +  if(!s) +  cpp_error(this, "#ifdef what?"); +  +  nflags = CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF | CPP_NO_OUTPUT; +  if(!OUTP()) +  nflags|=CPP_REALLY_NO_OUTPUT; +  if (s) { +  if(FIND_DEFINE(s)) +  nflags&=~CPP_NO_OUTPUT; +  free_string (s); +  } +  +  pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, nflags, +  charset); +  break; +  } +  +  if(GOBBLE_WORD(ifndef_)) +  { +  INT32 nflags; +  struct pike_string *s; +  SKIPSPACE(); +  +  s = GOBBLE_IDENTIFIER(); +  if(!s) +  cpp_error(this, "#ifndef what?"); +  +  nflags=CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF; +  if(!OUTP()) +  nflags|=CPP_REALLY_NO_OUTPUT; +  if (s) { +  if(FIND_DEFINE(s)) +  nflags|=CPP_NO_OUTPUT; +  free_string (s); +  } +  +  pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, nflags, +  charset); +  break; +  } +  +  goto unknown_preprocessor_directive; +  } +  case 'e': /* endif, else, elif, error */ +  { +  if(GOBBLE_WORD(endif_)) +  { +  if(!(flags & CPP_EXPECT_ENDIF)) +  cpp_error(this, "Unmatched #endif."); +  +  return pos; +  } +  +  if(GOBBLE_WORD(else_)) +  { +  if(!(flags & CPP_EXPECT_ELSE)) +  cpp_error(this, "Unmatched #else."); +  +  flags&=~CPP_EXPECT_ELSE; +  flags|=CPP_EXPECT_ENDIF; +  +  flags ^= CPP_NO_OUTPUT; +  break; +  } +  +  if(GOBBLE_WORD(elif_) || GOBBLE_WORD(elseif_)) +  { +  if(!(flags & CPP_EXPECT_ELSE)) +  cpp_error(this, "Unmatched #elif."); +  +  flags|=CPP_EXPECT_ENDIF; +  +  if((flags & (CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT)) == CPP_NO_OUTPUT) +  { +  struct string_builder save,tmp; +  save=this->buf; +  init_string_builder(&this->buf, 0); +  pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, +  CPP_END_AT_NEWLINE | CPP_DO_IF, +  charset); +  tmp=this->buf; +  this->buf=save; +  +  string_builder_putchar(&tmp, 0); +  tmp.s->len--; +  +  calc(this,MKPCHARP_STR(tmp.s),tmp.s->len,0,0); +  free_string_builder(&tmp); +  if(!SAFE_IS_ZERO(Pike_sp-1)) flags&=~CPP_NO_OUTPUT; +  pop_stack(); +  } else { +  FIND_EOL(); +  flags |= CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT; +  } +  break; +  } +  } +  goto unknown_preprocessor_directive; +  +  case 'd': /* define */ +  { +  +  if(GOBBLE_WORD(define_)) +  { +  struct string_builder str; +  INT32 argno=-1; +  ptrdiff_t tmp3; +  struct pike_string *def_name; +  struct define_struct *def; +  struct svalue *partbase,*argbase=Pike_sp; +  int varargs=0; +  +  SKIPSPACE(); +  +  def_name = GOBBLE_IDENTIFIER(); +  if(!def_name) { +  cpp_error(this, "Define what?"); +  FIND_EOL(); +  break; +  } +  +  if(GOBBLE('(')) +  { +  argno=0; +  SKIPWHITE(); +  +  while(DATA(pos)!=')') +  { +  struct pike_string *arg_name; +  if(argno) +  { +  if(!GOBBLE(',')) +  cpp_error(this, +  "Expecting comma in macro definition."); +  SKIPWHITE(); +  } +  if(varargs) +  cpp_error(this,"Expected ) after ..."); +  +  arg_name = GOBBLE_IDENTIFIER(); +  if(!arg_name) +  { +  cpp_error(this, "Expected argument for macro."); +  break; +  } +  +  check_stack(1); +  push_string(arg_name); +  +  SKIPWHITE(); +  argno++; +  if(argno>=MAX_ARGS) +  { +  cpp_error(this, "Too many arguments in macro definition."); +  pop_stack(); +  argno--; +  } +  +  if(DATA(pos)=='.' && DATA(pos+1)=='.' && DATA(pos+2)=='.') +  { +  varargs=1; +  pos+=3; +  SKIPWHITE(); +  } +  } +  +  if(!GOBBLE(')')) +  cpp_error(this, "Missing ) in macro definition."); +  } +  +  SKIPSPACE(); +  +  partbase=Pike_sp; +  init_string_builder(&str, 0); +  +  while(1) +  { +  INT32 extra=0; +  ptrdiff_t old_pos = pos; +  +  switch(DATA(pos++)) +  { +  case '/': +  if(DATA(pos)=='/') +  { +  if (this->keep_comments) { +  FIND_EOL_PRETEND(); +  string_builder_append( &str, ADD_PCHARP(data, old_pos), pos-old_pos ); +  continue; +  } +  string_builder_putchar(&str, ' '); +  FIND_EOL(); +  continue; +  } +  +  if(DATA(pos)=='*') +  { +  if (this->keep_comments) { +  SKIPCOMMENT_INC_LINES(); +  string_builder_append( &str, ADD_PCHARP(data, old_pos), pos-old_pos ); +  continue; +  } +  PUTC(' '); +  SKIPCOMMENT(); +  continue; +  } +  +  string_builder_putchar(&str, '/'); +  continue; +  +  case '0': case '1': case '2': case '3': case '4': +  case '5': case '6': case '7': case '8': case '9': +  string_builder_putchar(&str, DATA(pos-1)); +  while(DATA(pos)>='0' && DATA(pos)<='9') +  string_builder_putchar(&str, DATA(pos++)); +  continue; +  +  case '\\': +  if(GOBBLE('\n')) +  { +  this->current_line++; +  PUTNL(); +  continue; +  } +  if (DATA(pos) == '\r' && DATA(pos+1) == '\n') { +  pos += 2; +  this->current_line++; +  PUTNL(); +  continue; +  } +  /* Identifiers might start with \uxxxx, so try to parse +  * an identifier now. */ +  goto gobble_identifier_in_define; +  +  case ',': +  { +  int oldpos; +  +  oldpos = pos; +  SKIPSPACE_PRETEND(); +  +  if (DATA(pos) == '#' && DATA(pos+1) == '#') { +  extra|= DEF_ARG_NEED_COMMA; +  pos += 2; +  goto concat_identifier; +  } else { +  pos = oldpos; +  goto gobble_identifier_in_define; +  } +  } +  case '#': +  if(GOBBLE('#')) +  { +  extra= (extra & DEF_ARG_NEED_COMMA) | DEF_ARG_NOPRESPACE; +  +  while(str.s->len && wide_isspace(index_shared_string(str.s,str.s->len-1))) +  str.s->len--; +  concat_identifier: +  if(!str.s->len && Pike_sp-partbase>1) +  { + #ifdef PIKE_DEBUG +  if(TYPEOF(Pike_sp[-1]) != PIKE_T_INT) +  Pike_fatal("Internal error in CPP\n"); + #endif +  Pike_sp[-1].u.integer|=DEF_ARG_NOPOSTSPACE; +  } +  }else{ +  extra=DEF_ARG_STRINGIFY; +  } +  SKIPSPACE(); +  pos++; +  /* fall through */ +  +  gobble_identifier_in_define: +  default: { +  struct pike_string *s; +  pos--; +  s = GOBBLE_IDENTIFIER(); +  if (s) +  { +  tmp3=pos-1; +  if(argno>0) +  { +  if (s->refs > 1) +  { +  for(e=0;e<argno;e++) +  { +  if(argbase[e].u.string == s) +  { +  check_stack(2); +  push_string(finish_string_builder(&str)); +  init_string_builder(&str, 0); +  push_int(e | extra); +  extra=0; +  break; +  } +  } +  if(e!=argno) { +  free_string (s); +  continue; +  } +  } +  } +  string_builder_shared_strcat (&str, s); +  free_string (s); +  }else{ +  string_builder_putchar(&str, DATA(pos++)); +  } +  extra=0; +  continue; +  } +  +  case '"': +  FIXSTRING(str, 1); +  continue; +  +  case '\'': +  tmp3=pos-1; +  FIND_END_OF_CHAR(); +  string_builder_append(&str, ADD_PCHARP(data, tmp3), pos - tmp3); +  continue; +  +  case '\n': +  PUTNL(); +  this->current_line++; +  /* Fallthrough */ +  case 0: +  break; +  } +  push_string(finish_string_builder(&str)); +  break; +  } +  +  if(OUTP()) +  { +  f_aggregate(Pike_sp - partbase); +  +  def = alloc_empty_define(def_name); +  def->args=argno; +  def->varargs=varargs; +  +  add_ref(def->parts = Pike_sp[-2].u.array); +  +  { +  struct define_struct *d; +  if ((d = FIND_DEFINE(def->name)) && +  (d->flags & (CPP_MACRO_IN_USE | CPP_MACRO_DISABLED))) { +  cpp_error(this, +  "Illegal to redefine a macro during its expansion."); +  } else { +  mapping_string_insert(this->defines, def->name, Pike_sp-1); +  } +  } +  } +  free_string (def_name); +  pop_n_elems(Pike_sp-argbase); +  break; +  } +  +  goto unknown_preprocessor_directive; +  } +  case 'u': /* undefine */ +  { +  +  /* NOTE: Reuses undefine_ for undef_ */ +  if(GOBBLE_WORD(undefine_) || GOBBLE_WORD(undef_)) +  { +  struct pike_string *s; +  SKIPSPACE(); +  s = GOBBLE_IDENTIFIER(); +  if(!s) { +  cpp_error(this, "Undefine what?"); +  break; +  } +  if(OUTP()) +  { +  undefine(this,s); +  } +  free_string (s); +  break; +  } +  +  goto unknown_preprocessor_directive; +  } +  case 'c': /* charset */ +  { +  +  if (GOBBLE_WORD(charset_)) { +  ptrdiff_t p; +  struct pike_string *s; +  +  if (flags & (CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE)) { +  /* Only allowed at the top-level */ +  cpp_error(this, "#charset directive inside #if/#endif."); +  /* Skip to end of line */ +  while (DATA(pos) && DATA(pos) != '\n') { +  pos++; +  } +  break; +  } +  +  SKIPSPACE(); +  +  p = pos; +  while(DATA(pos) && !wide_isspace(DATA(pos))) { +  pos++; +  } +  +  if (pos != p) { +  /* The rest of the string. */ +  push_string( make_shared_binary_pcharp( ADD_PCHARP(data,pos), len-pos ) ); +  /* The charset name */ +  push_string( make_shared_binary_pcharp( ADD_PCHARP(data,p),pos-p)); +  +  if (!safe_apply_handler ("decode_charset", this->handler, this->compat_handler, +  2, BIT_STRING)) { +  cpp_handle_exception (this, NULL); +  } else { +  low_cpp(this, MKPCHARP_STR(Pike_sp[-1].u.string),Pike_sp[-1].u.string->len, +  flags, charset); +  pop_stack(); +  } +  /* FIXME: Is this the correct thing to return? */ +  return len; +  } else { +  cpp_error(this, "What charset?"); +  } +  break; +  } +  goto unknown_preprocessor_directive; +  } +  case 'p': /* pragma */ +  { +  +  if(GOBBLE_WORD(pragma_)) +  { +  if(OUTP()) +  string_builder_strcat(&this->buf, "#pragma"); +  else +  FIND_EOL(); +  break; +  } +  if(GOBBLE_WORD(pike_)) +  { +  if(OUTP()) +  { +  int major, minor; +  ptrdiff_t tmp; +  PCHARP ptr; +  +  string_builder_strcat(&this->buf, "#pike"); +  tmp= this->buf.s->len; +  pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, +  CPP_END_AT_NEWLINE | CPP_DO_IF, +  charset); +  +  ptr=MKPCHARP_STR(this->buf.s); +  INC_PCHARP(ptr, tmp); +  +  /* Zero terminate the buffer contents here to make sure +  * that STRTOL_PCHARP does not read beyond the end of the +  * buffer */ +  string_builder_putchar(&this->buf, 0); +  this->buf.s->len--; +  +  major=STRTOL_PCHARP(ptr, &ptr, 10); +  if(INDEX_PCHARP(ptr,0) == '.') +  { +  INC_PCHARP(ptr, 1); +  minor=STRTOL_PCHARP(ptr, &ptr, 10); +  cpp_change_compat(this, major, minor); +  }else{ +  cpp_error(this, "Missing '.' in #pike."); +  this->compat_minor=0; +  } +  } +  else +  FIND_EOL(); +  break; +  } +  } +  case 'r': /* require */ +  { +  if(GOBBLE_WORD(require_)) +  { +  struct string_builder save, tmp; +  save = this->buf; +  init_string_builder(&this->buf, 0); +  pos += low_cpp(this, ADD_PCHARP(data,pos), len-pos, +  CPP_END_AT_NEWLINE | CPP_DO_IF, +  charset); +  tmp = this->buf; +  this->buf = save; +  string_builder_putchar(&tmp, 0); +  tmp.s->len--; +  +  calc(this,MKPCHARP_STR(tmp.s),tmp.s->len,0,0); +  if(SAFE_IS_ZERO(Pike_sp-1)) this->dependencies_fail=1; +  pop_stack(); +  free_string_builder(&tmp); +  if(this->dependencies_fail) return pos; +  break; +  } +  goto unknown_preprocessor_directive; +  } +  default: +  unknown_preprocessor_directive: +  { +  struct pike_string *directive = GOBBLE_IDENTIFIER(); +  if (directive) { +  struct svalue *fun = NULL; +  struct svalue sv; +  struct pike_string *directive_string = +  add_shared_strings(MK_STRING("directive_"), directive); +  int id = find_shared_string_identifier(directive_string, +  Pike_fp->current_object->prog); +  +  free_string(directive_string); +  if (id >= 0) { +  /* NB: This svalue holds no reference! */ +  SET_SVAL(sv, PIKE_T_FUNCTION, id, object, Pike_fp->current_object); +  fun = &sv; +  } +  +  if(!fun && this->directives) { +  /* Try a mapping lookup instead. */ +  fun = low_mapping_string_lookup(this->directives, directive); +  } +  +  if (fun) { +  ptrdiff_t foo; +  free_string(directive); +  +  SKIPSPACE(); +  foo = pos; +  FIND_EOL(); +  push_int(flags); +  push_string(make_shared_binary_pcharp(ADD_PCHARP(data,foo), pos-foo)); +  safe_apply_svalue(fun, 2, 1); +  if ((TYPEOF(Pike_sp[-1]) == PIKE_T_STRING) && +  Pike_sp[-1].u.string->len) { +  /* We need to recurse. */ +  low_cpp(this, MKPCHARP_STR(Pike_sp[-1].u.string), +  Pike_sp[-1].u.string->len, flags, charset); +  } +  pop_stack(); +  break; +  } +  } +  if(!OUTP() && !this->picky_cpp) break; +  { +  if (directive) { +  cpp_error_sprintf(this, "Unknown preprocessor directive %S.", +  directive); +  free_string(directive); +  } else { +  cpp_error_sprintf(this, "Invalid preprocessor directive character at %d: '%c'.", +  pos, DATA(pos)); +  } +  } +  } +  } +  } +  continue; +  ADD_TO_BUFFER: +  // keep line +  string_builder_append(&this->buf, ADD_PCHARP(data,old_pos), pos-old_pos); +  } +  +  if(flags & CPP_EXPECT_ENDIF) { +  INT_TYPE saved_line = this->current_line; +  this->current_line = first_line; +  cpp_error(this, "End of file while searching for #endif."); +  this->current_line = saved_line; +  } +  +  return pos; + } +  +  PIKEFUN void cpp(string data, int flags) +  { +  low_cpp(THIS, MKPCHARP_STR(data), data->len, flags, THIS->charset); +  } +    /*** Magic defines ***/      /*! @decl constant __LINE__    *!    *! This define contains the current line number, represented as an    *! integer, in the source file.    */ - static void insert_current_line(struct cpp *this, + static void insert_current_line(struct CPP_struct *this,    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    string_builder_sprintf(tmp, " %ld ", (long)this->current_line);   }      /*! @decl constant __FILE__    *!    *! This define contains the file path and name of the source file.    */ - static void insert_current_file_as_string(struct cpp *this, + static void insert_current_file_as_string(struct CPP_struct *this,    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    PUSH_STRING_SHIFT(this->current_file->str, this->current_file->len,    this->current_file->size_shift, tmp);   }      /*! @decl constant __DIR__    *!    *! This define contains the directory path of the source file.    */ - static void insert_current_dir_as_string(struct cpp *this, + static void insert_current_dir_as_string(struct CPP_struct *this,    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    ref_push_string(this->current_file);    /* FIXME: This isn't safe if the master hasn't been compiled yet. */    SAFE_APPLY_MASTER("dirname",1);    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();   }      /*! @decl constant __TIME__    *!    *! This define contains the current time at the time of compilation,    *! e.g. "12:20:51".    */ - static void insert_current_time_as_string(struct cpp *UNUSED(this), + static void insert_current_time_as_string(struct CPP_struct *UNUSED(this),    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    /* FIXME: Is this code safe? */    time_t tmp2;    char *buf;    time(&tmp2);    buf=ctime(&tmp2);       PUSH_STRING0((p_wchar0 *)buf+11, 8, tmp);   }      /*! @decl constant __DATE__    *!    *! This define contains the current date at the time of compilation,    *! e.g. "Jul 28 2001".    */ - static void insert_current_date_as_string(struct cpp *UNUSED(this), + static void insert_current_date_as_string(struct CPP_struct *UNUSED(this),    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    /* FIXME: Is this code safe? */    time_t tmp2;    char *buf;    time(&tmp2);    buf=ctime(&tmp2);   
pike.git/src/cpp.cmod:3013:      /*! @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__]    */ - static void insert_current_version(struct cpp *this, + static void insert_current_version(struct CPP_struct *this,    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    string_builder_sprintf(tmp, " %d.%d ", this->compat_major,    this->compat_minor);   }         /*! @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__]    */ - static void insert_current_minor(struct cpp *this, + static void insert_current_minor(struct CPP_struct *this,    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    string_builder_sprintf(tmp, " %d ", this->compat_minor);   }      /*! @decl int(1..) __COUNTER__    *! This define contains a unique counter (unless it has been expanded    *! Int.NATIVE_MAX times) represented as an integer.    *!    */ - static void insert_current_counter(struct cpp *UNUSED(this), + static void insert_current_counter(struct CPP_struct *UNUSED(this),    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    static int counter = 0;    string_builder_sprintf(tmp, " %d ", ++counter);   }      /*! @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__]    */ - static void insert_current_major(struct cpp *this, + static void insert_current_major(struct CPP_struct *this,    struct define_struct *UNUSED(def),    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    string_builder_sprintf(tmp, " %d ", this->compat_major);   }      /* _Pragma(STRING) */   /*! @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]    */ - static void insert_pragma(struct cpp *this, + static void insert_pragma(struct CPP_struct *this,    struct define_struct *UNUSED(def),    struct pike_string *arg,    struct string_builder *tmp)   {    int i;    int in_string = 0;       /* Make some reasonable amount of space. */    string_build_mkspace(tmp, arg->len + 20, arg->size_shift);   
pike.git/src/cpp.cmod:3141:    }       string_builder_sprintf(tmp, "\n#line %ld ", (long)this->current_line);    PUSH_STRING_SHIFT(this->current_file->str,    this->current_file->len,    this->current_file->size_shift,    tmp);    string_builder_putchar(tmp, '\n');   }    - static void insert_callback_define(struct cpp *this, + static void insert_callback_define(struct CPP_struct *this,    struct define_struct *def,    struct pike_string *arg,    struct string_builder *tmp)   {    ref_push_string( def->name );    ref_push_string( arg );    if (safe_apply_handler( "evaluate_define",    this->handler, this->compat_handler, 2, 0 ) &&    TYPEOF(Pike_sp[-1]) == T_STRING ) {    string_builder_shared_strcat(tmp, Pike_sp[-1].u.string);
pike.git/src/cpp.cmod:3166:    {    string_builder_sprintf(tmp, "\n#line %ld ", (long)this->current_line);    insert_current_file_as_string( this,def,arg,tmp);    string_builder_putchar(tmp, '\n');    }    }    pop_stack();    }   }    - static void insert_callback_define_no_args(struct cpp *this, + static void insert_callback_define_no_args(struct CPP_struct *this,    struct define_struct *def,    struct pike_string *UNUSED(arg),    struct string_builder *tmp)   {    struct svalue *save_sp = Pike_sp;    ref_push_string( def->name );    if (safe_apply_handler( "evaluate_define",    this->handler, this->compat_handler, 1, 0 ) &&    TYPEOF(Pike_sp[-1]) == T_STRING )    string_builder_shared_strcat(tmp, Pike_sp[-1].u.string);
pike.git/src/cpp.cmod:3268:    *!    *! 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.    */    - /*! @decl constant __OS2__ -  *! -  *! This define is defined when the Pike is running on IBM OS/2. -  */ -  +    /*! @endnamespace */    - /*! @decl string cpp(string data, mapping|string|void current_file, @ -  *! int|string|void charset, object|void handler, @ -  *! void|int compat_major, void|int compat_minor, @ -  *! void|int picky_cpp) -  *! -  *! 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, -  *! it will default to @expr{"-"@}. @[charset] defaults to @expr{"ISO-10646"@}. -  *! -  *! 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 -  *! @member string "current_file" -  *! Name of the current file. It is used for generating -  *! #line directives and for locating include files. -  *! @member int|string "charset" -  *! Charset to use when processing @expr{data@}. -  *! @member object "handler" -  *! Compilation handler. -  *! @member int "compat_major" -  *! Sets the major pike version used for compat handling. -  *! @member int "compat_minor" -  *! Sets the minor pike version used for compat handling. -  *! @member int "picky_cpp" -  *! Generate more warnings. -  *! @member int "keep_comments" -  *! This option keeps @[cpp()] from removing comments. -  *! Useful in combination with the prefix feature below. -  *! @member string "prefix" -  *! 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 -  *! -  *! @seealso -  *! @[compile()] -  */ -  - /* Doesn't free string_builder buf! */ - static void free_cpp(struct cpp *this) - { -  if(this->defines) -  free_mapping(this->defines); -  -  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); -  -  if(this->prefix) -  free_string(this->prefix); - } -  -  - PIKEFUN string cpp(string data, -  mapping|string|void opts_or_file, +  PIKEFUN void create(mapping|string|void opts_or_file,    int|string|void charset_sv,    object|void handler,    int|void compat_major_sv,    int|void compat_minor_sv,    int|void picky_cpp_sv) -  efun; +  flags ID_PROTECTED;    { -  struct cpp this; -  struct svalue *save_sp = Pike_sp - args; -  struct mapping *predefs = NULL; +  struct CPP_struct *this = THIS;       struct pike_string *prefix = NULL;       struct pike_string *current_file = 0;    -  int auto_convert = 0; +     struct pike_string *charset = NULL;       int compat_major = compat_major_sv?compat_major_sv->u.integer:0;    int compat_minor = compat_minor_sv?compat_minor_sv->u.integer:0;    int picky_cpp = picky_cpp_sv?picky_cpp_sv->u.integer:0;    -  ONERROR err; - #ifdef PIKE_DEBUG -  ONERROR tmp; - #endif /* PIKE_DEBUG */ +  this->prefix = NULL; +  this->current_line=1; +  this->compile_errors=0; +  this->defines = allocate_mapping(32); +  this->keep_comments = 0; +  this->dependencies_fail = 0; +  this->auto_convert = 0;    -  this.prefix = NULL; -  this.current_line=1; -  this.compile_errors=0; -  this.defines = allocate_mapping(32); -  this.keep_comments = 0; -  this.dependencies_fail = 0; -  +     if (opts_or_file) {    if (TYPEOF(*opts_or_file) == PIKE_T_MAPPING) {    struct svalue *tmp;    struct mapping *m = opts_or_file->u.mapping;      #define GET_TYPE(type, name) ((tmp = simple_mapping_string_lookup(m, name)) \    && (TYPEOF(*(tmp)) == PIKE_T_##type || (Pike_error("Expected type %s,"\    "got type %s for " name ".", get_name_of_type(PIKE_T_##type), get_name_of_type(TYPEOF(*tmp))), 0)))       if (GET_TYPE(STRING, "current_file")) current_file = tmp->u.string;    if (GET_TYPE(STRING, "charset")) charset_sv = tmp;    if (GET_TYPE(OBJECT, "handler")) handler = tmp->u.object;    if (GET_TYPE(INT, "compat_major")) compat_major = tmp->u.integer;    if (GET_TYPE(INT, "compat_minor")) compat_minor = tmp->u.integer;    if (GET_TYPE(INT, "picky")) picky_cpp = tmp->u.integer;    if (GET_TYPE(STRING, "prefix")) prefix = tmp->u.string; -  if (GET_TYPE(INT, "keep_comments")) this.keep_comments = tmp->u.integer; +  if (GET_TYPE(INT, "keep_comments")) this->keep_comments = tmp->u.integer;   #undef GET_TYPE    } else if (TYPEOF(*opts_or_file) == PIKE_T_STRING) {    current_file = opts_or_file->u.string;    }    }    -  this.data = data; -  add_ref(data); -  +     if(current_file)    add_ref(current_file);    else    current_file = make_shared_string("-"); -  this.current_file = current_file; +  this->current_file = current_file;    -  this.compat_major=PIKE_MAJOR_VERSION; -  this.compat_minor=PIKE_MINOR_VERSION; -  this.compat_handler = 0; -  this.handler = handler; +  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); -  +     if (prefix) {    int i;    if (prefix->size_shift) {    Pike_error("No widechars allowed in cpp prefix.\n");    }    for (i = 0; i < prefix->len; i++) {    if (!wide_isidchar(prefix->str[i])) {    Pike_error("Invalid char in prefix.\n");    }    } -  this.prefix = prefix; +  this->prefix = prefix;    add_ref(prefix);    }          if(charset_sv) {    if(TYPEOF(*charset_sv) == T_STRING) { -  charset = charset_sv->u.string; -  push_string(data); -  this.data = data = NULL; -  ref_push_string(charset); -  if (!safe_apply_handler ("decode_charset", this.handler, -  this.compat_handler, 2, BIT_STRING)) { -  cpp_handle_exception (&this, "Error decoding with charset %S", -  charset); -  Pike_error("Unknown charset.\n"); +  this->charset = charset_sv->u.string; +  add_ref(this->charset);    } -  this.data = data = Pike_sp[-1].u.string; -  Pike_sp--; -  dmalloc_touch_svalue(Pike_sp); -  } +     else if(TYPEOF(*charset_sv) == T_INT) -  auto_convert = charset_sv->u.integer; +  this->auto_convert = charset_sv->u.integer;    else {    SIMPLE_ARG_TYPE_ERROR("cpp", 3, "string|int");    }    }       if(compat_major) -  cpp_change_compat(&this, compat_major, compat_minor); +  cpp_change_compat(this, compat_major, compat_minor);    -  this.picky_cpp = picky_cpp; +  this->picky_cpp = picky_cpp; +  pop_n_elems(args); +  }    -  +  PIKEFUN void define_ansi_macros() +  { +  struct CPP_struct *this = THIS; +  +  /* These attempt to be compatible with the C standard. */ +  do_magic_define(this,"__LINE__",insert_current_line); +  do_magic_define(this,"__FILE__",insert_current_file_as_string); +  do_magic_define(this,"__DATE__",insert_current_date_as_string); +  do_magic_define(this,"__TIME__",insert_current_time_as_string); +  +  /* These are from the 201x C standard. */ +  do_magic_define(this,"_Pragma",insert_pragma)->args = 1; +  simple_add_define(this, "static_assert", "_Static_assert"); +  } +  +  PIKEFUN void define_pike_macros() +  { +  struct CPP_struct *this = THIS; +  +  /* These are Pike extensions. */ +  do_magic_define(this,"__DIR__",insert_current_dir_as_string); +  do_magic_define(this,"__VERSION__",insert_current_version); +  do_magic_define(this,"__MAJOR__",insert_current_major); +  do_magic_define(this,"__MINOR__",insert_current_minor); +  +  simple_add_define(this, "__ARGS__", "__args__"); +  +  do_magic_define(this,"__COUNTER__",insert_current_counter); +  + #if 0 +  /* Left in place for documentation reference purposes. */ +  struct define_struct *def = +  alloc_empty_define(make_shared_string("__deprecated__"), 1); +  def->args = 1; +  REF_MAKE_CONST_STRING(def->first, "__attribute__(\"deprecated\", "); +  def->parts[0].argument = 0; +  REF_MAKE_CONST_STRING(def->parts[0].postfix, ")"); +  mapping_string_insert(this->defines, def->name, Pike_sp-1); +  pop_stack(); + #endif /* 0 */ +  +  simple_add_define(this, "__PIKE__", " 1 "); +  +  simple_add_define(this, "__REAL_VERSION__", +  " " DEFINETOSTR(PIKE_MAJOR_VERSION) "." +  DEFINETOSTR(PIKE_MINOR_VERSION) " "); +  simple_add_define(this, "__REAL_MAJOR__", +  " " DEFINETOSTR(PIKE_MAJOR_VERSION) " "); +  simple_add_define(this, "__REAL_MINOR__", +  " " DEFINETOSTR(PIKE_MINOR_VERSION) " "); +  simple_add_define(this, "__BUILD__", +  " " DEFINETOSTR(PIKE_BUILD_VERSION) " "); +  simple_add_define(this, "__REAL_BUILD__", +  " " DEFINETOSTR(PIKE_BUILD_VERSION) " "); +  simple_add_define(this, "__AUTO_BIGNUM__", " 1 "); + #ifdef __NT__ +  simple_add_define(this, "__NT__", " 1 "); + #endif + #ifdef __amigaos__ +  simple_add_define(this, "__amigaos__", " 1 "); + #endif + #ifdef __APPLE__ +  simple_add_define(this, "__APPLE__", " 1 "); + #endif +  simple_add_define(this, "SIZEOF_INT", +  " " DEFINETOSTR(SIZEOF_INT) " "); +  simple_add_define(this, "SIZEOF_FLOAT", +  " " DEFINETOSTR(SIZEOF_FLOAT) " "); +  } + } +  + /*! @decl string cpp(string data, mapping|string|void current_file, @ +  *! int|string|void charset, object|void handler, @ +  *! void|int compat_major, void|int compat_minor, @ +  *! void|int picky_cpp) +  *! +  *! 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, +  *! it will default to @expr{"-"@}. @[charset] defaults to @expr{"ISO-10646"@}. +  *! +  *! 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 +  *! @member string "current_file" +  *! Name of the current file. It is used for generating +  *! #line directives and for locating include files. +  *! @member int|string "charset" +  *! Charset to use when processing @expr{data@}. +  *! @member object "handler" +  *! Compilation handler. +  *! @member int "compat_major" +  *! Sets the major pike version used for compat handling. +  *! @member int "compat_minor" +  *! Sets the minor pike version used for compat handling. +  *! @member int "picky_cpp" +  *! Generate more warnings. +  *! @member int "keep_comments" +  *! This option keeps @[cpp()] from removing comments. +  *! Useful in combination with the prefix feature below. +  *! @member string "prefix" +  *! 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 +  *! +  *! @seealso +  *! @[compile()] +  */ +  + 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; + { +  struct svalue *save_sp = Pike_sp - args; +  struct object *cpp_obj = clone_object(CPP_program, args-1); +  struct CPP_struct *this = +  (struct CPP_struct *)get_storage(cpp_obj, CPP_program); +  struct mapping *predefs = NULL; +  + #ifdef PIKE_DEBUG +  ONERROR tmp; + #endif /* PIKE_DEBUG */ +  +  push_object(cpp_obj); +     if (use_initial_predefs)    /* Typically compiling the master here. */    predefs = initial_predefs_mapping();    else { -  low_unsafe_apply_handler ("get_predefines", this.handler, -  this.compat_handler, 0); +  low_unsafe_apply_handler ("get_predefines", this->handler, +  this->compat_handler, 0);    if (!UNSAFE_IS_ZERO (Pike_sp - 1)) {    struct keypair *k;    int e, sprintf_args = 0;    if (TYPEOF(Pike_sp[-1]) != T_MAPPING) {    push_static_text ("Invalid return value from get_predefines, got %O\n");    push_svalue (Pike_sp - 3);    sprintf_args = 2;    }    else {    predefs = copy_mapping (Pike_sp[-1].u.mapping);
pike.git/src/cpp.cmod:3514:    }    if (!predefs) {    predef_map_error:    f_sprintf (sprintf_args);    Pike_error("%S", Pike_sp[-1].u.string);    }    }    pop_stack();    }    -  if (auto_convert && (!data->size_shift) && (data->len > 1)) { -  /* Try to determine if we need to recode the string */ -  struct pike_string *new_data = recode_string(&this, data); -  free_string(data); -  this.data = data = new_data; -  } -  if (data->size_shift) { -  /* Get rid of any byte order marks (0xfeff) */ -  struct pike_string *new_data = filter_bom(data); -  free_string(data); -  this.data = data = new_data; -  } +  apply(cpp_obj, "define_ansi_macros", 0);    -  init_string_builder(&this.buf, 0); +  apply(cpp_obj, "define_pike_macros", 0);    -  /* These attempt to be compatible with the C standard. */ -  do_magic_define(&this,"__LINE__",insert_current_line); -  do_magic_define(&this,"__FILE__",insert_current_file_as_string); -  do_magic_define(&this,"__DATE__",insert_current_date_as_string); -  do_magic_define(&this,"__TIME__",insert_current_time_as_string); -  -  /* These are from the 201x C standard. */ -  do_magic_define(&this,"_Pragma",insert_pragma)->args = 1; -  simple_add_define(&this, "static_assert", "_Static_assert"); -  -  simple_add_define(&this, "__ARGS__", "__args__"); -  -  do_magic_define(&this,"__COUNTER__",insert_current_counter); -  -  /* These are Pike extensions. */ -  do_magic_define(&this,"__DIR__",insert_current_dir_as_string); -  do_magic_define(&this,"__VERSION__",insert_current_version); -  do_magic_define(&this,"__MAJOR__",insert_current_major); -  do_magic_define(&this,"__MINOR__",insert_current_minor); -  -  { - #if 0 -  /* Left in place for documentation reference purposes. */ -  struct define_struct *def = -  alloc_empty_define(make_shared_string("__deprecated__"), 1); -  def->args = 1; -  REF_MAKE_CONST_STRING(def->first, "__attribute__(\"deprecated\", "); -  def->parts[0].argument = 0; -  REF_MAKE_CONST_STRING(def->parts[0].postfix, ")"); -  mapping_string_insert(this.defines, def->name, Pike_sp-1); -  pop_stack(); - #endif /* 0 */ -  -  simple_add_define(&this, "__PIKE__", " 1 "); -  -  simple_add_define(&this, "__REAL_VERSION__", -  " " DEFINETOSTR(PIKE_MAJOR_VERSION) "." -  DEFINETOSTR(PIKE_MINOR_VERSION) " "); -  simple_add_define(&this, "__REAL_MAJOR__", -  " " DEFINETOSTR(PIKE_MAJOR_VERSION) " "); -  simple_add_define(&this, "__REAL_MINOR__", -  " " DEFINETOSTR(PIKE_MINOR_VERSION) " "); -  simple_add_define(&this, "__BUILD__", -  " " DEFINETOSTR(PIKE_BUILD_VERSION) " "); -  simple_add_define(&this, "__REAL_BUILD__", -  " " DEFINETOSTR(PIKE_BUILD_VERSION) " "); -  simple_add_define(&this, "__AUTO_BIGNUM__", " 1 "); - #ifdef __NT__ -  simple_add_define(&this, "__NT__", " 1 "); - #endif - #ifdef __amigaos__ -  simple_add_define(&this, "__amigaos__", " 1 "); - #endif - #ifdef __OS2__ -  simple_add_define(&this, "__OS2__", " 1 "); - #endif - #ifdef __APPLE__ -  simple_add_define(&this, "__APPLE__", " 1 "); - #endif -  simple_add_define(&this, "SIZEOF_INT", -  " " DEFINETOSTR(SIZEOF_INT) " "); -  simple_add_define(&this, "SIZEOF_FLOAT", -  " " DEFINETOSTR(SIZEOF_FLOAT) " "); -  } -  +     if (predefs) {    struct keypair *k;    int e;    NEW_MAPPING_LOOP (predefs->data) {    if (TYPEOF(k->val) == T_STRING) -  add_define (&this, k->ind.u.string, k->val.u.string); +  add_define (this, k->ind.u.string, k->val.u.string);    else if(TYPEOF(k->val) == T_FUNCTION || TYPEOF(k->val) == T_OBJECT)    {    struct define_struct *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);    free_string(s);    def->magic = insert_callback_define;    def->varargs=1;    def->args=1;    }    else    {    def = alloc_empty_define(k->ind.u.string);    def->magic = insert_callback_define_no_args;    } -  mapping_string_insert(this.defines, def->name, Pike_sp-1); +  mapping_string_insert(this->defines, def->name, Pike_sp-1);    pop_stack();    }    else -  add_define (&this, k->ind.u.string, empty_pike_string); +  add_define (this, k->ind.u.string, empty_pike_string);    }    free_mapping (predefs);    }    -  string_builder_binary_strcat(&this.buf, "#line 1 ", 8); -  PUSH_STRING_SHIFT(this.current_file->str, this.current_file->len, -  this.current_file->size_shift, &this.buf); -  string_builder_putchar(&this.buf, '\n'); +  this->data = data; +  add_ref(data);    -  +  if (this->charset) { +  push_string(data); +  this->data = data = NULL; +  ref_push_string(this->charset); +  if (!safe_apply_handler ("decode_charset", this->handler, +  this->compat_handler, 2, BIT_STRING)) { +  cpp_handle_exception (this, "Error decoding with charset %S", +  THIS->charset); +  Pike_error("Unknown charset.\n"); +  } +  this->data = data = Pike_sp[-1].u.string; +  Pike_sp--; +  dmalloc_touch_svalue(Pike_sp); +  } +  +  if (this->auto_convert && (!data->size_shift) && (data->len > 1)) { +  /* Try to determine if we need to recode the string */ +  struct pike_string *new_data = recode_string(this, data); +  free_string(data); +  this->data = data = new_data; +  } +  if (data->size_shift) { +  /* Get rid of any byte order marks (0xfeff) */ +  struct pike_string *new_data = filter_bom(data); +  free_string(data); +  this->data = data = new_data; +  } +  +  string_builder_binary_strcat(&this->buf, "#line 1 ", 8); +  PUSH_STRING_SHIFT(this->current_file->str, this->current_file->len, +  this->current_file->size_shift, &this->buf); +  string_builder_putchar(&this->buf, '\n'); +    #ifdef PIKE_DEBUG    SET_ONERROR(tmp, fatal_on_error, "Preprocessor exited with longjump!\n");   #endif /* PIKE_DEBUG */    -  +  ref_push_string(data); /* data */ +  push_int(0); /* flags */ +  apply(cpp_obj, "cpp", 2);    -  low_cpp(&this, MKPCHARP_STR(data), data->len, -  0, auto_convert, charset); -  +    #ifdef PIKE_DEBUG    UNSET_ONERROR(tmp);   #endif /* PIKE_DEBUG */    -  UNSET_ONERROR(err); -  free_cpp(&this); -  -  if(this.compile_errors) +  if(this->compile_errors)    { -  free_string_builder(&this.buf); +     throw_error_object(fast_clone_object(cpp_error_program), 0, 0, 0,    "Cpp() failed\n");    } -  else if(this.dependencies_fail) +  else if(this->dependencies_fail)    { -  free_string_builder(&this.buf); -  pop_n_elems(Pike_sp - save_sp); +     push_int(0);    }    else    { -  pop_n_elems(Pike_sp - save_sp); -  push_string(finish_string_builder(&this.buf)); +  push_string(finish_string_builder(&this->buf)); +  /* NB: Make sure the buffer isn't freed twice. */ +  this->buf.s = NULL;    } -  +  stack_pop_n_elems_keep_top((Pike_sp - save_sp) - 1);   }      /*! @module Builtin    */      /*! @decl mapping(string:mixed) _take_over_initial_predefines() -  +  *! +  *! Returns a mapping containing the set of predefined macros. +  *! These are typically the macros defined via the @tt{-D@} option +  *! when starting Pike. +  *! +  *! This function is typically called by the @[MasterObject] at +  *! initialization, and may only be called once. After it has been called, +  *! @[cpp()] will start calling @[CompilationHandler->get_predefines()] to +  *! retrieve the set of predefined macros. +  *! +  *! @seealso +  *! [cpp()], @[CompilationHandler->get_predefines()]    */   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;    free(tmp);    }    last_predef = 0;    }    else Pike_error ("Initial predefines already taken over.\n");   }      /*! @endmodule    */
pike.git/src/cpp.cmod:3727:    "function(void:mapping(string:string))",    OPT_SIDE_EFFECT, NULL, NULL));    simple_add_constant ("_take_over_initial_predefines", &s, 0);    free_svalue (&s);   }         void add_predefine(const char *s)   {    struct pike_predef_s *tmp=ALLOC_STRUCT(pike_predef_s); -  char * pos=strchr(s,'='); +  size_t len = strlen(s); +  char *pos=strchr(s,'='); +     if(pos)    { -  tmp->name=xalloc(pos-s+1); -  memcpy(tmp->name,s,pos-s); +  tmp->name = xalloc(len+1); +  memcpy(tmp->name, s, len+1);    tmp->name[pos-s]=0;    -  tmp->value=xalloc(s+strlen(s)-pos); -  memcpy(tmp->value,pos+1,s+strlen(s)-pos); +  tmp->value = tmp->name + (pos-s) + 1;    }else{ -  tmp->name=xalloc(strlen(s)+1); -  memcpy(tmp->name,s,strlen(s)+1); +  tmp->name = xalloc(len + 1 + 4); +  memcpy(tmp->name,s,len + 1);    -  tmp->value=xalloc(4); +  tmp->value = tmp->name + len + 1;    memcpy(tmp->value," 1 ",4);    }    tmp->next = NULL; -  +     if (first_predef) {    last_predef->next = tmp;    last_predef = tmp;    }    else first_predef = last_predef = tmp;   }      void exit_cpp(void)   {   #ifdef DO_PIKE_CLEANUP    struct pike_predef_s *tmp;       EXIT;       while((tmp=first_predef))    {    free(tmp->name); -  free(tmp->value); +     first_predef=tmp->next;    free(tmp);    }    free_svalue(&defined_macro_sval);       free_string (efun_str);    free_string (constant_str);    free_string (defined_str);      #endif   }