From e02b4fa8dc2e156d7cb182aa5ab6b0f5ebed143d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Sun, 21 Nov 2010 13:41:04 +0100
Subject: [PATCH] Added the !-modifier for sscanf. Fixes [LysLysKOM 18812886].

---
 .gitattributes   |  1 -
 src/sscanf.c     | 22 +++++++++++++++++++---
 src/testsuite.in |  1 +
 src/treeopt.in   |  6 +++---
 4 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/.gitattributes b/.gitattributes
index d38f610584..0ee787125c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -799,7 +799,6 @@ testfont binary
 /src/test_co.pike foreign_ident
 /src/time_stuff.h foreign_ident
 /src/tmodule.c foreign_ident
-/src/treeopt.in foreign_ident
 /src/uncompressor.c foreign_ident
 /src/version.c foreign_ident
 /tools/pike.el foreign_ident
diff --git a/src/sscanf.c b/src/sscanf.c
index 4479aa49fe..4e10ee8f79 100644
--- a/src/sscanf.c
+++ b/src/sscanf.c
@@ -611,8 +611,8 @@ static INT32 PIKE_CONCAT4(very_low_sscanf_,INPUT_SHIFT,_,MATCH_SHIFT)(	 \
 {									 \
   struct svalue sval;							 \
   INT32 matches, arg;							 \
-  ptrdiff_t cnt, eye, e, field_length = 0;				 \
-  int no_assign = 0, minus_flag = 0, plus_flag = 0;			 \
+  ptrdiff_t cnt, eye, start_eye, e, field_length = 0, truncated = 0;	 \
+  int no_assign = 0, minus_flag = 0, plus_flag = 0, truncate = 0;	 \
   struct sscanf_set set;						 \
 									 \
 									 \
@@ -658,6 +658,8 @@ static INT32 PIKE_CONCAT4(very_low_sscanf_,INPUT_SHIFT,_,MATCH_SHIFT)(	 \
     field_length=-1;							 \
     minus_flag=0;							 \
     plus_flag=0;							 \
+    truncate=0;								 \
+    start_eye = eye;							 \
 									 \
     cnt++;								 \
     if(cnt>=match_len)							 \
@@ -694,6 +696,11 @@ static INT32 PIKE_CONCAT4(very_low_sscanf_,INPUT_SHIFT,_,MATCH_SHIFT)(	 \
 	  cnt++;							 \
 	  continue;							 \
 									 \
+        case '!':							 \
+	  truncate=1;							 \
+	  cnt++;							 \
+	  continue;							 \
+									 \
 	case '{':							 \
 	{								 \
 	  ONERROR err;							 \
@@ -1270,7 +1277,7 @@ INPUT_IS_WIDE(								 \
 	case 'n':							 \
 	  sval.type=T_INT;						 \
 	  sval.subtype=NUMBER_NUMBER;					 \
-	  sval.u.integer=TO_INT32(eye);					 \
+	  sval.u.integer=TO_INT32(eye - truncated);			 \
 	  break;							 \
 									 \
 	default:							 \
@@ -1280,6 +1287,9 @@ INPUT_IS_WIDE(								 \
       break;								 \
     }									 \
     matches++;								 \
+    if (truncate) {							 \
+      truncated += eye - start_eye;					 \
+    }									 \
 									 \
     if(no_assign)							 \
     {									 \
@@ -1456,6 +1466,8 @@ INT32 low_sscanf(struct pike_string *data, struct pike_string *format, INT32 fla
  *!     @expr{-28@}.
  *!   @value "%n"
  *!     Returns the current character offset in @[data].
+ *!     Note that any characters matching fields scanned with the
+ *!     @expr{"!"@}-modifier are removed from the count (see below).
  *!   @value "%f"
  *!     Reads a float ("0101" makes 101.0).
  *!   @value "%F"
@@ -1530,6 +1542,9 @@ INT32 low_sscanf(struct pike_string *data, struct pike_string *format, INT32 fla
  *!     Interpret the data as a signed entity. In other words,
  *!     @expr{"%+1c"@} will read @expr{"\xFF"@} as @expr{-1@} instead
  *!     of @expr{255@}, as @expr{"%1c"@} would have.
+ *!   @value "!"
+ *!     Ignore the matched characters with respect to any following
+ *!     @expr{"%n"@}.
  *! @endstring
  *!
  *! @note
@@ -1669,6 +1684,7 @@ static void push_sscanf_argument_types(PCHARP format, ptrdiff_t format_len,
 
       case '-':
       case '+':
+      case '!':
       case '0': case '1': case '2': case '3': case '4':
       case '5': case '6': case '7': case '8': case '9':
 	cnt++;
diff --git a/src/testsuite.in b/src/testsuite.in
index a7c955d692..286cf916fd 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -7704,6 +7704,7 @@ test_equal([[ array_sscanf("\51726\30212\66610\30131", "%*[ \t]%s")[0] ]],
 
 test_equal([[ array_sscanf("hej","%s") ]], [[ ({ "hej" }) ]])
 test_equal([[ array_sscanf("hej","%s%n") ]], [[ ({ "hej", 3 }) ]])
+test_equal([[ array_sscanf("hejhopp", "%*!3s%s%n") ]], [[ ({ "hopp", 4 }) ]])
 test_eval_error([[ function f=array_sscanf; f("hej","%s% ") ]])
 
 test_equal([[ array_sscanf("\x304b\x3066\x3044\x308a\x3087\x3046\x308a", "%[^\x3042\x3044\x3046\x3048\x304a]")[0] ]],
diff --git a/src/treeopt.in b/src/treeopt.in
index fd2dd946f4..f82bc56482 100644
--- a/src/treeopt.in
+++ b/src/treeopt.in
@@ -2,7 +2,7 @@
 // This file is part of Pike. For copyright information see COPYRIGHT.
 // Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 // for more information.
-// $Id: treeopt.in,v 1.101 2010/02/03 20:22:29 grubba Exp $
+// $Id$
 //
 // The tree optimizer
 //
@@ -188,7 +188,7 @@ F_GE(F_APPLY(F_CONSTANT
 //
 //   =>
 //
-// (sscanf(s, "%*" + A + "s" + "xxxx", ...) || 1) - 1
+// (sscanf(s, "%*!" + A + "s" + "xxxx", ...) || 1) - 1
 F_SSCANF(':'(4 = +,
 	     F_ARG_LIST(F_RANGE(0 = +[ pike_types_le($$->type,
 						     string_type_string)],
@@ -199,7 +199,7 @@ F_SSCANF(':'(4 = +,
 {
   struct pike_string *percent_star_string;
   struct pike_string *s_string;
-  MAKE_CONST_STRING(percent_star_string, "%*");
+  MAKE_CONST_STRING(percent_star_string, "%*!");
   MAKE_CONST_STRING(s_string, "s");
   $$ = mkopernode("`-",
 		  mknode(F_LOR,
-- 
GitLab