diff -Naur bash-4.1/lib/glob/xmbsrtowcs.c bash-4.1-fasterWideCharConversion/lib/glob/xmbsrtowcs.c --- bash-4.1/lib/glob/xmbsrtowcs.c 2008-08-12 16:17:54.000000000 +0200 +++ bash-4.1-fasterWideCharConversion/lib/glob/xmbsrtowcs.c 2010-03-03 16:40:58.664811945 +0100 @@ -18,6 +18,14 @@ along with Bash. If not, see . */ +/* Tell glibc's and to provide + prototypes for strchrnul() and mbsnrtowcs(). + This must come before because may include + , and once has been included, it's too late. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + #include #include @@ -131,6 +139,91 @@ If conversion is failed, the return value is (size_t)-1 and the values of DESTP and INDICESP are NULL. */ +#ifndef _GNU_SOURCE +# error "Optimized conversion to wide-character strings requires _GNU_SOURCE" +#endif + +static size_t +xdupmbstowcs__no_indices (destp, src) + wchar_t **destp; /* Store the pointer to the wide character string */ + const char *src; /* Multibyte character string */ +{ + const char *p; /* Conversion start position of src */ + wchar_t *wsbuf; /* Buffer for wide characters. */ + size_t wsbuf_size; /* Size of WSBUF */ + size_t wcnum; /* Number of wide characters in WSBUF */ + mbstate_t state; /* Conversion State */ + + memset (&state, '\0', sizeof(mbstate_t)); + + wsbuf_size = 0; + wsbuf = NULL; + + p = src; + wcnum = 0; + do + { + size_t wcslength; /* Number of wide characters produced by the conversion. */ + const char *end_or_backslash; + size_t nms; /* Number of multibyte characters to convert at one time. */ + mbstate_t tmp_state; + const char *tmp_p; + + end_or_backslash = strchrnul(p, '\\'); + nms = (end_or_backslash - p); + if(*end_or_backslash == '\0') + nms++; + + /* Compute the number of produced wide-characters. */ + tmp_p = p; + tmp_state = state; + wcslength = mbsnrtowcs(NULL, &tmp_p, nms, 0, &tmp_state); + + /* Conversion failed. */ + if (wcslength == (size_t)-1) + { + free (wsbuf); + *destp = NULL; + return (size_t)-1; + } + + /* Resize the buffer if it is not large enough. */ + if (wsbuf_size < wcnum+wcslength+1) /* 1 for the L'\0' or the potential L'\\' */ + { + wchar_t *wstmp; + + wsbuf_size = wcnum+wcslength+1; /* 1 for the L'\0' or the potential L'\\' */ + + wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t)); + if (wstmp == NULL) + { + free (wsbuf); + *destp = NULL; + return (size_t)-1; + } + wsbuf = wstmp; + } + + /* Perform the conversion. This is assumed to return 'wcslength'. + * It may set 'p' to NULL. */ + mbsnrtowcs(wsbuf+wcnum, &p, nms, wsbuf_size-wcnum, &state); + + wcnum += wcslength; + + if (mbsinit (&state) && (p != NULL) && (*p == '\\')) + { + wsbuf[wcnum++] = L'\\'; + p++; + } + } + while (p != NULL); + + *destp = wsbuf; + + /* Return the length of the wide character string, not including `\0'. */ + return wcnum; +} + #define WSBUF_INC 32 size_t @@ -155,6 +248,10 @@ return (size_t)-1; } + /* Use faster version if 'indicesp' is NULL. */ + if (indicesp == NULL) + return xdupmbstowcs__no_indices(destp, src); + memset (&state, '\0', sizeof(mbstate_t)); wsbuf_size = WSBUF_INC;