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]

Re: implement printf("%a")


Eric Blake <ebb9 <at> byu.net> writes:

> > Thus, I am proposing a _WANT_IO_C99 flag (optionally
> > _WANT_IO_C99_FORMATS).  The default is no for all platforms except for
> > *-linux and Cygwin where it will default to yes.  The flag will remove
> > the 'a', 'A', 'z', etc... specifiers that do not appear in C90.
> > 
> > This would be implemented the same as long_long and long_double are
> > today and have a configure option.
> 
> OK, I'll work on that next.  It may be a day or two before I have time to
> complete it.

How about this?

2007-05-11  Eric Blake  <ebb9@byu.net>

	Minimize printf/scanf size on platforms that don't need C99.
	* acconfig.h (_WANT_IO_C99_FORMATS): New macro.
	* newlib.hin (_WANT_IO_C99_FORMATS): Likewise.
	* configure.in (newlib-io-c99-formats): New configure option.
	(_WANT_IO_C99_FORMATS): Define appropriately.
	* configure.host (*-linux*, cygwin): Default c99-formats to yes.
	* libc/stdio/vfprintf.c (_VFPRINTF_R) [!_WANT_IO_C99_FORMATS]:
	Cripple ' flag; hh, z, j, t sizes; a, A, F, C, S specifiers.
	* libc/stdio/vfscanf.c (_VFSCANF_R) [!_WANT_IO_C99_FORMATS]:
	Likewise.
	* configure: Regenerate.

Index: acconfig.h
===================================================================
RCS file: /cvs/src/src/newlib/acconfig.h,v
retrieving revision 1.3
diff -u -p -r1.3 acconfig.h
--- acconfig.h	15 Mar 2007 21:32:09 -0000	1.3
+++ acconfig.h	11 May 2007 16:28:35 -0000
@@ -9,6 +9,10 @@
 /* Newlib version */
 #undef _NEWLIB_VERSION
 
+/* C99 formats support (such as %a, %zu, ...) in IO functions like
+ * printf/scanf enabled */
+#undef _WANT_IO_C99_FORMATS
+
 /* long long type support in IO functions like printf/scanf enabled */
 #undef _WANT_IO_LONG_LONG
 
Index: configure.host
===================================================================
RCS file: /cvs/src/src/newlib/configure.host,v
retrieving revision 1.93
diff -u -p -r1.93 configure.host
--- configure.host	20 Feb 2007 21:02:36 -0000	1.93
+++ configure.host	11 May 2007 16:28:35 -0000
@@ -24,6 +24,7 @@
 #   target_optspace	--enable-target-optspace ("yes", "no", "")
 #   newlib_multithread	--enable-newlib-multithread ("yes", "no", "yes")
 #   newlib_elix_level	--enable-newlib-elix-level ("1","2","3","4") ("4")
+#   newlib_io_c99_formats --enable-newlib-io-c99-formats ("yes", "no", "")
 #   newlib_io_long_long --enable-newlib-io-long-long ("yes", "no", "")
 #   newlib_io_long_double --enable-newlib-io-long-double ("yes", "no", "")
 
@@ -62,6 +63,7 @@ crt1_dir=
 have_crt0=
 use_libtool=no
 have_sys_mach_dir=no
+default_newlib_io_c99_formats=no
 default_newlib_io_long_long=no
 default_newlib_io_long_double=no
 default_newlib_io_pos_args=no
@@ -398,6 +400,7 @@ case "${host}" in
 	crt1=crt1.o
 	crt1_dir=libc/sys/${sys_dir}	
 	gcc_dir=`gcc -print-search-dirs | awk '/^install:/{print $2}'`
+	default_newlib_io_c99_formats="yes"
 	default_newlib_io_long_double="yes"
 	default_newlib_io_long_long="yes"
 	default_newlib_io_pos_args="yes"
@@ -498,6 +501,7 @@ case "${host}" in
   *-*-cygwin*)
 	test -z "$cygwin_srcdir" && cygwin_srcdir=`cd 
${srcdir}/../winsup/cygwin; pwd`
 	export cygwin_srcdir
+	default_newlib_io_c99_formats="yes"
 	default_newlib_io_long_long="yes"
 	default_newlib_io_long_double="yes"
 	default_newlib_io_pos_args="yes"
@@ -744,6 +748,13 @@ esac
 
 # Use defaults for certain settings if not specified by user
 
+# Enable C99 format support in I/O routines if requested.
+if [ "x${newlib_io_c99_formats}" = "x" ]; then
+	if [ ${default_newlib_io_c99_formats} = "yes" ]; then
+		newlib_io_c99_formats="yes";
+	fi
+fi
+
 # Enable long long support in I/O routines if requested.
 if [ "x${newlib_io_long_long}" = "x" ]; then
 	if [ ${default_newlib_io_long_long} = "yes" ]; then
Index: configure.in
===================================================================
RCS file: /cvs/src/src/newlib/configure.in,v
retrieving revision 1.35
diff -u -p -r1.35 configure.in
--- configure.in	15 Mar 2007 21:32:12 -0000	1.35
+++ configure.in	11 May 2007 16:28:35 -0000
@@ -20,6 +20,15 @@ AC_ARG_ENABLE(newlib-io-pos-args,
   *)   AC_MSG_ERROR(bad value ${enableval} for newlib-io-pos-args option) ;;
  esac], [newlib_io_pos_args=])dnl
 
+dnl Support --enable-newlib-io-c99-formats
+AC_ARG_ENABLE(newlib-io-c99-formats,
+[  --enable-newlib-io-c99-formats   enable C99 support in IO functions like 
printf/scanf],
+[case "${enableval}" in
+  yes) newlib_io_c99_formats=yes;;
+  no)  newlib_io_c99_formats=no ;;
+  *)   AC_MSG_ERROR(bad value ${enableval} for newlib-io-c99-formats option) ;;
+ esac], [newlib_io_c99_formats=])dnl
+
 dnl Support --enable-newlib-io-long-long
 AC_ARG_ENABLE(newlib-io-long-long,
 [  --enable-newlib-io-long-long   enable long long type support in IO 
functions like printf/scanf],
@@ -229,6 +238,10 @@ if test "${newlib_elix_level}" -gt "0"; 
 AC_DEFINE_UNQUOTED(_ELIX_LEVEL,${newlib_elix_level})
 fi
 
+if test "${newlib_io_c99_formats}" = "yes"; then
+AC_DEFINE_UNQUOTED(_WANT_IO_C99_FORMATS)
+fi
+
 if test "${newlib_io_long_long}" = "yes"; then
 AC_DEFINE_UNQUOTED(_WANT_IO_LONG_LONG)
 fi
Index: newlib.hin
===================================================================
RCS file: /cvs/src/src/newlib/newlib.hin,v
retrieving revision 1.13
diff -u -p -r1.13 newlib.hin
--- newlib.hin	15 Mar 2007 21:32:12 -0000	1.13
+++ newlib.hin	11 May 2007 16:28:35 -0000
@@ -9,6 +9,10 @@
 /* Newlib version */
 #undef _NEWLIB_VERSION
 
+/* C99 formats support (such as %a, %zu, ...) in IO functions like
+ * printf/scanf enabled */
+#undef _WANT_IO_C99_FORMATS
+
 /* long long type support in IO functions like printf/scanf enabled */
 #undef _WANT_IO_LONG_LONG
 
Index: libc/stdio/vfprintf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/vfprintf.c,v
retrieving revision 1.57
diff -u -p -r1.57 vfprintf.c
--- libc/stdio/vfprintf.c	11 May 2007 13:09:44 -0000	1.57
+++ libc/stdio/vfprintf.c	11 May 2007 16:28:35 -0000
@@ -319,16 +319,20 @@ _EXFUN(get_arg, (struct _reent *data, in
 #define	LONGDBL		0x008		/* long double */
 #define	LONGINT		0x010		/* long integer */
 #ifndef _NO_LONGLONG
-#define	QUADINT		0x020		/* quad integer */
+# define QUADINT	0x020		/* quad integer */
 #else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
 	 that %lld behaves the same as %ld, not as %d, as expected if:
 	 sizeof (long long) = sizeof long > sizeof int  */
-#define	QUADINT		LONGINT
+# define QUADINT	LONGINT
 #endif
 #define	SHORTINT	0x040		/* short integer */
 #define	ZEROPAD		0x080		/* zero (as opposed to blank) 
pad */
 #define FPT		0x100		/* Floating point number */
-#define CHARINT		0x200		/* char as integer */
+#ifdef _WANT_IO_C99_FORMATS
+# define CHARINT	0x200		/* char as integer */
+#else /* define as 0, to make SARG and UARG occupy fewer instructions  */
+# define CHARINT	0
+#endif
 
 int _EXFUN(_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list));
 
@@ -565,12 +569,15 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap)
 
 rflag:		ch = *fmt++;
 reswitch:	switch (ch) {
+#ifdef _WANT_IO_C99_FORMATS
 		case '\'':
-		  /* In the C locale, LC_NUMERIC requires
+		  /* The ' flag is required by POSIX, but not C99.
+		     In the C locale, LC_NUMERIC requires
 		     thousands_sep to be the empty string.  And since
 		     no other locales are supported (yet), this flag
 		     is currently a no-op.  */
 		  goto rflag;
+#endif
 		case ' ':
 			/*
 			 * ``If the space and + flags both appear, the space
@@ -714,24 +721,27 @@ reswitch:	switch (ch) {
 			goto rflag;
 #endif
 		case 'h':
+#ifdef _WANT_IO_C99_FORMATS
 			if (*fmt == 'h') {
 				fmt++;
 				flags |= CHARINT;
-			} else {
+			} else
+#endif
 				flags |= SHORTINT;
-			}
 			goto rflag;
 		case 'l':
+#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
 			if (*fmt == 'l') {
 				fmt++;
 				flags |= QUADINT;
-			} else {
+			} else
+#endif
 				flags |= LONGINT;
-			}
 			goto rflag;
-		case 'q':
+		case 'q': /* extension */
 			flags |= QUADINT;
 			goto rflag;
+#ifdef _WANT_IO_C99_FORMATS
 		case 'j':
 		  if (sizeof (intmax_t) == sizeof (long))
 		    flags |= LONGINT;
@@ -769,8 +779,9 @@ reswitch:	switch (ch) {
 		       have ptrdiff_t as wide as long long.  */
 		    flags |= QUADINT;
 		  goto rflag;
-		case 'c':
 		case 'C':
+#endif /* _WANT_IO_C99_FORMATS */
+		case 'c':
 			cp = buf;
 #ifdef _MB_CAPABLE
 			if (ch == 'C' || (flags & LONGINT)) {
@@ -792,7 +803,7 @@ reswitch:	switch (ch) {
 			}
 			sign = '\0';
 			break;
-		case 'D':
+		case 'D':  /* extension */
 			flags |= LONGINT;
 			/*FALLTHROUGH*/
 		case 'd':
@@ -811,12 +822,14 @@ reswitch:	switch (ch) {
 			base = DEC;
 			goto number;
 #ifdef FLOATING_POINT
+# ifdef _WANT_IO_C99_FORMATS
 		case 'a':
 		case 'A':
+		case 'F':
+# endif
 		case 'e':
 		case 'E':
 		case 'f':
-		case 'F':
 		case 'g':
 		case 'G':
 # ifdef _NO_LONGDBL
@@ -835,7 +848,7 @@ reswitch:	switch (ch) {
 			if (isinf (_fpvalue)) {
 				if (_fpvalue < 0)
 					sign = '-';
-				if (ch <= 'G') /* 'E', 'F', or 'G' */
+				if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
 					cp = "INF";
 				else
 					cp = "inf";
@@ -844,7 +857,7 @@ reswitch:	switch (ch) {
 				break;
 			}
 			if (isnan (_fpvalue)) {
-				if (ch <= 'G') /* 'E', 'F', or 'G' */
+				if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
 					cp = "NAN";
 				else
 					cp = "nan";
@@ -866,7 +879,7 @@ reswitch:	switch (ch) {
 			if (tmp == 2) {
 				if (_fpvalue < 0)
 					sign = '-';
-				if (ch <= 'G') /* 'E', 'F', or 'G' */
+				if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
 					cp = "INF";
 				else
 					cp = "inf";
@@ -875,7 +888,7 @@ reswitch:	switch (ch) {
 				break;
 			}
 			if (tmp == 1) {
-				if (ch <= 'G') /* 'E', 'F', or 'G' */
+				if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
 					cp = "NAN";
 				else
 					cp = "nan";
@@ -885,6 +898,7 @@ reswitch:	switch (ch) {
 			}
 # endif /* !_NO_LONGDBL */
 
+# ifdef _WANT_IO_C99_FORMATS
 			if (ch == 'a' || ch == 'A') {
 				ox[0] = '0';
 				ox[1] = ch == 'a' ? 'x' : 'X';
@@ -902,7 +916,9 @@ reswitch:	switch (ch) {
 				  }
 				else
 				  cp = buf;
-			} else if (prec == -1) {
+			} else
+# endif /* _WANT_IO_C99_FORMATS */
+			if (prec == -1) {
 				prec = DEFPREC;
 			} else if ((ch == 'g' || ch == 'G') && prec == 0) {
 				prec = 1;
@@ -919,8 +935,10 @@ reswitch:	switch (ch) {
 				else
 					ch = 'g';
 			}
+# ifdef _WANT_IO_C99_FORMATS
 			else if (ch == 'F')
 				ch = 'f';
+# endif
 			if (ch <= 'e') {	/* 'a', 'A', 'e', or 'E' fmt */
 				--expt;
 				expsize = exponent (expstr, expt, ch);
@@ -958,12 +976,14 @@ reswitch:	switch (ch) {
 				*GET_ARG (N, ap, long_ptr_t) = ret;
 			else if (flags & SHORTINT)
 				*GET_ARG (N, ap, short_ptr_t) = ret;
+#ifdef _WANT_IO_C99_FORMATS
 			else if (flags & CHARINT)
 				*GET_ARG (N, ap, char_ptr_t) = ret;
+#endif
 			else
 				*GET_ARG (N, ap, int_ptr_t) = ret;
 			continue;	/* no output */
-		case 'O':
+		case 'O': /* extension */
 			flags |= LONGINT;
 			/*FALLTHROUGH*/
 		case 'o':
@@ -986,7 +1006,9 @@ reswitch:	switch (ch) {
 			ch = 'x';
 			goto nosign;
 		case 's':
+#ifdef _WANT_IO_C99_FORMATS
 		case 'S':
+#endif
 			sign = '\0';
 			if ((cp = GET_ARG (N, ap, char_ptr_t)) == NULL) {
 				cp = "(null)";
@@ -1068,7 +1090,7 @@ reswitch:	switch (ch) {
 				size = strlen (cp);
 
 			break;
-		case 'U':
+		case 'U': /* extension */
 			flags |= LONGINT;
 			/*FALLTHROUGH*/
 		case 'u':
@@ -1357,6 +1379,7 @@ _DEFUN(cvt, (data, value, ndigits, flags
 		*sign = '\000';
 # endif /* !_NO_LONGDBL */
 
+# ifdef _WANT_IO_C99_FORMATS
 	if (ch == 'a' || ch == 'A') {
 		/* This code assumes FLT_RADIX is a power of 2.  The initial
 		   division ensures the digit before the decimal will be less
@@ -1387,7 +1410,9 @@ _DEFUN(cvt, (data, value, ndigits, flags
 		}
 		*length = bp - buf;
 		return buf;
-	} else if (ch == 'f' || ch == 'F') {
+        }
+# endif /* _WANT_IO_C99_FORMATS */
+	if (ch == 'f' || ch == 'F') {
 		mode = 3;		/* ndigits after the decimal point */
 	} else {
 		/* To obtain ndigits after the decimal point for the 'e'
@@ -1426,7 +1451,11 @@ _DEFUN(exponent, (p0, exp, fmtch),
 {
 	register char *p, *t;
 	char expbuf[10];
+# ifdef _WANT_IO_C99_FORMATS
 	int isa = fmtch == 'a' || fmtch == 'A';
+# else
+#  define isa 0
+# endif
 
 	p = p0;
 	*p++ = isa ? 'p' - 'a' + fmtch : fmtch;
@@ -1682,6 +1711,7 @@ _DEFUN(get_arg, (data, n, fmt, ap, numar
 		case 'q':
 		  flags |= QUADINT;
 		  break;
+# ifdef _WANT_IO_C99_FORMATS
 		case 'j':
 		  if (sizeof (intmax_t) == sizeof (long))
 		    flags |= LONGINT;
@@ -1712,14 +1742,17 @@ _DEFUN(get_arg, (data, n, fmt, ap, numar
 		       have ptrdiff_t as wide as long long.  */
 		    flags |= QUADINT;
 		  break;
+# endif /* _WANT_IO_C99_FORMATS */
 		case 'l':
 		default:
+# if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
 		  if (*fmt == 'l')
 		    {
 		      flags |= QUADINT;
 		      ++fmt;
 		    }
 		  else
+# endif
 		    flags |= LONGINT;
 		  break;
 		}
@@ -1750,36 +1783,44 @@ _DEFUN(get_arg, (data, n, fmt, ap, numar
 		  case 'O':
 		    spec_type = LONG_INT;
 		    break;
+# ifdef _WANT_IO_C99_FORMATS
 		  case 'a':
 		  case 'A':
-		  case 'f':
 		  case 'F':
+# endif
+		  case 'f':
 		  case 'g':
 		  case 'G':
 		  case 'E':
 		  case 'e':
-#ifndef _NO_LONGDBL
+# ifndef _NO_LONGDBL
 		    if (flags & LONGDBL)
 		      spec_type = LONG_DOUBLE;
 		    else
-#endif
+# endif
 		      spec_type = DOUBLE;
 		    break;
 		  case 's':
+# ifdef _WANT_IO_C99_FORMATS
 		  case 'S':
+# endif
 		  case 'p':
 		  case 'n':
 		    spec_type = CHAR_PTR;
 		    break;
 		  case 'c':
+# ifdef _WANT_IO_C99_FORMATS
 		    if (flags & LONGINT)
 		      spec_type = WIDE_CHAR;
 		    else
+# endif
 		      spec_type = INT;
 		    break;
+# ifdef _WANT_IO_C99_FORMATS
 		  case 'C':
 		    spec_type = WIDE_CHAR;
 		    break;
+# endif
 		  }
 
 		/* if we have a positional parameter, just store the type, 
otherwise
Index: libc/stdio/vfscanf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/vfscanf.c,v
retrieving revision 1.34
diff -u -p -r1.34 vfscanf.c
--- libc/stdio/vfscanf.c	17 Apr 2007 20:53:24 -0000	1.34
+++ libc/stdio/vfscanf.c	11 May 2007 16:28:35 -0000
@@ -361,26 +361,31 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	  flags |= SUPPRESS;
 	  goto again;
 	case 'l':
+#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
 	  if (*fmt == 'l')	/* Check for 'll' = long long (SUSv3) */
 	    {
 	      ++fmt;
 	      flags |= LONGDBL;
 	    }
 	  else
+#endif
 	    flags |= LONG;
 	  goto again;
 	case 'L':
 	  flags |= LONGDBL;
 	  goto again;
 	case 'h':
+#ifdef _WANT_IO_C99_FORMATS
 	  if (*fmt == 'h')	/* Check for 'hh' = char int (SUSv3) */
 	    {
 	      ++fmt;
 	      flags |= CHAR;
 	    }
 	  else
+#endif
 	    flags |= SHORT;
 	  goto again;
+#ifdef _WANT_IO_C99_FORMATS
         case 'j':               /* intmax_t */
 	  if (sizeof (intmax_t) == sizeof (long))
 	    flags |= LONG;
@@ -418,6 +423,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	       have size_t as wide as long long.  */
 	    flags |= LONGDBL;
 	  goto again;
+#endif /* _WANT_IO_C99_FORMATS */
 
 	case '0':
 	case '1':
@@ -470,7 +476,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	  base = 10;
 	  break;
 
-	case 'X':		/* compat   XXX */
+	case 'X':
 	case 'x':
 	  flags |= PFXOK;	/* enable 0x prefixing */
 	  c = CT_INT;
@@ -479,19 +485,25 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	  break;
 
 #ifdef FLOATING_POINT
-	case 'E':		/* compat   XXX */
-	case 'G':		/* compat   XXX */
-/* ANSI says that E,G and X behave the same way as e,g,x */
-	  /* FALLTHROUGH */
+# ifdef _WANT_IO_C99_FORMATS
+	case 'a':
+	case 'A':
+	case 'F':
+# endif
+	case 'E':
+	case 'G':
 	case 'e':
 	case 'f':
 	case 'g':
 	  c = CT_FLOAT;
 	  break;
 #endif
+
+#ifdef _WANT_IO_C99_FORMATS
         case 'S':
           flags |= LONG;
           /* FALLTHROUGH */
+#endif
 
 	case 's':
 	  c = CT_STRING;
@@ -503,9 +515,11 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	  c = CT_CCL;
 	  break;
 
+#ifdef _WANT_IO_C99_FORMATS
         case 'C':
           flags |= LONG;
           /* FALLTHROUGH */
+#endif
 
 	case 'c':
 	  flags |= NOSKIP;
@@ -522,12 +536,15 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	case 'n':
 	  if (flags & SUPPRESS)	/* ??? */
 	    continue;
+#ifdef _WANT_IO_C99_FORMATS
 	  if (flags & CHAR)
 	    {
 	      cp = va_arg (ap, char *);
 	      *cp = nread;
 	    }
-	  else if (flags & SHORT)
+	  else
+#endif
+          if (flags & SHORT)
 	    {
 	      sp = va_arg (ap, short *);
 	      *sp = nread;
@@ -976,11 +993,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap
 	      res = (*ccfn) (rptr, buf, (char **) NULL, base);
 	      if (flags & POINTER)
 		*(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
+#ifdef _WANT_IO_C99_FORMATS
 	      else if (flags & CHAR)
 		{
 		  cp = va_arg (ap, char *);
 		  *cp = res;
 		}
+#endif
 	      else if (flags & SHORT)
 		{
 		  sp = va_arg (ap, short *);




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