15dd04ce5SOliver Tappe/* Test of conversion of string to wide string.
25dd04ce5SOliver Tappe Copyright (C) 2008-2011 Free Software Foundation, Inc.
35dd04ce5SOliver Tappe
45dd04ce5SOliver Tappe This program is free software: you can redistribute it and/or modify
55dd04ce5SOliver Tappe it under the terms of the GNU General Public License as published by
65dd04ce5SOliver Tappe the Free Software Foundation; either version 3 of the License, or
75dd04ce5SOliver Tappe (at your option) any later version.
85dd04ce5SOliver Tappe
95dd04ce5SOliver Tappe This program is distributed in the hope that it will be useful,
105dd04ce5SOliver Tappe but WITHOUT ANY WARRANTY; without even the implied warranty of
115dd04ce5SOliver Tappe MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
125dd04ce5SOliver Tappe GNU General Public License for more details.
135dd04ce5SOliver Tappe
145dd04ce5SOliver Tappe You should have received a copy of the GNU General Public License
155dd04ce5SOliver Tappe along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
165dd04ce5SOliver Tappe
175dd04ce5SOliver Tappe/* Written by Bruno Haible <bruno@clisp.org>, 2008.  */
185dd04ce5SOliver Tappe
195dd04ce5SOliver Tappe#undef NDEBUG
205dd04ce5SOliver Tappe#include <assert.h>
215dd04ce5SOliver Tappe#include <locale.h>
225dd04ce5SOliver Tappe#include <stdio.h>
235dd04ce5SOliver Tappe#include <string.h>
245dd04ce5SOliver Tappe#include <wchar.h>
255dd04ce5SOliver Tappe
265dd04ce5SOliver Tappe
275dd04ce5SOliver Tappe#define BUFSIZE 10
285dd04ce5SOliver Tappe
295dd04ce5SOliver Tappe
305dd04ce5SOliver Tappeint
315dd04ce5SOliver Tappemain(int argc, char *argv[])
325dd04ce5SOliver Tappe{
335dd04ce5SOliver Tappe	mbstate_t state;
345dd04ce5SOliver Tappe	wchar_t wc;
355dd04ce5SOliver Tappe	size_t ret;
365dd04ce5SOliver Tappe	int mode;
375dd04ce5SOliver Tappe
385dd04ce5SOliver Tappe	/* configure should already have checked that the locale is supported.  */
395dd04ce5SOliver Tappe	if (setlocale(LC_ALL, "") == NULL) {
405dd04ce5SOliver Tappe		fprintf(stderr, "unable to set standard locale\n");
415dd04ce5SOliver Tappe		return 1;
425dd04ce5SOliver Tappe	}
435dd04ce5SOliver Tappe
445dd04ce5SOliver Tappe	/* Test NUL byte input.  */
455dd04ce5SOliver Tappe	{
465dd04ce5SOliver Tappe		const char *src;
475dd04ce5SOliver Tappe
485dd04ce5SOliver Tappe		memset(&state, '\0', sizeof(mbstate_t));
495dd04ce5SOliver Tappe
505dd04ce5SOliver Tappe		src = "";
515dd04ce5SOliver Tappe		ret = mbsnrtowcs(NULL, &src, 1, 0, &state);
525dd04ce5SOliver Tappe		assert(ret == 0);
535dd04ce5SOliver Tappe		assert(mbsinit (&state));
545dd04ce5SOliver Tappe
555dd04ce5SOliver Tappe		src = "";
565dd04ce5SOliver Tappe		ret = mbsnrtowcs(NULL, &src, 1, 1, &state);
575dd04ce5SOliver Tappe		assert(ret == 0);
585dd04ce5SOliver Tappe		assert(mbsinit (&state));
595dd04ce5SOliver Tappe
605dd04ce5SOliver Tappe		wc = (wchar_t) 0xBADFACE;
615dd04ce5SOliver Tappe		src = "";
625dd04ce5SOliver Tappe		ret = mbsnrtowcs(&wc, &src, 1, 0, &state);
635dd04ce5SOliver Tappe		assert(ret == 0);
645dd04ce5SOliver Tappe		assert(wc == (wchar_t) 0xBADFACE);
655dd04ce5SOliver Tappe		assert(mbsinit (&state));
665dd04ce5SOliver Tappe
675dd04ce5SOliver Tappe		wc = (wchar_t) 0xBADFACE;
685dd04ce5SOliver Tappe		src = "";
695dd04ce5SOliver Tappe		ret = mbsnrtowcs(&wc, &src, 1, 1, &state);
705dd04ce5SOliver Tappe		assert(ret == 0);
715dd04ce5SOliver Tappe		assert(wc == 0);
725dd04ce5SOliver Tappe		assert(mbsinit (&state));
735dd04ce5SOliver Tappe	}
745dd04ce5SOliver Tappe
755dd04ce5SOliver Tappe	for (mode = '1'; mode <= '4'; ++mode) {
765dd04ce5SOliver Tappe		int unlimited;
775dd04ce5SOliver Tappe		for (unlimited = 0; unlimited < 2; unlimited++) {
785dd04ce5SOliver Tappe			wchar_t buf[BUFSIZE];
795dd04ce5SOliver Tappe			const char *src;
805dd04ce5SOliver Tappe			mbstate_t temp_state;
815dd04ce5SOliver Tappe
825dd04ce5SOliver Tappe			{
835dd04ce5SOliver Tappe				size_t i;
845dd04ce5SOliver Tappe				for (i = 0; i < BUFSIZE; i++)
855dd04ce5SOliver Tappe					buf[i] = (wchar_t) 0xBADFACE;
865dd04ce5SOliver Tappe			}
875dd04ce5SOliver Tappe
885dd04ce5SOliver Tappe			switch (mode) {
895dd04ce5SOliver Tappe				case '1':
905dd04ce5SOliver Tappe					/* Locale encoding is ISO-8859-1 or ISO-8859-15.  */
915dd04ce5SOliver Tappe		    	printf("ISO8859-1 ...\n");
925dd04ce5SOliver Tappe				{
935dd04ce5SOliver Tappe					char input[] = "B\374\337er"; /* "B����er" */
945dd04ce5SOliver Tappe					memset(&state, '\0', sizeof(mbstate_t));
955dd04ce5SOliver Tappe
965dd04ce5SOliver Tappe					if (setlocale (LC_ALL, "en_US.ISO8859-1") == NULL) {
975dd04ce5SOliver Tappe						fprintf(stderr,
985dd04ce5SOliver Tappe							"unable to set ISO8859-1 locale, skipping\n");
995dd04ce5SOliver Tappe						break;
1005dd04ce5SOliver Tappe					}
1015dd04ce5SOliver Tappe
1025dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
1035dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input, 1, &state);
1045dd04ce5SOliver Tappe					assert(ret == 1);
1055dd04ce5SOliver Tappe					assert(wc == 'B');
1065dd04ce5SOliver Tappe					assert(mbsinit (&state));
1075dd04ce5SOliver Tappe					input[0] = '\0';
1085dd04ce5SOliver Tappe
1095dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
1105dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input + 1, 1, &state);
1115dd04ce5SOliver Tappe					assert(ret == 1);
1125dd04ce5SOliver Tappe					assert(wctob (wc) == (unsigned char) '\374');
1135dd04ce5SOliver Tappe					assert(mbsinit (&state));
1145dd04ce5SOliver Tappe					input[1] = '\0';
1155dd04ce5SOliver Tappe
1165dd04ce5SOliver Tappe					src = input + 2;
1175dd04ce5SOliver Tappe					temp_state = state;
1185dd04ce5SOliver Tappe					ret = mbsnrtowcs(NULL, &src, 4, unlimited ? BUFSIZE : 1,
1195dd04ce5SOliver Tappe						&temp_state);
1205dd04ce5SOliver Tappe					assert(ret == 3);
1215dd04ce5SOliver Tappe					assert(src == input + 2);
1225dd04ce5SOliver Tappe					assert(mbsinit (&state));
1235dd04ce5SOliver Tappe
1245dd04ce5SOliver Tappe					src = input + 2;
1255dd04ce5SOliver Tappe					ret = mbsnrtowcs(buf, &src, 4, unlimited ? BUFSIZE : 1,
1265dd04ce5SOliver Tappe						&state);
1275dd04ce5SOliver Tappe					assert(ret == (unlimited ? 3 : 1));
1285dd04ce5SOliver Tappe					assert(src == (unlimited ? NULL : input + 3));
1295dd04ce5SOliver Tappe					assert(wctob (buf[0]) == (unsigned char) '\337');
1305dd04ce5SOliver Tappe					if (unlimited) {
1315dd04ce5SOliver Tappe						assert(buf[1] == 'e');
1325dd04ce5SOliver Tappe						assert(buf[2] == 'r');
1335dd04ce5SOliver Tappe						assert(buf[3] == 0);
1345dd04ce5SOliver Tappe						assert(buf[4] == (wchar_t) 0xBADFACE);
1355dd04ce5SOliver Tappe					} else
1365dd04ce5SOliver Tappe						assert(buf[1] == (wchar_t) 0xBADFACE);
1375dd04ce5SOliver Tappe					assert(mbsinit (&state));
1385dd04ce5SOliver Tappe				}
1395dd04ce5SOliver Tappe					break;
1405dd04ce5SOliver Tappe
1415dd04ce5SOliver Tappe				case '2':
1425dd04ce5SOliver Tappe					/* Locale encoding is UTF-8.  */
1435dd04ce5SOliver Tappe		    	printf("UTF-8 ...\n");
1445dd04ce5SOliver Tappe				{
1455dd04ce5SOliver Tappe					char input[] = "B\303\274\303\237er"; /* "B����er" */
1465dd04ce5SOliver Tappe					memset(&state, '\0', sizeof(mbstate_t));
1475dd04ce5SOliver Tappe
1485dd04ce5SOliver Tappe					if (setlocale (LC_ALL, "en_US.UTF-8") == NULL) {
1495dd04ce5SOliver Tappe						fprintf(stderr,
1505dd04ce5SOliver Tappe							"unable to set UTF-8 locale, skipping\n");
1515dd04ce5SOliver Tappe						break;
1525dd04ce5SOliver Tappe					}
1535dd04ce5SOliver Tappe
1545dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
1555dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input, 1, &state);
1565dd04ce5SOliver Tappe					assert(ret == 1);
1575dd04ce5SOliver Tappe					assert(wc == 'B');
1585dd04ce5SOliver Tappe					assert(mbsinit (&state));
1595dd04ce5SOliver Tappe					input[0] = '\0';
1605dd04ce5SOliver Tappe
1615dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
1625dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input + 1, 1, &state);
1635dd04ce5SOliver Tappe					assert(ret == (size_t)(-2));
1645dd04ce5SOliver Tappe					assert(wc == (wchar_t) 0xBADFACE);
1655dd04ce5SOliver Tappe					assert(!mbsinit (&state));
1665dd04ce5SOliver Tappe					input[1] = '\0';
1675dd04ce5SOliver Tappe
1685dd04ce5SOliver Tappe// Copying mbstate_t doesn't really copy the ICU-converter's state, so this
1695dd04ce5SOliver Tappe// doesn't work on Haiku.
1705dd04ce5SOliver Tappe#ifndef __HAIKU__
1715dd04ce5SOliver Tappe					src = input + 2;
1725dd04ce5SOliver Tappe					temp_state = state;
1735dd04ce5SOliver Tappe					ret = mbsnrtowcs(NULL, &src, 6, unlimited ? BUFSIZE : 2,
1745dd04ce5SOliver Tappe						&temp_state);
1755dd04ce5SOliver Tappe					assert(ret == 4);
1765dd04ce5SOliver Tappe					assert(src == input + 2);
1775dd04ce5SOliver Tappe					assert(!mbsinit (&state));
1785dd04ce5SOliver Tappe#endif
1795dd04ce5SOliver Tappe
1805dd04ce5SOliver Tappe					src = input + 2;
1815dd04ce5SOliver Tappe					ret = mbsnrtowcs(buf, &src, 6, unlimited ? BUFSIZE : 2,
1825dd04ce5SOliver Tappe						&state);
1835dd04ce5SOliver Tappe					assert(ret == (unlimited ? 4 : 2));
1845dd04ce5SOliver Tappe					assert(src == (unlimited ? NULL : input + 5));
1855dd04ce5SOliver Tappe					assert(wctob (buf[0]) == EOF);
1865dd04ce5SOliver Tappe					assert(wctob (buf[1]) == EOF);
1875dd04ce5SOliver Tappe					if (unlimited) {
1885dd04ce5SOliver Tappe						assert(buf[2] == 'e');
1895dd04ce5SOliver Tappe						assert(buf[3] == 'r');
1905dd04ce5SOliver Tappe						assert(buf[4] == 0);
1915dd04ce5SOliver Tappe						assert(buf[5] == (wchar_t) 0xBADFACE);
1925dd04ce5SOliver Tappe					} else
1935dd04ce5SOliver Tappe						assert(buf[2] == (wchar_t) 0xBADFACE);
1945dd04ce5SOliver Tappe					assert(mbsinit (&state));
1955dd04ce5SOliver Tappe				}
1965dd04ce5SOliver Tappe					break;
1975dd04ce5SOliver Tappe
1985dd04ce5SOliver Tappe				case '3':
1995dd04ce5SOliver Tappe					/* Locale encoding is EUC-JP.  */
2005dd04ce5SOliver Tappe		    	printf("EUC-JP ...\n");
2015dd04ce5SOliver Tappe				{
2025dd04ce5SOliver Tappe					char input[] = "<\306\374\313\334\270\354>"; /* "<���������>" */
2035dd04ce5SOliver Tappe					memset(&state, '\0', sizeof(mbstate_t));
2045dd04ce5SOliver Tappe
2055dd04ce5SOliver Tappe					if (setlocale (LC_ALL, "en_US.EUC-JP") == NULL) {
2065dd04ce5SOliver Tappe						fprintf(stderr,
2075dd04ce5SOliver Tappe							"unable to set EUC-JP locale, skipping\n");
2085dd04ce5SOliver Tappe						break;
2095dd04ce5SOliver Tappe					}
2105dd04ce5SOliver Tappe
2115dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
2125dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input, 1, &state);
2135dd04ce5SOliver Tappe					assert(ret == 1);
2145dd04ce5SOliver Tappe					assert(wc == '<');
2155dd04ce5SOliver Tappe					assert(mbsinit (&state));
2165dd04ce5SOliver Tappe					input[0] = '\0';
2175dd04ce5SOliver Tappe
2185dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
2195dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input + 1, 2, &state);
2205dd04ce5SOliver Tappe					assert(ret == 2);
2215dd04ce5SOliver Tappe					assert(wctob (wc) == EOF);
2225dd04ce5SOliver Tappe					assert(mbsinit (&state));
2235dd04ce5SOliver Tappe					input[1] = '\0';
2245dd04ce5SOliver Tappe					input[2] = '\0';
2255dd04ce5SOliver Tappe
2265dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
2275dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input + 3, 1, &state);
2285dd04ce5SOliver Tappe					assert(ret == (size_t)(-2));
2295dd04ce5SOliver Tappe					assert(wc == (wchar_t) 0xBADFACE);
2305dd04ce5SOliver Tappe					assert(!mbsinit (&state));
2315dd04ce5SOliver Tappe					input[3] = '\0';
2325dd04ce5SOliver Tappe
2335dd04ce5SOliver Tappe// Copying mbstate_t doesn't really copy the ICU-converter's state, so this
2345dd04ce5SOliver Tappe// doesn't work on Haiku.
2355dd04ce5SOliver Tappe#ifndef __HAIKU__
2365dd04ce5SOliver Tappe					src = input + 4;
2375dd04ce5SOliver Tappe					temp_state = state;
2385dd04ce5SOliver Tappe					ret = mbsnrtowcs(NULL, &src, 5, unlimited ? BUFSIZE : 2,
2395dd04ce5SOliver Tappe						&temp_state);
2405dd04ce5SOliver Tappe					assert(ret == 3);
2415dd04ce5SOliver Tappe					assert(src == input + 4);
2425dd04ce5SOliver Tappe					assert(!mbsinit (&state));
2435dd04ce5SOliver Tappe#endif
2445dd04ce5SOliver Tappe
2455dd04ce5SOliver Tappe					src = input + 4;
2465dd04ce5SOliver Tappe					ret = mbsnrtowcs(buf, &src, 5, unlimited ? BUFSIZE : 2,
2475dd04ce5SOliver Tappe						&state);
2485dd04ce5SOliver Tappe					assert(ret == (unlimited ? 3 : 2));
2495dd04ce5SOliver Tappe					assert(src == (unlimited ? NULL : input + 7));
2505dd04ce5SOliver Tappe					assert(wctob (buf[0]) == EOF);
2515dd04ce5SOliver Tappe					assert(wctob (buf[1]) == EOF);
2525dd04ce5SOliver Tappe					if (unlimited) {
2535dd04ce5SOliver Tappe						assert(buf[2] == '>');
2545dd04ce5SOliver Tappe						assert(buf[3] == 0);
2555dd04ce5SOliver Tappe						assert(buf[4] == (wchar_t) 0xBADFACE);
2565dd04ce5SOliver Tappe					} else
2575dd04ce5SOliver Tappe						assert(buf[2] == (wchar_t) 0xBADFACE);
2585dd04ce5SOliver Tappe					assert(mbsinit (&state));
2595dd04ce5SOliver Tappe				}
2605dd04ce5SOliver Tappe					break;
2615dd04ce5SOliver Tappe
2625dd04ce5SOliver Tappe				case '4':
2635dd04ce5SOliver Tappe					/* Locale encoding is GB18030.  */
2645dd04ce5SOliver Tappe		    	printf("GB18030 ...\n");
2655dd04ce5SOliver Tappe				{
2665dd04ce5SOliver Tappe					char input[] = "B\250\271\201\060\211\070er"; /* "B����er" */
2675dd04ce5SOliver Tappe					memset(&state, '\0', sizeof(mbstate_t));
2685dd04ce5SOliver Tappe
2695dd04ce5SOliver Tappe					if (setlocale (LC_ALL, "en_US.GB18030") == NULL) {
2705dd04ce5SOliver Tappe						fprintf(stderr,
2715dd04ce5SOliver Tappe							"unable to set GB18030 locale, skipping\n");
2725dd04ce5SOliver Tappe						break;
2735dd04ce5SOliver Tappe					}
2745dd04ce5SOliver Tappe
2755dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
2765dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input, 1, &state);
2775dd04ce5SOliver Tappe					assert(ret == 1);
2785dd04ce5SOliver Tappe					assert(wc == 'B');
2795dd04ce5SOliver Tappe					assert(mbsinit (&state));
2805dd04ce5SOliver Tappe					input[0] = '\0';
2815dd04ce5SOliver Tappe
2825dd04ce5SOliver Tappe					wc = (wchar_t) 0xBADFACE;
2835dd04ce5SOliver Tappe					ret = mbrtowc(&wc, input + 1, 1, &state);
2845dd04ce5SOliver Tappe					assert(ret == (size_t)(-2));
2855dd04ce5SOliver Tappe					assert(wc == (wchar_t) 0xBADFACE);
2865dd04ce5SOliver Tappe					assert(!mbsinit (&state));
2875dd04ce5SOliver Tappe					input[1] = '\0';
2885dd04ce5SOliver Tappe
2895dd04ce5SOliver Tappe// Copying mbstate_t doesn't really copy the ICU-converter's state, so this
2905dd04ce5SOliver Tappe// doesn't work on Haiku.
2915dd04ce5SOliver Tappe#ifndef __HAIKU__
2925dd04ce5SOliver Tappe					src = input + 2;
2935dd04ce5SOliver Tappe					temp_state = state;
2945dd04ce5SOliver Tappe					ret = mbsnrtowcs(NULL, &src, 8, unlimited ? BUFSIZE : 2,
2955dd04ce5SOliver Tappe						&temp_state);
2965dd04ce5SOliver Tappe					assert(ret == 4);
2975dd04ce5SOliver Tappe					assert(src == input + 2);
2985dd04ce5SOliver Tappe					assert(!mbsinit (&state));
2995dd04ce5SOliver Tappe#endif
3005dd04ce5SOliver Tappe
3015dd04ce5SOliver Tappe					src = input + 2;
3025dd04ce5SOliver Tappe					ret = mbsnrtowcs(buf, &src, 8, unlimited ? BUFSIZE : 2,
3035dd04ce5SOliver Tappe						&state);
3045dd04ce5SOliver Tappe					assert(ret == (unlimited ? 4 : 2));
3055dd04ce5SOliver Tappe					assert(src == (unlimited ? NULL : input + 7));
3065dd04ce5SOliver Tappe					assert(wctob (buf[0]) == EOF);
3075dd04ce5SOliver Tappe					assert(wctob (buf[1]) == EOF);
3085dd04ce5SOliver Tappe					if (unlimited) {
3095dd04ce5SOliver Tappe						assert(buf[2] == 'e');
3105dd04ce5SOliver Tappe						assert(buf[3] == 'r');
3115dd04ce5SOliver Tappe						assert(buf[4] == 0);
3125dd04ce5SOliver Tappe						assert(buf[5] == (wchar_t) 0xBADFACE);
3135dd04ce5SOliver Tappe					} else
3145dd04ce5SOliver Tappe						assert(buf[2] == (wchar_t) 0xBADFACE);
3155dd04ce5SOliver Tappe					assert(mbsinit (&state));
3165dd04ce5SOliver Tappe				}
3175dd04ce5SOliver Tappe					break;
3185dd04ce5SOliver Tappe
3195dd04ce5SOliver Tappe				default:
3205dd04ce5SOliver Tappe					return 1;
3215dd04ce5SOliver Tappe			}
3225dd04ce5SOliver Tappe		}
3235dd04ce5SOliver Tappe	}
3245dd04ce5SOliver Tappe
3255dd04ce5SOliver Tappe	return 0;
3265dd04ce5SOliver Tappe}
327