diff options
Diffstat (limited to 'manual/examples/mbstouwcs.c')
-rw-r--r-- | manual/examples/mbstouwcs.c | 49 |
1 files changed, 37 insertions, 12 deletions
diff --git a/manual/examples/mbstouwcs.c b/manual/examples/mbstouwcs.c index 5d223da..c94e1fa 100644 --- a/manual/examples/mbstouwcs.c +++ b/manual/examples/mbstouwcs.c @@ -1,3 +1,4 @@ +#include <stdbool.h> #include <stdlib.h> #include <string.h> #include <wchar.h> @@ -7,22 +8,46 @@ wchar_t * mbstouwcs (const char *s) { - size_t len = strlen (s); - wchar_t *result = malloc ((len + 1) * sizeof (wchar_t)); + /* Include the null terminator in the conversion. */ + size_t len = strlen (s) + 1; + wchar_t *result = reallocarray (NULL, len, sizeof (wchar_t)); + if (result == NULL) + return NULL; + wchar_t *wcp = result; - wchar_t tmp[1]; mbstate_t state; - size_t nbytes; - memset (&state, '\0', sizeof (state)); - while ((nbytes = mbrtowc (tmp, s, len, &state)) > 0) + + while (true) { - if (nbytes >= (size_t) -2) - /* Invalid input string. */ - return NULL; - *wcp++ = towupper (tmp[0]); - len -= nbytes; - s += nbytes; + wchar_t wc; + size_t nbytes = mbrtowc (&wc, s, len, &state); + if (nbytes == 0) + { + /* Terminate the result string. */ + *wcp = L'\0'; + break; + } + else if (nbytes == (size_t) -2) + { + /* Truncated input string. */ + errno = EILSEQ; + free (result); + return NULL; + } + else if (nbytes == (size_t) -1) + { + /* Some other error (including EILSEQ). */ + free (result); + return NULL; + } + else + { + /* A character was converted. */ + *wcp++ = towupper (wc); + len -= nbytes; + s += nbytes; + } } return result; } |