From 75a9f6813e17d411b148608a3e417630b14ef90a Mon Sep 17 00:00:00 2001
From: Arne Goedeke <el@laramies.com>
Date: Sun, 4 Dec 2011 20:55:56 +0100
Subject: [PATCH] cpp: handle exception in magic define, fixed prefix handling

---
 lib/modules/Pike.pmod/module.pmod |  8 +++++
 src/cpp.c                         | 42 +++++++++++++++++-----
 src/preprocessor.h                | 58 +++++++++++++++++--------------
 3 files changed, 73 insertions(+), 35 deletions(-)

diff --git a/lib/modules/Pike.pmod/module.pmod b/lib/modules/Pike.pmod/module.pmod
index da139d0950..d70f3e57ad 100644
--- a/lib/modules/Pike.pmod/module.pmod
+++ b/lib/modules/Pike.pmod/module.pmod
@@ -80,6 +80,14 @@ constant low_check_call = predef::__low_check_call;
 constant get_return_type = predef::__get_return_type;
 constant get_first_arg_type = predef::__get_first_arg_type;
 
+// precompile.pike checks for this
+#if constant(__builtin.__HAVE_CPP_PREFIX_SUPPORT__)
+//! This constant exists and has the value 1 if cpp supports
+//! the prefix feature.
+//! @seealso @[cpp()]
+constant __HAVE_CPP_PREFIX_SUPPORT__ = __builtin.__HAVE_CPP_PREFIX_SUPPORT__;
+#endif
+
 program Encoder = [program] master()->Encoder;
 program Decoder = [program] master()->Decoder;
 program Codec = [program] master()->Codec;
diff --git a/src/cpp.c b/src/cpp.c
index 81b2380e3c..6f5d5b872c 100644
--- a/src/cpp.c
+++ b/src/cpp.c
@@ -1042,8 +1042,9 @@ static void simple_add_define(struct cpp *this,
 		   (data[pos+1] == '\n')) {			\
 	  pos+=2;						\
 	} else {						\
-	  break;						\
+	    continue;						\
 	}							\
+        this->current_line++;					\
       default:							\
 	continue;						\
       }								\
@@ -1601,7 +1602,14 @@ void free_one_define(struct hash_entry *h)
 static ptrdiff_t low_cpp(struct cpp *this, void *data, ptrdiff_t len,
 			 int shift, int flags, int auto_convert,
 			 struct pike_string *charset);
-
+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);
 #define SHIFT 0
 #include "preprocessor.h"
 #undef SHIFT
@@ -1731,10 +1739,10 @@ static void insert_callback_define(struct cpp *this,
 {
   ref_push_string( def->link.s );
   push_string( make_shared_binary_pcharp( args[0].arg, args[0].len ) );
-  safe_apply_handler( "evaluate_define", this->handler, this->compat_handler, 2, 0 );
-  if( TYPEOF(sp[-1]) == T_STRING )
+  if (safe_apply_handler( "evaluate_define", this->handler, this->compat_handler, 2, 0 ) && TYPEOF(sp[-1]) == T_STRING ) {
     string_builder_shared_strcat(tmp, sp[-1].u.string);
-  pop_stack();
+    pop_stack();
+  }
 }
 
 static void insert_callback_define_no_args(struct cpp *this,
@@ -1742,11 +1750,11 @@ static void insert_callback_define_no_args(struct cpp *this,
                                            struct define_argument *args,
                                            struct string_builder *tmp)
 {
+  struct svalue *save_sp = Pike_sp;
   ref_push_string( def->link.s );
-  safe_apply_handler( "evaluate_define", this->handler, this->compat_handler, 1, 0 );
-  if( TYPEOF(sp[-1]) == T_STRING )
+  if (safe_apply_handler( "evaluate_define", this->handler, this->compat_handler, 1, 0 ) && TYPEOF(sp[-1]) == T_STRING )
     string_builder_shared_strcat(tmp, sp[-1].u.string);
-  pop_stack();
+  if (Pike_sp > save_sp) pop_n_elems(Pike_sp-save_sp);
 }
 
 /*! @namespace predef:: */
@@ -2099,6 +2107,20 @@ void f_cpp(INT32 args)
 	    free_mapping (predefs);
 	    predefs = NULL;
 	    goto predef_map_error;
+	  } 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) {
+
+	     push_constant_text ("expected zero, string or function value for"
+				 " predefine\n");
+	     push_constant_text ("expected zero, string or function value for"
+				 " predefine %O\n");
+	     push_svalue (&k->ind);
+	     sprintf_args = 2;
+	     free_mapping (predefs);
+	     predefs = NULL;
+	     goto predef_map_error;
 	  }
 	}
       }
@@ -2186,7 +2208,7 @@ void f_cpp(INT32 args)
     NEW_MAPPING_LOOP (predefs->data) {
       if (TYPEOF(k->val) == T_STRING)
 	add_define (&this, k->ind.u.string, k->val.u.string);
-      else if(TYPEOF(k->val) != T_INT || k->val.u.integer )
+      else if(TYPEOF(k->val) == T_FUNCTION || TYPEOF(k->val) == T_OBJECT)
       {
         struct define *def;
         if( index_shared_string( k->ind.u.string, k->ind.u.string->len-1) == ')' )
@@ -2287,6 +2309,8 @@ void init_cpp()
 	   /* OPT_SIDE_EFFECT since we might instantiate modules etc. */
 	   OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);
 
+  ADD_INT_CONSTANT("__HAVE_CPP_PREFIX_SUPPORT__", 1, 0);
+
   /* Somewhat tricky to add a _constant_ function in _static_modules.Builtin. */
   SET_SVAL(s, T_FUNCTION, FUNCTION_BUILTIN, efun,
 	   make_callable (f__take_over_initial_predefines,
diff --git a/src/preprocessor.h b/src/preprocessor.h
index fb24131c86..36f73b23db 100644
--- a/src/preprocessor.h
+++ b/src/preprocessor.h
@@ -1063,6 +1063,10 @@ static ptrdiff_t lower_cpp(struct cpp *this,
 			   int auto_convert,
 			   struct pike_string *charset)
 {
+  static const WCHAR string_recur_[] =
+    { 's', 't', 'r', 'i', 'n', 'g', '_', 'r', 'e', 'c', 'u', 'r' };
+  static const WCHAR include_recur_[] =
+   { 'i', 'n', 'c', 'l', 'u', 'd', 'e', '_', 'r', 'e', 'c', 'u', 'r' };
   ptrdiff_t pos, tmp, e;
   int include_mode;
   INT32 first_line = this->current_line;
@@ -1434,7 +1438,9 @@ static ptrdiff_t lower_cpp(struct cpp *this,
 	  }
 	  
 	  /* Remove any newlines from the completed expression. */
-	  switch (tmp.s->size_shift) {
+	  if (!(d->magic == insert_callback_define
+	     || d->magic == insert_callback_define_no_args))
+	     switch (tmp.s->size_shift) {
 	  case 0:
 	    for(e=0; e< (ptrdiff_t)tmp.s->len; e++)
 	      if(STR0(tmp.s)[e]=='\n')
@@ -1534,31 +1540,35 @@ static ptrdiff_t lower_cpp(struct cpp *this,
     }
     SKIPSPACE();
 
-    if (this->prefix) {
-	int i;
-	if (this->prefix->len+1 >= len-pos) {
-	    goto ADD_TO_BUFFER;
-	}
-	for (i = 0; i < this->prefix->len; i++) {
-	    if (this->prefix->str[i] != data[pos+i]) {
-		FIND_EOS();
+    if (!CHECKWORD2(string_recur_, NELEM(string_recur_))
+     && !CHECKWORD2(include_recur_, NELEM(include_recur_))) {
+	if (this->prefix) {
+	    int i;
+	    if (this->prefix->len+1 >= len-pos) {
 		goto ADD_TO_BUFFER;
 	    }
-	}
-	if (data[pos+i] != '_') {
-	    FIND_EOS();
-	    goto ADD_TO_BUFFER;
-	}
-
-	pos += this->prefix->len + 1;
-    } else {
-	int i;
-	for (i = pos; i < len; i++) {
-	    if (data[i] == '_') {
+	    for (i = 0; i < this->prefix->len; i++) {
+		if (this->prefix->str[i] != data[pos+i]) {
+		    FIND_EOS();
+		    goto ADD_TO_BUFFER;
+		}
+	    }
+	    if (data[pos+i] != '_') {
 		FIND_EOS();
 		goto ADD_TO_BUFFER;
-	    } else if (!WC_ISIDCHAR(data[i]))
-		break;
+	    }
+
+	    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 (!WC_ISIDCHAR(data[i]))
+		    break;
+	    }
 	}
     }
 
@@ -1637,8 +1647,6 @@ static ptrdiff_t lower_cpp(struct cpp *this,
       case 's':
 	{
 	  static const WCHAR string_[] = { 's', 't', 'r', 'i', 'n', 'g' };
-	  static const WCHAR string_recur_[] =
-	    { 's', 't', 'r', 'i', 'n', 'g', '_', 'r', 'e', 'c', 'u', 'r' };
 
 	  if(WGOBBLE2(string_))
 	  {
@@ -1656,8 +1664,6 @@ static ptrdiff_t lower_cpp(struct cpp *this,
     case 'i': /* include, if, ifdef */
       {
 	static const WCHAR include_[] = { 'i', 'n', 'c', 'l', 'u', 'd', 'e' };
-	static const WCHAR include_recur_[] =
-	  { 'i', 'n', 'c', 'l', 'u', 'd', 'e', '_', 'r', 'e', 'c', 'u', 'r' };
 	static const WCHAR if_[] = { 'i', 'f' };
 	static const WCHAR ifdef_[] = { 'i', 'f', 'd', 'e', 'f' };
 	static const WCHAR ifndef_[] = { 'i', 'f', 'n', 'd', 'e', 'f' };
-- 
GitLab