delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2012/12/21/19:16:26

X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f
X-Recipient: djgpp-workers AT delorie DOT com
X-Authenticated: #27081556
X-Provags-ID: V01U2FsdGVkX18kCCJ6sYUkKMX3sx8IIRpUVK5roMV6Xi3l0Dr3DY
xzj/nbLz/kIYNf
Message-ID: <50D4FBCF.2060706@gmx.de>
Date: Sat, 22 Dec 2012 01:16:15 +0100
From: Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:16.0) Gecko/20121025 Thunderbird/16.0.2
MIME-Version: 1.0
To: djgpp-workers AT delorie DOT com
Subject: Implementation of %n$ conversion specifier for scanf family of functions.
X-Y-GMX-Trusted: 0
Reply-To: djgpp-workers AT delorie DOT com

The patch below will implement the C99 numeric conversion specifier aka %n$ for
the scanf family of functions.


Regards,
Juan M. Guerrero



# cvs ci -m"Info about %n$ conversion specifier added." djgpp/src/docs/kb/wc204.txi
# cvs ci -m"Support for %n$ conversion specifier added." djgpp/src/libc/ansi/stdio/doscan.c
# cvs ci -m"Info about %n$ conversion specifier added." djgpp/src/libc/ansi/stdio/scanf.txh
# cvs ci -m"Added new test file tscanf2.c." djgpp/tests/libc/ansi/stdio/makefile
# cvs add djgpp/tests/libc/ansi/stdio/tscanf3.c
# cvs ci -m"Test for %n$ conversion specifier." djgpp/tests/libc/ansi/stdio/tscanf3.c

2012-12-21  Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>

     * djgpp/src/docs/kb/wc204.txi:  Info about %n$ conversion specifier added.

     * djgpp/src/libc/ansi/stdio/doscan.c:  Support for %n$ conversion specifier added.

     * djgpp/src/libc/ansi/stdio/scanf.txh:  Info about %n$ conversion specifier added.

     * djgpp/tests/libc/ansi/stdio/makefile:  Added new test file tscanf3.c.

     * djgpp/tests/libc/ansi/stdio/tscanf3.c:  Test for %n$ conversion specifier.






diff -aprNU5 djgpp.orig/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi
--- djgpp.orig/src/docs/kb/wc204.txi    2012-12-21 20:58:08 +0000
+++ djgpp/src/docs/kb/wc204.txi    2012-12-21 21:13:22 +0000
@@ -1261,5 +1261,10 @@ family of functions.
  @findex scanf AT r{, and m modifier character}
  The @code{m} modifier character is now supported by @code{_doscan}
  and the @code{scanf} family of functions.  This is a @acronym{GNU}
  @code{glibc} extension and it is specified in the upcoming revision
  of the @acronym{POSIX.1} standard.
+
+@findex _doscan AT r{, and @acronym{C99} numeric conversion specifiers}
+@findex scanf AT r{, and @acronym{C99} numeric conversion specifiers}
+The @code{%n$} numeric conversion specifiers are now supported
+by @code{_doscan} and the @code{scanf} family of functions.
diff -aprNU5 djgpp.orig/src/libc/ansi/stdio/doscan.c djgpp/src/libc/ansi/stdio/doscan.c
--- djgpp.orig/src/libc/ansi/stdio/doscan.c    2012-12-21 21:32:48 +0000
+++ djgpp/src/libc/ansi/stdio/doscan.c    2012-12-22 00:26:24 +0000
@@ -61,15 +61,17 @@ _doscan(FILE *iop, const char *fmt, va_l

  int
  _doscan_low(FILE *iop, int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), const char *fmt, va_list argp)
  {
    register int ch;
-  int nmatch, len, ch1;
+  int nmatch, n, len, ch1;
    int *ptr, fileended, size;
    int suppressed;
    bool allocate_char_buffer;
    int previous_errno = errno;
+  const va_list arg_list = argp;
+  bool retrieve_argp;

    decimal_point = localeconv()->decimal_point[0];
    nchars = 0;
    nmatch = 0;
    fileended = 0;
@@ -84,25 +86,37 @@ _doscan_low(FILE *iop, int (*scan_getc)(
        return nmatch;
      case '%':
        if ((ch = *fmt++) == '%')
          goto def;

+      retrieve_argp = true;
        allocate_char_buffer = false;
        ptr = NULL;
-      if (ch != '*')
+repeat:
+      if (ch != '*' && retrieve_argp)
          ptr = va_arg(argp, int *);
        else
          ch = *fmt++;
-      len = 0;
+      n = len = 0;
        size = REGULAR;
        while (isdigit(ch & 0xff))
        {
-        len = len * 10 + ch - '0';
+        n = n * 10 + ch - '0';
          ch = *fmt++;
        }
-      if (len == 0)
-        len = DEFAULT_WIDTH;
+      if (ch == '$')
+      {
+        /* C99 */
+        /* for %n$ numeric conversion specifier */
+        int i;
+        for (argp = arg_list, i = 0; i < n; i++)
+          ptr = va_arg(argp, int *);
+        retrieve_argp = false;
+        goto repeat;
+      }
+      else
+        len = (n == 0) ? DEFAULT_WIDTH : n;

        if (ch == 'l')
        {
          size = LONG;
          ch = *fmt++;
diff -aprNU5 djgpp.orig/src/libc/ansi/stdio/scanf.txh djgpp/src/libc/ansi/stdio/scanf.txh
--- djgpp.orig/src/libc/ansi/stdio/scanf.txh    2012-12-21 20:58:08 +0000
+++ djgpp/src/libc/ansi/stdio/scanf.txh    2012-12-21 21:13:22 +0000
@@ -16,12 +16,27 @@ the variables pointed to by the argument
  The format string contains regular characters which much match the input
  exactly as well as a conversion specifiers, which begin with a percent
  symbol.  Any whitespace in the format string matches zero or more of any
  whitespace characters in the input.  Thus, a single space may match a
  newline and two tabs in the input.  All conversions except @samp{c} and
-@samp{[} also skip leading whitespace automatically.  Each conversion
-specifier contains the following fields:
+@samp{[} also skip leading whitespace automatically.
+Conversions can be applied to the nth argument after the format in the
+argument list, rather than to the next unused argument.  In this case,
+the conversion specifier character @code{%} is replaced by the sequence
+@code{%n$}, where @code{n} is a decimal integer in the range [@code{1}, @code{number of the last argument}].
+This feature provides for the definition of format strings that select
+arguments in an order appropriate to specific languages.  In format strings
+containing the @code{%n$} form of conversion specifications, it is unspecified
+whether numbered arguments in the argument list can be referenced from
+the format string more than once.  The format can contain either form of
+a conversion specification - that is, @code{%} or @code{%n$} - but the two
+forms cannot be mixed within a single format string.  The only exception
+to this is that @code{%%} or @code{%*} can be mixed with the @code{%n$}
+form.  When numbered argument specifications are used, specifying the
+Nth argument requires that all the leading arguments, from the first
+to the (N-1)th, are pointers.
+Each conversion specifier contains the following fields:

  @itemize @bullet

  @item An asterisk (@samp{*}) which indicates that the input should be
  converted according to the conversion spec, but not stored anywhere.
diff -aprNU5 djgpp.orig/tests/libc/ansi/stdio/makefile djgpp/tests/libc/ansi/stdio/makefile
--- djgpp.orig/tests/libc/ansi/stdio/makefile    2012-12-21 20:58:08 +0000
+++ djgpp/tests/libc/ansi/stdio/makefile    2012-12-21 21:13:22 +0000
@@ -23,9 +23,10 @@ SRC += sscanf2.c
  SRC += sscanf3.c
  SRC += tmpnam.c
  SRC += tremove.c
  SRC += tscanf.c
  SRC += tscanf2.c
+SRC += tscanf3.c
  SRC += tsnprtf.c
  SRC += tsnprtf2.c

  include $(TOP)/../makefile.inc
diff -aprNU5 djgpp.orig/tests/libc/ansi/stdio/tscanf3.c djgpp/tests/libc/ansi/stdio/tscanf3.c
--- djgpp.orig/tests/libc/ansi/stdio/tscanf3.c    1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/ansi/stdio/tscanf3.c    2012-12-22 00:58:18 +0000
@@ -0,0 +1,43 @@
+/* Test the n$ numeric conversion specifier.  */
+
+#include <stdio.h>
+
+int main(void)
+{
+  const char *buffer[3] = {
+    "Fecha y hora es: 21 de deciembre de 2012, 01:02:03",
+    "Datum und Uhrzeit ist: 21. Dezember 2012, 01:02:03",
+    "Date and hour is: december 21 2012, 01:02:03"
+  };
+  const char *format[3] = {
+    "%*[A-Za-z :] %3$d %*[a-z] %2$9c %*[a-z] %1$d %*[,] %4$d%*[:] %5$d%*[:] %6$d%*",
+    "%*[A-Za-z :] %3$d %*[.] %2$8c %1$d %*[,] %4$d%*[:] %5$d%*[:] %6$d%*",
+    "%*[A-Za-z ]%*[:] %2$8c %3$d %1$d %*[,] %4$d%*[:] %5$d%*[:] %6$d%*"
+  };
+  const char *language[3] = {
+    "spanish",
+    "german",
+    "english"
+  };
+  char month[10];
+  int year, day, hour, min, sec, i;
+
+
+  for (i = 0; i < (sizeof buffer / sizeof buffer[0]); i++)
+  {
+    sscanf(buffer[i], format[i], &year, month, &day, &hour, &min, &sec);
+    if (i == 0)
+      month[9] = '\0';
+    else
+      month[8] = '\0';
+    printf("Result of scanf using %s format\n\"%s\":\n"
+           "  year:  %d\n"
+           "  month: %s\n"
+           "  day:   %d\n"
+           "  hour:  %d\n"
+           "  min:   %d\n"
+           "  sec:   %d\n", language[i], format[i], year, month, day, hour, min, sec);
+  }
+
+  return 0;
+}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019