This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] handle C99 j, t, and z flags in sscanf


This patch enables support for the sscanf modifiers j (intmax_t), t
(ptrdiff_t), and z (size_t).  The support was already present in
vfprintf.c, so this is really just a copy and paste of the logic into
sscanf.c.

I updated the inline documentation comments to mention the flags.  The
corresponding docs for sprintf should really be updated too since they
don't mention them either, but I figured that could be done with another
patch.

I'm also attaching the brief testcase that I came up with as a sanity
check.  It simply round-trips %jd, %td, and %zu through sprintf/sscanf
and verifies the result.

Brian
2007-04-17  Brian Dessent  <brian@dessent.net>

	* libc/stdio/sscanf.c: Update documentation comments.
	(__SVFSCANF_R): Handle j, t, and z modifiers.

Index: libc/stdio/sscanf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/sscanf.c,v
retrieving revision 1.9
diff -u -p -r1.9 sscanf.c
--- libc/stdio/sscanf.c	28 Oct 2005 21:38:59 -0000	1.9
+++ libc/stdio/sscanf.c	17 Apr 2007 18:48:19 -0000
@@ -147,9 +147,9 @@ DESCRIPTION
 		Then <<scanf>> proceeds to the next format specification.
 
         o size
-		<<h>>, <<l>>, and <<L>> are optional size characters which
-		override the default way that <<scanf>> interprets the
-		data type of the corresponding argument.
+		<<h>>, <<j>>, <<l>>, <<L>>, <<t>>, and <<z>> are optional size
+		characters which override the default way that <<scanf>>
+		interprets the data type of the corresponding argument.
 
 
 .Modifier   Type(s)
@@ -162,6 +162,11 @@ DESCRIPTION
 .   h       D, I, O, U, X     no effect
 .           e, f, c, s, p
 .
+.   j       d, i, o, u, x, n  convert input to intmax_t,
+.                             store in intmax_t object
+.
+.   j       all others        no effect
+.
 .   l       d, i, o, u, x, n  convert input to long,
 .                             store in long object
 .
@@ -180,7 +185,18 @@ DESCRIPTION
 .   L       e, f, g, E, G     convert to long double,
 .                             store in long double
 .
-.   L      all others         no effect
+.   L       all others        no effect
+.
+.   t       d, i, o, u, x, n  convert input to ptrdiff_t,
+.                             store in ptrdiff_t object
+.
+.   t       all others        no effect
+.
+.   z       d, i, o, u, x, n  convert input to size_t,
+.                             store in size_t object
+.
+.   z       all others        no effect
+.
 
 
         o <[type]>
Index: libc/stdio/vfscanf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/vfscanf.c,v
retrieving revision 1.33
diff -u -p -r1.33 vfscanf.c
--- libc/stdio/vfscanf.c	26 Sep 2006 21:22:19 -0000	1.33
+++ libc/stdio/vfscanf.c	17 Apr 2007 18:48:19 -0000
@@ -380,6 +380,43 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	  else
 	    flags |= SHORT;
 	  goto again;
+        case 'j':               /* intmax_t */
+	  if (sizeof (intmax_t) == sizeof (long))
+	    flags |= LONG;
+	  else
+	    flags |= LONGDBL;
+	  goto again;
+        case 't':               /* ptrdiff_t */
+	  if (sizeof (ptrdiff_t) < sizeof (int))
+	    /* POSIX states ptrdiff_t is 16 or more bits, as
+	       is short.  */
+	    flags |= SHORT;
+	  else if (sizeof (ptrdiff_t) == sizeof (int))
+	    /* no flag needed */;
+	  else if (sizeof (ptrdiff_t) <= sizeof (long))
+	    flags |= LONG;
+	  else
+	    /* POSIX states that at least one programming
+	       environment must support ptrdiff_t no wider than
+	       long, but that means other environments can
+	       have ptrdiff_t as wide as long long.  */
+	    flags |= LONGDBL;
+	  goto again;
+        case 'z':               /* size_t */
+	  if (sizeof (size_t) < sizeof (int))
+	    /* POSIX states size_t is 16 or more bits, as is short.  */
+	    flags |= SHORT;
+	  else if (sizeof (size_t) == sizeof (int))
+	    /* no flag needed */;
+	  else if (sizeof (size_t) <= sizeof (long))
+	    flags |= LONG;
+	  else
+	    /* POSIX states that at least one programming
+	       environment must support size_t no wider than
+	       long, but that means other environments can
+	       have size_t as wide as long long.  */
+	    flags |= LONGDBL;
+	  goto again;
 
 	case '0':
 	case '1':
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>

  
int main ()
{
  int i;
  float f;
  char buf[1024];

#define IVAL 42
#define FVAL 42.4242F

#define ERR(fmt, ...) printf ("Line %d: " fmt "\n", \
                              __LINE__, ##__VA_ARGS__)

#define ROUNDTRIP(t, v, fmt) ({ \
    t var = 0; i = f = 0; \
    sprintf (buf, "%d " fmt " %f", IVAL, (t)v, FVAL); \
    if (getenv ("DEBUG")) printf ("%s\n", buf); \
    if (sscanf (buf, "%d " fmt " %f", &i, &var, &f) != 3) \
      ERR ("sscanf didn't return 3"); \
    else if (i != IVAL || var != (t)v || f != FVAL) \
      ERR ("wrong values: i = %d [want %d], " \
           "var = " fmt " [want " fmt "], " \
           "f = %f [want %f]", i, IVAL, var, (t)v, f, FVAL); \
  })
  
  ROUNDTRIP (intmax_t, 0, "%jd");
  ROUNDTRIP (intmax_t, -1, "%jd");
  ROUNDTRIP (intmax_t, INTMAX_MIN, "%jd");
  ROUNDTRIP (intmax_t, INTMAX_MAX, "%jd");

  ROUNDTRIP (ptrdiff_t, 0, "%td");
  ROUNDTRIP (ptrdiff_t, -1, "%td");
  ROUNDTRIP (ptrdiff_t, PTRDIFF_MIN, "%td");
  ROUNDTRIP (ptrdiff_t, PTRDIFF_MAX, "%td");

  ROUNDTRIP (size_t, 0, "%zu");
  ROUNDTRIP (size_t, SIZE_MAX, "%zu");

  exit (0);
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]