This is the mail archive of the newlib@sources.redhat.com mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: %S %C vfprintf contribution


Artem B. Bityuckiy wrote:

Hello.

Nicholas Wourms wrote:
> Artem B. Bityuckiy wrote:
>
>> Hello.
>>
>> Here is the patch that makes vfprintf (and hence, all other
>> vfprintf-based Xprintf functions) understand ISO C 90 %S (same as %ls)
>> and %C (same as %lc) format placeholders. Please, review it and give
>> us know if something is wrong.
>>
>> This is tested a little bit- it works and it seems should work with
>> any locale if wcrtomb and wcsrtomb functions work.
>>
>
> I believe the preferred patch type is unidiff or `diff -up`.
OK, here is the patch to vfprintf.c produced by diff -up.
>
> Cheers,
> Nicholas
>
Initially, we've added these changes to Newlib-1.11.0. They was tested with Newlib-1.11.0 too. But then I've copy changes to Newlib from CVS. vfprintf.c from CVS differs from Newlib-1.11.0's vfprintf.c. I didn't test (even compile) Newlib from CVS with these patch, but it must work.


Thanks.


-- Best regards, Artem B. Bityuckiy SoftMine Corporation, Software Engineer Tel.: +7(812)329-67-44, +7(812)329-67-45 Mobile: +79112449030 E-mail: abitytsky@softminecorp.com Web: www.softminecorp.com

--- vfprintf_cvs.c	2003-10-30 13:31:41.000000000 +0300
+++ vfprintf_smc_cvs.c	2003-10-31 10:39:54.000000000 +0300
@@ -162,6 +162,7 @@ static char *rcsid = "$Id: vfprintf.c,v 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 #include <reent.h>
 
 #ifdef _HAVE_STDC
@@ -237,7 +238,12 @@ __sbprintf(fp, fmt, ap)
 #include <math.h>
 #include "floatio.h"
 
-#define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
+#if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX)
+#  define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
+#else 
+#  define BUF MB_LEN_MAX
+#endif
+
 #define	DEFPREC		6
 
 static char *cvt _PARAMS((struct _reent *, double, int, int, char *, int *, int, int *));
@@ -245,7 +251,11 @@ static int exponent _PARAMS((char *, int
 
 #else /* no FLOATING_POINT */
 
-#define	BUF		40
+#if (MB_LEN_MAX < 40)
+#  define BUF 40
+#else
+#  define BUF MB_LEN_MAX
+#endif
 
 #endif /* FLOATING_POINT */
 
@@ -269,6 +279,7 @@ static int exponent _PARAMS((char *, int
 #define	SHORTINT	0x040		/* short integer */
 #define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
 #define FPT		0x100		/* Floating point number */
+#define WIDECHARSTR     0x200           /* Widechar string */
 
 int 
 _DEFUN (VFPRINTF, (fp, fmt0, ap),
@@ -520,7 +531,23 @@ reswitch:	switch (ch) {
 			flags |= QUADINT;
 			goto rflag;
 		case 'c':
-			*(cp = buf) = va_arg(ap, int);
+                case 'C':
+                        cp = buf;
+                        if (*fmt == 'C' || (flags & LONGINT))
+                        {
+                            mbstate_t ps;
+
+                            memset((void *)&ps, '\0', sizeof(mbstate_t));
+                            if ((size = (int)wcrtomb(cp, 
+                                                     (wchar_t)va_arg(ap, int), 
+                                                     &ps)) == -1)
+                                goto error; 
+                        }
+                        else
+                        {
+                            *cp = (char)va_arg(ap, int);
+                            size = 1;
+                        }
 			size = 1;
 			sign = '\0';
 			break;
@@ -644,8 +671,66 @@ reswitch:	switch (ch) {
 			ch = 'x';
 			goto nosign;
 		case 's':
-			if ((cp = va_arg(ap, char *)) == NULL)
-				cp = "(null)";
+                case 'S':
+		        sign = '\0';
+                        cp = va_arg(ap, char *);
+
+                        if (cp && (ch == 'S' || (flags & LONGINT))) {
+                            mbstate_t ps;
+                            _CONST wchar_t *wcp;
+
+                            wcp = (_CONST wchar_t *)cp;
+                            size = m = 0;
+                            memset((void *)&ps, '\0', sizeof(mbstate_t));
+
+                            /* 
+                             * Count number of bytes needed to store multibyte
+                             * string that will be produced from widechar
+                             * string.
+                             */
+                            if (prec >= 0) {
+                                while (1) {
+                                    if (wcp[m] == L'\0')
+                                        break;
+                                    if ((n = (int)wcrtomb(buf, 
+                                                          wcp[m], &ps)) == -1)
+                                        goto error;
+                                    if (n + size > prec)
+                                        break;
+                                    m += 1;
+                                    size += n;
+                                    if (size == prec)
+                                        break;
+                                }
+                            }
+                            else {
+                                if ((size = (int)wcsrtombs(NULL, &wcp, 
+                                                           0, &ps)) == -1)
+                                    goto error; 
+                                wcp = (_CONST wchar_t *)cp;
+                            }
+
+                            if (size == 0)
+                                break;
+
+                            if ((cp = (char *)malloc(size + 1)) == NULL)
+                                goto error;
+                            
+                            flags |= WIDECHARSTR;
+
+                            /*
+                             * Convert widechar string to multibyte string.
+                             */
+                            memset((void *)&ps, '\0', sizeof(mbstate_t));
+                            if (wcsrtombs(cp, &wcp, size, &ps) != size)
+                                goto error;
+                            cp[size] = '\0';
+                            break;
+                        }
+
+			if (cp == NULL)
+			    cp = "(null)";
+
 			if (prec >= 0) {
 				/*
 				 * can't use strlen; can only look for the
@@ -662,7 +747,6 @@ reswitch:	switch (ch) {
 					size = prec;
 			} else
 				size = strlen(cp);
-			sign = '\0';
 			break;
 		case 'U':
 			flags |= LONGINT;
@@ -846,6 +930,9 @@ number:			if ((dprec = prec) >= 0)
 		ret += width > realsz ? width : realsz;
 
 		FLUSH();	/* copy out the I/O vectors */
+
+                if (flags & WIDECHARSTR)
+                    free(cp);
 	}
 done:
 	FLUSH();

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]