Skip to content

Commit fed2405

Browse files
committed
Patch #479898: Use multibyte C library for printing strings if available.
1 parent e9ce0b0 commit fed2405

4 files changed

Lines changed: 81 additions & 23 deletions

File tree

Objects/stringobject.c

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ static PyStringObject *nullstring;
2626
static PyObject *interned;
2727

2828

29+
#if defined(HAVE_MBTOWC) && defined(HAVE_WCHAR_H)
30+
# define PRINT_MULTIBYTE_STRING
31+
# include <locale.h>
32+
# include <wchar.h>
33+
# if defined(HAVE_ISWPRINT)
34+
# define _isprint iswprint
35+
# else
36+
# define _isprint isprint
37+
# endif
38+
#endif
39+
40+
static const char *hexchars = "0123456789abcdef";
41+
2942
/*
3043
For both PyString_FromString() and PyString_FromStringAndSize(), the
3144
parameter `size' denotes number of characters to allocate, not counting any
@@ -749,8 +762,14 @@ PyString_AsStringAndSize(register PyObject *obj,
749762
static int
750763
string_print(PyStringObject *op, FILE *fp, int flags)
751764
{
765+
#ifndef PRINT_MULTIBYTE_STRING
752766
int i;
753767
char c;
768+
#else
769+
char *scur, *send;
770+
wchar_t c;
771+
int cr;
772+
#endif
754773
int quote;
755774

756775
/* XXX Ought to check for interrupts when writing long strings */
@@ -776,20 +795,36 @@ string_print(PyStringObject *op, FILE *fp, int flags)
776795
quote = '"';
777796

778797
fputc(quote, fp);
798+
#ifndef PRINT_MULTIBYTE_STRING
779799
for (i = 0; i < op->ob_size; i++) {
780800
c = op->ob_sval[i];
801+
#else
802+
for (scur = op->ob_sval, send = op->ob_sval + op->ob_size;
803+
scur < send; scur += cr) {
804+
if ((cr = mbtowc(&c, scur, send - scur)) <= 0)
805+
goto non_printable;
806+
#endif
781807
if (c == quote || c == '\\')
782-
fprintf(fp, "\\%c", c);
808+
fputc('\\', fp), fputc(c, fp);
783809
else if (c == '\t')
784-
fprintf(fp, "\\t");
810+
fputs("\\t", fp);
785811
else if (c == '\n')
786-
fprintf(fp, "\\n");
812+
fputs("\\n", fp);
787813
else if (c == '\r')
788-
fprintf(fp, "\\r");
789-
else if (c < ' ' || c >= 0x7f)
790-
fprintf(fp, "\\x%02x", c & 0xff);
791-
else
814+
fputs("\\r", fp);
815+
#ifndef PRINT_MULTIBYTE_STRING
816+
else if (' ' <= c && c < 0x7f)
792817
fputc(c, fp);
818+
else
819+
fprintf(fp, "\\x%02x", c & 0xff);
820+
#else
821+
else if (_isprint(c))
822+
fwrite(scur, cr, 1, fp);
823+
else {
824+
non_printable: cr = 1; /* unit to move cursor */
825+
fprintf(fp, "\\x%02x", *scur & 0xff);
826+
}
827+
#endif
793828
}
794829
fputc(quote, fp);
795830
return 0;
@@ -810,8 +845,14 @@ PyString_Repr(PyObject *obj, int smartquotes)
810845
return NULL;
811846
}
812847
else {
848+
#ifndef PRINT_MULTIBYTE_STRING
813849
register int i;
814850
register char c;
851+
#else
852+
register char *scur, *send;
853+
wchar_t c;
854+
int cr;
855+
#endif
815856
register char *p;
816857
int quote;
817858

@@ -824,11 +865,18 @@ PyString_Repr(PyObject *obj, int smartquotes)
824865

825866
p = PyString_AS_STRING(v);
826867
*p++ = quote;
868+
#ifndef PRINT_MULTIBYTE_STRING
827869
for (i = 0; i < op->ob_size; i++) {
828870
/* There's at least enough room for a hex escape
829871
and a closing quote. */
830872
assert(newsize - (p - PyString_AS_STRING(v)) >= 5);
831873
c = op->ob_sval[i];
874+
#else
875+
for (scur = op->ob_sval, send = op->ob_sval + op->ob_size;
876+
scur < send; scur += cr) {
877+
if ((cr = mbtowc(&c, scur, send - scur)) <= 0)
878+
goto non_printable;
879+
#endif
832880
if (c == quote || c == '\\')
833881
*p++ = '\\', *p++ = c;
834882
else if (c == '\t')
@@ -837,15 +885,20 @@ PyString_Repr(PyObject *obj, int smartquotes)
837885
*p++ = '\\', *p++ = 'n';
838886
else if (c == '\r')
839887
*p++ = '\\', *p++ = 'r';
840-
else if (c < ' ' || c >= 0x7f) {
841-
/* For performance, we don't want to call
842-
PyOS_snprintf here (extra layers of
843-
function call). */
844-
sprintf(p, "\\x%02x", c & 0xff);
845-
p += 4;
846-
}
847-
else
888+
#ifndef PRINT_MULTIBYTE_STRING
889+
else if (' ' <= c && c < 0x7f)
848890
*p++ = c;
891+
else {
892+
#else
893+
else if (_isprint(c))
894+
memcpy(p, scur, cr), p += cr;
895+
else {
896+
non_printable: cr = 1; c = *scur;
897+
#endif
898+
*p++ = '\\'; *p++ = 'x';
899+
*p++ = hexchars[(c >> 4) & 0x0f];
900+
*p++ = hexchars[c & 0x0f];
901+
}
849902
}
850903
assert(newsize - (p - PyString_AS_STRING(v)) >= 1);
851904
*p++ = quote;

configure

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#! /bin/sh
2-
# From configure.in Revision: 1.352 .
2+
# From configure.in Revision: 1.353 .
33
# Guess values for system-dependent variables and create Makefiles.
44
# Generated by GNU Autoconf 2.53.
55
#
@@ -11657,14 +11657,16 @@ echo "${ECHO_T}MACHDEP_OBJS" >&6
1165711657
1165811658
1165911659
11660+
11661+
1166011662
1166111663
1166211664
1166311665
for ac_func in alarm chown chroot clock confstr ctermid ctermid_r execv \
1166411666
fchdir flock fork fsync fdatasync fpathconf ftime ftruncate \
1166511667
gai_strerror getgroups getlogin getpeername getpgid getpid getpwent getwd \
11666-
hstrerror inet_pton kill killpg lchown link lstat mkfifo mknod mktime \
11667-
mremap nice pathconf pause plock poll pthread_init \
11668+
hstrerror inet_pton iswprint kill killpg lchown link lstat mbtowc mkfifo \
11669+
mknod mktime mremap nice pathconf pause plock poll pthread_init \
1166811670
putenv readlink \
1166911671
select setegid seteuid setgid setgroups \
1167011672
setlocale setregid setreuid setsid setpgid setuid setvbuf snprintf \

configure.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,8 +1679,8 @@ AC_MSG_RESULT(MACHDEP_OBJS)
16791679
AC_CHECK_FUNCS(alarm chown chroot clock confstr ctermid ctermid_r execv \
16801680
fchdir flock fork fsync fdatasync fpathconf ftime ftruncate \
16811681
gai_strerror getgroups getlogin getpeername getpgid getpid getpwent getwd \
1682-
hstrerror inet_pton kill killpg lchown link lstat mkfifo mknod mktime \
1683-
mremap nice pathconf pause plock poll pthread_init \
1682+
hstrerror inet_pton iswprint kill killpg lchown link lstat mbtowc mkfifo \
1683+
mknod mktime mremap nice pathconf pause plock poll pthread_init \
16841684
putenv readlink \
16851685
select setegid seteuid setgid setgroups \
16861686
setlocale setregid setreuid setsid setpgid setuid setvbuf snprintf \

pyconfig.h.in

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@
196196
/* Define to 1 if you have the <inttypes.h> header file. */
197197
#undef HAVE_INTTYPES_H
198198

199+
/* Define to 1 if you have the `iswprint' function. */
200+
#undef HAVE_ISWPRINT
201+
199202
/* Define to 1 if you have the `kill' function. */
200203
#undef HAVE_KILL
201204

@@ -226,9 +229,6 @@
226229
/* Define to 1 if you have the <libintl.h> header file. */
227230
#undef HAVE_LIBINTL_H
228231

229-
/* Define to 1 if you have the `rt' library (-lrt). */
230-
#undef HAVE_LIBRT
231-
232232
/* Define to 1 if you have the <libutil.h> header file. */
233233
#undef HAVE_LIBUTIL_H
234234

@@ -250,6 +250,9 @@
250250
/* Define this if you have the makedev macro. */
251251
#undef HAVE_MAKEDEV
252252

253+
/* Define to 1 if you have the `mbtowc' function. */
254+
#undef HAVE_MBTOWC
255+
253256
/* Define to 1 if you have the `memmove' function. */
254257
#undef HAVE_MEMMOVE
255258

0 commit comments

Comments
 (0)