Mail Archives: djgpp-workers/2012/12/22/13:54:05
Am 22.12.2012 09:27, schrieb Eli Zaretskii:
> > +@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.
>
> The use of "n" in "%n$" may mislead the reader to think it's a literal
> "n" meant here. I suggest to use @var{n} instead, or even something
> like @var{param-no}.
[snip]
I have changed the patch as you suggested neither less I have retained "n"
as variable name. Keeping the variable name shall make the djgpp description
match the linux scanf man page description and the descriptio given in
<http://pubs.opengroup.org/onlinepubs/009695399/functions/scanf.html>
> > +/* Test the n$ numeric conversion specifier. */
[snip]
> It would be better to include the expected results in the program,
> instead of relying on a human eye to detect errors.
Fixed.
Regards,
Juan M. Guerrero
2012-12-22 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-22 11:57:16 +0000
+++ djgpp/src/docs/kb/wc204.txi 2012-12-22 17:54:40 +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{%@var{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-22 11:57:16 +0000
+++ djgpp/src/libc/ansi/stdio/doscan.c 2012-12-22 17:54:40 +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_arg_ptr;
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_arg_ptr = true;
allocate_char_buffer = false;
ptr = NULL;
- if (ch != '*')
+repeat:
+ if (ch != '*' && retrieve_arg_ptr)
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_arg_ptr = 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-22 11:57:16 +0000
+++ djgpp/src/libc/ansi/stdio/scanf.txh 2012-12-22 18:06:50 +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 @var{n}th 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{%@var{n}$}, where @var{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{%@var{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{%@var{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{%@var{n}$} form. When numbered argument specifications are used,
+specifying the @var{n}th argument requires that all the leading arguments,
+from the first to the (@var{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-22 11:57:16 +0000
+++ djgpp/tests/libc/ansi/stdio/makefile 2012-12-22 17:54:40 +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 17:54:40 +0000
@@ -0,0 +1,99 @@
+/* Test the n$ numeric conversion specifier. */
+
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+ const char *buffer[3] = {
+ "Fecha y hora es: 21 de diciembre 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"
+ };
+ typedef struct {
+ const int year;
+ const char *month;
+ const int day;
+ const int hour;
+ const int min;
+ const int sec;
+ } result;
+ result testcases[3] = {
+ { 2012, "diciembre", 21, 1, 2, 3}, /* spanish */
+ { 2012, "Dezember", 21, 1, 2, 3}, /* german */
+ { 2012, "december", 21, 1, 2, 3} /* english */
+ };
+ char month[10];
+ int year, day, hour, min, sec, i, status;
+
+
+ for (status = i = 0; i < (sizeof buffer / sizeof buffer[0]);)
+ {
+ sscanf(buffer[i], format[i], &year, month, &day, &hour, &min, &sec);
+ if (i == 0)
+ month[9] = '\0';
+ else
+ month[8] = '\0';
+
+ if (year == testcases[i].year)
+ {
+ status++;
+ if (!strcmp(month, testcases[i].month))
+ {
+ status++;
+ if (day == testcases[i].day)
+ {
+ status++;
+ if (hour == testcases[i].hour)
+ {
+ status++;
+ if (min == testcases[i].min)
+ {
+ status++;
+ if (sec == testcases[i].sec)
+ status++;
+ else
+ printf("At least one conversion failed.\nConversion should have been: %d but is %d\n", testcases[i].sec, sec);
+ }
+ else
+ printf("At least one conversion failed.\nConversion should have been: %d but is %d\n", testcases[i].min, min);
+ }
+ else
+ printf("At least one conversion failed.\nConversion should have been: %d but is %d\n", testcases[i].hour, hour);
+ }
+ else
+ printf("At least one conversion failed.\nConversion should have been: %d but is %d\n", testcases[i].day, day);
+ }
+ else
+ printf("At least one conversion failed.\nConversion should have been: %s but is %s\n", testcases[i].month, month);
+ }
+ else
+ printf("At least one conversion failed.\nConversion should have been: %d but is %d\n", testcases[i].year, year);
+
+ printf("Result of scanf using the %s format string\n\"%s\":\n"
+ " year: %d\n"
+ " month: %s\n"
+ " day: %d\n"
+ " hour: %d\n"
+ " min: %d\n"
+ " sec: %d\n\n", language[i], format[i], year, month, day, hour, min, sec);
+
+ if (status != 6 * ++i)
+ return status;
+ }
+
+ if (status)
+ printf("Test passed successfully.");
+
+ return 0;
+}
- Raw text -