about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--stdio/vfscanf.c75
-rw-r--r--stdlib/strtol.c4
-rw-r--r--sysdeps/mach/hurd/closedir.c1
4 files changed, 68 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index 0d54c13488..88cdb2a86e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Sat Mar 18 14:07:08 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>
+
+	* stdio/vfscanf.c: Grok positional parameter specs (i.e. %3$d
+ 	means %d from 3rd arg).
+
+	* sysdeps/mach/hurd/closedir.c: Include hurd/fd.h.
+
+	* stdlib/strtol.c: If !GROUP, set END to null.  In loop, test only
+ 	END, not GROUP.
+
 Fri Mar 17 12:58:37 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>
 
 	* Makefile (subdirs): Put elf last.
diff --git a/stdio/vfscanf.c b/stdio/vfscanf.c
index 9a9e3bb79c..cacf16f466 100644
--- a/stdio/vfscanf.c
+++ b/stdio/vfscanf.c
@@ -60,7 +60,7 @@ DEFUN(__vfscanf, (s, format, arg),
   int group_flag;		/* %' modifier flag.  */
 
   /* Type modifiers.  */
-  char is_short, is_long, is_long_double;
+  int is_short, is_long, is_long_double;
 #ifdef	HAVE_LONGLONG
   /* We use the `L' modifier for `long long int'.  */
 #define	is_longlong	is_long_double
@@ -108,6 +108,18 @@ DEFUN(__vfscanf, (s, format, arg),
   /* Run through the format string.  */
   while (*f != '\0')
     {
+      unsigned int argpos;
+      /* Extract the next argument, which is of type TYPE.
+	 For a %N$... spec, this is the Nth argument from the beginning;
+	 otherwise it is the next argument after the state now in ARG.  */
+#define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
+			 ({ unsigned int pos = argpos;			      \
+			    va_list arg = (va_list) argptr;		      \
+			    while (--pos > 0)				      \
+			      (void) va_arg (arg, void *);		      \
+			    va_arg (arg, type);				      \
+			  }))
+
       if (!isascii (*f))
 	{
 	  /* Non-ASCII, may be a multibyte.  */
@@ -145,9 +157,30 @@ DEFUN(__vfscanf, (s, format, arg),
 	  continue;
 	}
 
-      /* Check for the assignment-suppressant and the number grouping flag.  */
+      /* Initialize state of modifiers.  */
+      argpos = 0;
       do_assign = 1;
       group_flag = 0;
+      is_short = is_long = is_long_double = malloc_string = 0;
+
+      /* Check for a positional parameter specification.  */
+      if (isdigit (*f))
+	{
+	  argpos = *f++ - '0';
+	  while (isdigit (*f))
+	    argpos = argpos * 10 + (*f++ - '0');
+	  if (*f == '$')
+	    ++f;
+	  else
+	    {
+	      /* Oops; that was actually the field width.  */
+	      width = argpos;
+	      argpos = 0;
+	      goto got_width;
+	    }
+	}
+
+      /* Check for the assignment-suppressant and the number grouping flag.  */
       while (*f == '*' || *f == '\'')
 	switch (*f++)
 	  {
@@ -166,11 +199,11 @@ DEFUN(__vfscanf, (s, format, arg),
 	  width *= 10;
 	  width += *f++ - '0';
 	}
+    got_width:
       if (width == 0)
 	width = -1;
 
       /* Check for type modifiers.  */
-      is_short = is_long = is_long_double = malloc_string = 0;
       while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q')
 	switch (*f++)
 	  {
@@ -218,13 +251,13 @@ DEFUN(__vfscanf, (s, format, arg),
 
 	case 'n':	/* Answer number of assignments done.  */
 	  if (do_assign)
-	    *va_arg(arg, int *) = read_in;
+	    *ARG (int *) = read_in;
 	  break;
 
 	case 'c':	/* Match characters.  */
 	  if (do_assign)
 	    {
-	      str = va_arg (arg, char *);
+	      str = ARG (char *);
 	      if (str == NULL)
 		conv_error ();
 	    }
@@ -256,7 +289,7 @@ DEFUN(__vfscanf, (s, format, arg),
 	      if (malloc_string)					      \
 		{							      \
 		  /* The string is to be stored in a malloc'd buffer.  */     \
-		  strptr = va_arg (arg, char **);			      \
+		  strptr = ARG (char **);			      \
 		  if (strptr == NULL)					      \
 		    conv_error ();					      \
 		  /* Allocate an initial buffer.  */			      \
@@ -264,7 +297,7 @@ DEFUN(__vfscanf, (s, format, arg),
 		  *strptr = str = malloc (strsize);			      \
 		}							      \
 	      else							      \
-		str = va_arg (arg, char *);				      \
+		str = ARG (char *);				      \
 	      if (str == NULL)						      \
 		conv_error ();						      \
 	    }
@@ -406,16 +439,16 @@ DEFUN(__vfscanf, (s, format, arg),
 
 	  /* Convert the number.  */
 	  *w = '\0';
-	  if (number_signed)
+	  if (is_longlong)
 	    {
-	      if (is_longlong)
+	      if (number_signed)
 		num.q = __strtoq_internal (work, &w, base, group_flag);
 	      else
 		num.uq = __strtouq_internal (work, &w, base, group_flag);
 	    }
 	  else
 	    {
-	      if (is_long_double)
+	      if (number_signed)
 		num.l = __strtol_internal (work, &w, base, group_flag);
 	      else
 		num.ul = __strtoul_internal (work, &w, base, group_flag);
@@ -428,25 +461,25 @@ DEFUN(__vfscanf, (s, format, arg),
 	      if (! number_signed)
 		{
 		  if (is_longlong)
-		    *va_arg (arg, unsigned LONGLONG int *) = num.uq;
+		    *ARG (unsigned LONGLONG int *) = num.uq;
 		  else if (is_long)
-		    *va_arg (arg, unsigned long int *) = num.ul;
+		    *ARG (unsigned long int *) = num.ul;
 		  else if (is_short)
-		    *va_arg (arg, unsigned short int *)
+		    *ARG (unsigned short int *)
 		      = (unsigned short int) num.ul;
 		  else
-		    *va_arg (arg, unsigned int *) = (unsigned int) num.ul;
+		    *ARG (unsigned int *) = (unsigned int) num.ul;
 		}
 	      else
 		{
 		  if (is_longlong)
-		    *va_arg (arg, LONGLONG int *) = num.q;
+		    *ARG (LONGLONG int *) = num.q;
 		  else if (is_long)
-		    *va_arg (arg, long int *) = num.l;
+		    *ARG (long int *) = num.l;
 		  else if (is_short)
-		    *va_arg (arg, short int *) = (short int) num.l;
+		    *ARG (short int *) = (short int) num.l;
 		  else
-		    *va_arg (arg, int *) = (int) num.l;
+		    *ARG (int *) = (int) num.l;
 		}
 	      ++done;
 	    }
@@ -505,19 +538,19 @@ DEFUN(__vfscanf, (s, format, arg),
 	    {
 	      long double d = __strtold_internal (work, &w, group_flag);
 	      if (do_assign && w != work)
-		*va_arg (arg, long double *) = d;
+		*ARG (long double *) = d;
 	    }
 	  else if (is_long)
 	    {
 	      double d = __strtod_internal (work, &w, group_flag);
 	      if (do_assign && w != work)
-		*va_arg (arg, double *) = d;
+		*ARG (double *) = d;
 	    }
 	  else
 	    {
 	      float d = __strtof_internal (work, &w, group_flag);
 	      if (do_assign && w != work)
-		*va_arg (arg, float *) = d;
+		*ARG (float *) = d;
 	    }
 
 	  if (w == work)
diff --git a/stdlib/strtol.c b/stdlib/strtol.c
index 1c63afb6fe..a6c19578a2 100644
--- a/stdlib/strtol.c
+++ b/stdlib/strtol.c
@@ -175,6 +175,8 @@ INTERNAL (strtol) (nptr, endptr, base, group)
       else
 	end = correctly_grouped_prefix (s, end, thousands, grouping);
     }
+  else
+    end = NULL;
 
   cutoff = ULONG_MAX / (unsigned LONG int) base;
   cutlim = ULONG_MAX % (unsigned LONG int) base;
@@ -183,7 +185,7 @@ INTERNAL (strtol) (nptr, endptr, base, group)
   i = 0;
   for (c = *s; c != '\0'; c = *++s)
     {
-      if (group && s == end)
+      if (s == end)
 	break;
       if (isdigit (c))
 	c -= '0';
diff --git a/sysdeps/mach/hurd/closedir.c b/sysdeps/mach/hurd/closedir.c
index bb970aed9e..6ac86a6cd4 100644
--- a/sysdeps/mach/hurd/closedir.c
+++ b/sysdeps/mach/hurd/closedir.c
@@ -23,6 +23,7 @@ Cambridge, MA 02139, USA.  */
 #include <dirent.h>
 #include <unistd.h>
 #include <hurd.h>
+#include <hurd/fd.h>
 
 /* Close the directory stream DIRP.
    Return 0 if successful, -1 if not.  */