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 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. Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit 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 * 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 + +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; +}