delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2002/12/14/08:28:04

Date: Sat, 14 Dec 2002 13:27:55 +0000
From: "Richard Dawe" <rich AT phekda DOT freeserve DOT co DOT uk>
Sender: rich AT phekda DOT freeserve DOT co DOT uk
To: djgpp-workers AT delorie DOT com
X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6
Subject: scanf and 'hh' width conversion, revision 2 (C99) [PATCH]
Message-Id: <E18NCKi-0000bW-00@phekda.freeserve.co.uk>
Reply-To: djgpp-workers AT delorie DOT com

Hello.

I was about to commit the patch to fix scanf to support
the 'hh' width conversion, when I realised that I had written
no documentation for it. Below is a patch that adds documentation
for 'hh'.

While I was looking at the scanf page, I noticed that some of
the type conversions did not list the argument type as signed or unsigned.
Since the C99 standard says explicitly that e.g.: %d will be put in
a signed variable, I have updated the docs to agree with C99.
In some cases the documentation said the opposite of C99 -
signed instead of unsigned for %o. I fixed the docs to agree with C99.

OK to commit?

Thanks, bye, Rich =]

Index: src/libc/ansi/stdio/doscan.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdio/doscan.c,v
retrieving revision 1.11
diff -p -c -3 -r1.11 doscan.c
*** src/libc/ansi/stdio/doscan.c	14 Jun 2002 14:19:42 -0000	1.11
--- src/libc/ansi/stdio/doscan.c	14 Dec 2002 13:24:04 -0000
***************
*** 13,22 ****
  #define	SPC	01
  #define	STP	02
  
! #define	SHORT	0
! #define	REGULAR	1
! #define	LONG	2
! #define LONGDOUBLE 4
  #define	INT	0
  #define	FLOAT	1
  
--- 13,24 ----
  #define	SPC	01
  #define	STP	02
  
! #define CHAR	0
! #define	SHORT	1
! #define	REGULAR	2
! #define	LONG	4
! #define LONGDOUBLE 8
! 
  #define	INT	0
  #define	FLOAT	1
  
*************** _doscan_low(FILE *iop, int (*scan_getc)(
*** 91,96 ****
--- 93,103 ----
      else if (ch=='h') {
        size = SHORT;
        ch = *fmt++;
+       if (ch=='h')
+       {
+ 	size = CHAR;
+ 	ch = *fmt++;
+       }
      } else if (ch=='L') {
        size = LONGDOUBLE;
        ch = *fmt++;
*************** _doscan_low(FILE *iop, int (*scan_getc)(
*** 107,116 ****
  	 This extension is supported by some compilers (e.g. Borland C).
  	 Old pre-ANSI compilers, such as Turbo C 2.0, also interpreted
  	 %E, %F and %G to store in a double (rather than a float), but
! 	 this contradicts the ANSI Standard, so we don't support it.  */
!       if (ch == 'd' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'x')
        {
! 	if (size==LONG && ch != 'x') /* ANSI: %lX is long, not long long */
  	  size = LONGDOUBLE;
  	else if (size != LONGDOUBLE)
  	  size = LONG;
--- 114,125 ----
  	 This extension is supported by some compilers (e.g. Borland C).
  	 Old pre-ANSI compilers, such as Turbo C 2.0, also interpreted
  	 %E, %F and %G to store in a double (rather than a float), but
! 	 this contradicts the ANSI Standard, so we don't support it.
!          %X should be treated as per the ANSI Standard - no length
! 	 is implied by the upper-case x. */
!       if (ch == 'd' || ch == 'i' || ch == 'o' || ch == 'u')
        {
! 	if (size == LONG)
  	  size = LONGDOUBLE;
  	else if (size != LONGDOUBLE)
  	  size = LONG;
*************** _doscan_low(FILE *iop, int (*scan_getc)(
*** 125,130 ****
--- 134,141 ----
          break;
        if (size==LONG)
  	*(long*)ptr = nchars;
+       else if (size==CHAR)
+ 	*(char*)ptr = nchars;
        else if (size==SHORT)
          *(short*)ptr = nchars;
        else if (size==LONGDOUBLE)
*************** _innum(int *ptr, int type, int len, int 
*** 292,297 ****
--- 303,312 ----
  
    case (FLOAT<<4) | LONGDOUBLE:
      *(long double *)ptr = _atold(numbuf);
+     break;
+ 
+   case (INT<<4) | CHAR:
+     *(char *)ptr = (char)lcval;
      break;
  
    case (INT<<4) | SHORT:
Index: src/libc/ansi/stdio/scanf.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdio/scanf.txh,v
retrieving revision 1.7
diff -p -c -3 -r1.7 scanf.txh
*** src/libc/ansi/stdio/scanf.txh	30 Jun 2001 14:05:40 -0000	1.7
--- src/libc/ansi/stdio/scanf.txh	14 Dec 2002 13:24:05 -0000
*************** This allows to describe an input field t
*** 29,37 ****
  @item A width specifier, which specifies the maximum number of input
  characters to use in the conversion. 
  
! @item An optional conversion qualifier, which may be @samp{h} to specify
! @code{short}, @samp{l} to specify doubles or long ints, or @samp{L} or
! @samp{ll} (two lower-case ell letters) to specify long doubles and the
  long long type.  If the @samp{h} qualifier appears before a specifier
  that implies conversion to a @code{long} or @code{float} or
  @code{double}, like in @samp{%hD} or @samp{%hf}, it is generally
--- 29,38 ----
  @item A width specifier, which specifies the maximum number of input
  characters to use in the conversion. 
  
! @item An optional conversion qualifier, which may be @samp{hh}
! to specify @code{char}, @samp{h} to specify @code{short}, @samp{l}
! to specify doubles or long ints, or @samp{L} or @samp{ll}
! (two lower-case ell letters) to specify long doubles and the
  long long type.  If the @samp{h} qualifier appears before a specifier
  that implies conversion to a @code{long} or @code{float} or
  @code{double}, like in @samp{%hD} or @samp{%hf}, it is generally
*************** of one is implied.
*** 57,62 ****
--- 58,67 ----
  Convert the input to a signed @code{int} using 10 as the base of the
  number representation.
  
+ @item hhd
+ 
+ Convert the input to a signed @code{char} using 10 as the base.
+ 
  @item hd
  
  Convert the input to a signed @code{short} using 10 as the base.
*************** Convert the input to a @code{long double
*** 108,167 ****
  @item i
  
  Convert the input, determining base automatically by the presence of
! @code{0x} or @code{0} prefixes, and store in an @code{int}.
  @xref{strtol}.
  
  @item hi
  
! Like @samp{i}, but stores the result in a @code{short}.
  
  @item li
  @itemx I
  
! Like @samp{i}, but stores the result in a @code{long}.
  
  @item Li
  @itemx lli
  @itemx lI
  
! Like @samp{i}, but stores the result in a @code{long long}.
  
  @item n
  
  Store the number of characters scanned so far into the @code{int}
  pointed to by the argument.
  
  @item hn
  
! Like @samp{n}, but the argument should point to a @code{short}.
  
  @item ln
  
! Like @samp{n}, but the argument should point to a @code{long}.
  
  @item Ln
  @itemx lln
  
! Like @samp{n}, but the argument should point to a @code{long long}.
  
  @item o
  
! Convert the input to a signed @code{int}, using base 8.
  
  @item ho
  
! Convert the input to a signed @code{short}, using base 8.
  
  @item lo
  @itemx O
  
! Convert the input to a signed @code{long}, using base 8.
  
  @item Lo
  @itemx llo
  @itemx lO
  
! Convert the input to a signed @code{long long}, using base 8.
  
  @item p
  
--- 113,184 ----
  @item i
  
  Convert the input, determining base automatically by the presence of
! @code{0x} or @code{0} prefixes, and store in a signed @code{int}.
  @xref{strtol}.
  
+ @item hhi
+ 
+ Like @samp{i}, but stores the result in a signed @code{char}.
+ 
  @item hi
  
! Like @samp{i}, but stores the result in a signed @code{short}.
  
  @item li
  @itemx I
  
! Like @samp{i}, but stores the result in a signed @code{long}.
  
  @item Li
  @itemx lli
  @itemx lI
  
! Like @samp{i}, but stores the result in a signed @code{long long}.
  
  @item n
  
  Store the number of characters scanned so far into the @code{int}
  pointed to by the argument.
  
+ @item hhn
+ 
+ Like @samp{n}, but the argument should point to a signed @code{char}.
+ 
  @item hn
  
! Like @samp{n}, but the argument should point to a signed @code{short}.
  
  @item ln
  
! Like @samp{n}, but the argument should point to a signed @code{long}.
  
  @item Ln
  @itemx lln
  
! Like @samp{n}, but the argument should point to a signed @code{long long}.
  
  @item o
  
! Convert the input to an unsigned @code{int}, using base 8.
! 
! @item hho
! 
! Convert the input to an unsigned @code{char}, using base 8.
  
  @item ho
  
! Convert the input to an unsigned @code{short}, using base 8.
  
  @item lo
  @itemx O
  
! Convert the input to an unsigned @code{long}, using base 8.
  
  @item Lo
  @itemx llo
  @itemx lO
  
! Convert the input to an unsigned @code{long long}, using base 8.
  
  @item p
  
*************** stored is then terminated with a null ch
*** 177,182 ****
--- 194,203 ----
  
  Convert the input to an unsigned @code{int} using 10 as the base.
  
+ @item hhu
+ 
+ Convert the input to an unsigned @code{char} using 10 as the base.
+ 
  @item hu
  
  Convert the input to an unsigned @code{short} using 10 as the base.
*************** Convert the input to an unsigned @code{l
*** 196,201 ****
--- 217,227 ----
  @itemx X
  
  Convert the input to an unsigned @code{int}, using base 16.
+ 
+ @item hhx
+ @itemx hhX
+ 
+ Convert the input to an unsigned @code{char}, using base 16.
  
  @item hx
  @itemx hX
Index: src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.126
diff -p -c -3 -r1.126 wc204.txi
*** src/docs/kb/wc204.txi	14 Dec 2002 12:55:43 -0000	1.126
--- src/docs/kb/wc204.txi	14 Dec 2002 13:24:15 -0000
*************** The function @code{atoll} was added.
*** 792,801 ****
  @findex strtold
  The function @code{strtold} was added.
  
  @findex _doprnt AT r{, and }hh AT r{ conversion qualifier}
  @findex printf AT r{, and }hh AT r{ conversion qualifier}
! The @code{hh} conversion qualifier is now supported by @code{_doprnt}
! and the @code{printf} family of functions.
  
  @findex delay AT r{, and Windows 2000 and XP}
  The @code{delay} function now works on Windows 2000 and XP.  However, the
--- 792,810 ----
  @findex strtold
  The function @code{strtold} was added.
  
+ @findex scanf AT r{, and the X type conversion and C99}
+ The behaviour of the @code{%X} type conversion for the @code{scanf}-family
+ of functions has changed.  Previously @code{%X} denoted
+ a @code{long} version of the @code{%x} type conversion.  Now @code{%X}
+ is equivalent to the @code{%x} type conversion, as required by C99.
+ 
  @findex _doprnt AT r{, and }hh AT r{ conversion qualifier}
  @findex printf AT r{, and }hh AT r{ conversion qualifier}
! @findex _doscan AT r{, and }hh AT r{ conversion qualifier}
! @findex scanf AT r{, and }hh AT r{ conversion qualifier}
! The @code{hh} conversion qualifier is now supported by @code{_doprnt},
! @code{_doscan}, the @code{printf} family of functions
! and the @code{scanf} family of functions.
  
  @findex delay AT r{, and Windows 2000 and XP}
  The @code{delay} function now works on Windows 2000 and XP.  However, the
Index: tests/libc/ansi/stdio/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/ansi/stdio/makefile,v
retrieving revision 1.7
diff -p -c -3 -r1.7 makefile
*** tests/libc/ansi/stdio/makefile	6 Dec 2002 09:37:53 -0000	1.7
--- tests/libc/ansi/stdio/makefile	14 Dec 2002 13:24:15 -0000
*************** SRC += mktemp.c
*** 16,21 ****
--- 16,22 ----
  SRC += printf.c
  SRC += printf2.c
  SRC += sscanf.c
+ SRC += sscanf2.c
  SRC += tmpnam.c
  SRC += tscanf.c
  SRC += tsnprtf.c
Index: tests/libc/ansi/stdio/sscanf2.c
===================================================================
RCS file: tests/libc/ansi/stdio/sscanf2.c
diff -N tests/libc/ansi/stdio/sscanf2.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- tests/libc/ansi/stdio/sscanf2.c	14 Dec 2002 13:24:18 -0000
***************
*** 0 ****
--- 1,117 ----
+ #include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ 
+ typedef struct {
+   const char *str;
+   const char *fmt;
+   const signed char res;
+ } signed_testcase_t;
+ 
+ typedef struct {
+   const char *str;
+   const char *fmt;
+   const unsigned char res;
+ } unsigned_testcase_t;
+ 
+ signed_testcase_t s_testcases[] = {
+   /* Normal */
+   { "127",  "%hhd", 127 },
+   { "127",  "%hhi", 127 },
+   { "0x7f", "%hhx", 127 },
+   { "0x7F", "%hhX", 127 },
+   { "0x7f", "%hhx", 127 },
+   { "0x7F", "%hhX", 127 },
+   { "0177", "%hho", 127 },
+ 
+   /* Truncation */
+   { "255",     "%hhd", -1 },
+   { "256",     "%hhd",  0 },
+   { "0xff",    "%hhx", -1 },
+   { "0x100",   "%hhx",  0 },
+   { "0377",    "%hho", -1 },
+   { "0400",    "%hho",  0 },
+   { "65535",   "%hhd", -1 },
+   { "65536",   "%hhd",  0 },
+   { "0xffff",  "%hhx", -1 },
+   { "0x10000", "%hhx",  0 },
+   { "177777",  "%hho", -1 },
+   { "200000",  "%hho",  0 },
+ 
+   /* Terminator */
+   { NULL, NULL, 0 }
+ };
+ 
+ unsigned_testcase_t u_testcases[] = {
+   /* Normal */
+   { "255", "%hhu", 255 },
+ 
+   /* Truncation */
+   { "256",   "%hhu",   0 },
+   { "65535", "%hhu", 255 },
+   { "65536", "%hhu",   0 },
+ 
+   /* Terminator */
+   { NULL, NULL, 0 }
+ };
+ 
+ static void
+ fail (const int testnum,
+       const char *input,
+       const char *fmt,
+       const char *reason,
+       const long code)
+ {
+   fprintf(stderr,
+ 	  "FAIL: Test %d: %s %s: %s: %ld\n",
+ 	  testnum, input, fmt, reason, code);
+   exit(EXIT_FAILURE);
+ }
+ 
+ int
+ main (void)
+ {
+   signed char   s_res;
+   unsigned char u_res;
+   int           testnum = 0;
+   int           ret;
+   int           i;
+ 
+   /* Signed testcases */
+   for (i = 0; s_testcases[i].str != NULL; i++) {
+     testnum++;
+     s_res = 0;
+ 
+     ret = sscanf(s_testcases[i].str, s_testcases[i].fmt, &s_res);
+     if ((ret == EOF) || (ret < 1)) {
+       fail(testnum, s_testcases[i].str, s_testcases[i].fmt,
+ 	   "sscanf failed", ret);
+     }
+ 
+     if (s_testcases[i].res != s_res) {
+       fail(testnum, s_testcases[i].str, s_testcases[i].fmt,
+ 	   "unexpected result", s_res);
+     }
+   }
+ 
+   /* Unsigned testcases */
+   for (i = 0; u_testcases[i].str != NULL; i++) {
+     testnum++;
+     u_res = 0;
+ 
+     ret = sscanf(u_testcases[i].str, u_testcases[i].fmt, &u_res);
+     if ((ret == EOF) || (ret < 1)) {
+       fail(testnum, u_testcases[i].str, u_testcases[i].fmt,
+ 	   "sscanf failed", ret);
+     }
+ 
+     if (u_testcases[i].res != u_res) {
+       fail(testnum, u_testcases[i].str, u_testcases[i].fmt,
+ 	   "unexpected result", u_res);
+     }
+   }
+ 
+   puts("PASS");
+   return(EXIT_SUCCESS);
+ }

- Raw text -


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