1# mbrtowc.m4 serial 25
2dnl Copyright (C) 2001-2002, 2004-2005, 2008-2012 Free Software Foundation,
3dnl Inc.
4dnl This file is free software; the Free Software Foundation
5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
7
8AC_DEFUN([gl_FUNC_MBRTOWC],
9[
10  AC_REQUIRE([gl_WCHAR_H_DEFAULTS])
11
12  AC_REQUIRE([AC_TYPE_MBSTATE_T])
13  gl_MBSTATE_T_BROKEN
14
15  AC_CHECK_FUNCS_ONCE([mbrtowc])
16  if test $ac_cv_func_mbrtowc = no; then
17    HAVE_MBRTOWC=0
18    AC_CHECK_DECLS([mbrtowc],,, [[
19/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
20   <wchar.h>.
21   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
22   included before <wchar.h>.  */
23#include <stddef.h>
24#include <stdio.h>
25#include <time.h>
26#include <wchar.h>
27]])
28    if test $ac_cv_have_decl_mbrtowc = yes; then
29      dnl On Minix 3.1.8, the system's <wchar.h> declares mbrtowc() although
30      dnl it does not have the function. Avoid a collision with gnulib's
31      dnl replacement.
32      REPLACE_MBRTOWC=1
33    fi
34  else
35    if test $REPLACE_MBSTATE_T = 1; then
36      REPLACE_MBRTOWC=1
37    else
38      gl_MBRTOWC_NULL_ARG1
39      gl_MBRTOWC_NULL_ARG2
40      gl_MBRTOWC_RETVAL
41      gl_MBRTOWC_NUL_RETVAL
42      case "$gl_cv_func_mbrtowc_null_arg1" in
43        *yes) ;;
44        *) AC_DEFINE([MBRTOWC_NULL_ARG1_BUG], [1],
45             [Define if the mbrtowc function has the NULL pwc argument bug.])
46           REPLACE_MBRTOWC=1
47           ;;
48      esac
49      case "$gl_cv_func_mbrtowc_null_arg2" in
50        *yes) ;;
51        *) AC_DEFINE([MBRTOWC_NULL_ARG2_BUG], [1],
52             [Define if the mbrtowc function has the NULL string argument bug.])
53           REPLACE_MBRTOWC=1
54           ;;
55      esac
56      case "$gl_cv_func_mbrtowc_retval" in
57        *yes) ;;
58        *) AC_DEFINE([MBRTOWC_RETVAL_BUG], [1],
59             [Define if the mbrtowc function returns a wrong return value.])
60           REPLACE_MBRTOWC=1
61           ;;
62      esac
63      case "$gl_cv_func_mbrtowc_nul_retval" in
64        *yes) ;;
65        *) AC_DEFINE([MBRTOWC_NUL_RETVAL_BUG], [1],
66             [Define if the mbrtowc function does not return 0 for a NUL character.])
67           REPLACE_MBRTOWC=1
68           ;;
69      esac
70    fi
71  fi
72])
73
74dnl Test whether mbsinit() and mbrtowc() need to be overridden in a way that
75dnl redefines the semantics of the given mbstate_t type.
76dnl Result is REPLACE_MBSTATE_T.
77dnl When this is set to 1, we replace both mbsinit() and mbrtowc(), in order to
78dnl avoid inconsistencies.
79
80AC_DEFUN([gl_MBSTATE_T_BROKEN],
81[
82  AC_REQUIRE([gl_WCHAR_H_DEFAULTS])
83
84  AC_REQUIRE([AC_TYPE_MBSTATE_T])
85  AC_CHECK_FUNCS_ONCE([mbsinit])
86  AC_CHECK_FUNCS_ONCE([mbrtowc])
87  if test $ac_cv_func_mbsinit = yes && test $ac_cv_func_mbrtowc = yes; then
88    gl_MBRTOWC_INCOMPLETE_STATE
89    gl_MBRTOWC_SANITYCHECK
90    REPLACE_MBSTATE_T=0
91    case "$gl_cv_func_mbrtowc_incomplete_state" in
92      *yes) ;;
93      *) REPLACE_MBSTATE_T=1 ;;
94    esac
95    case "$gl_cv_func_mbrtowc_sanitycheck" in
96      *yes) ;;
97      *) REPLACE_MBSTATE_T=1 ;;
98    esac
99  else
100    REPLACE_MBSTATE_T=1
101  fi
102])
103
104dnl Test whether mbrtowc puts the state into non-initial state when parsing an
105dnl incomplete multibyte character.
106dnl Result is gl_cv_func_mbrtowc_incomplete_state.
107
108AC_DEFUN([gl_MBRTOWC_INCOMPLETE_STATE],
109[
110  AC_REQUIRE([AC_PROG_CC])
111  AC_REQUIRE([gt_LOCALE_JA])
112  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
113  AC_CACHE_CHECK([whether mbrtowc handles incomplete characters],
114    [gl_cv_func_mbrtowc_incomplete_state],
115    [
116      dnl Initial guess, used when cross-compiling or when no suitable locale
117      dnl is present.
118changequote(,)dnl
119      case "$host_os" in
120                     # Guess no on AIX and OSF/1.
121        aix* | osf*) gl_cv_func_mbrtowc_incomplete_state="guessing no" ;;
122                     # Guess yes otherwise.
123        *)           gl_cv_func_mbrtowc_incomplete_state="guessing yes" ;;
124      esac
125changequote([,])dnl
126      if test $LOCALE_JA != none; then
127        AC_RUN_IFELSE(
128          [AC_LANG_SOURCE([[
129#include <locale.h>
130#include <string.h>
131/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
132   <wchar.h>.
133   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
134   included before <wchar.h>.  */
135#include <stddef.h>
136#include <stdio.h>
137#include <time.h>
138#include <wchar.h>
139int main ()
140{
141  if (setlocale (LC_ALL, "$LOCALE_JA") != NULL)
142    {
143      const char input[] = "B\217\253\344\217\251\316er"; /* "Büßer" */
144      mbstate_t state;
145      wchar_t wc;
146
147      memset (&state, '\0', sizeof (mbstate_t));
148      if (mbrtowc (&wc, input + 1, 1, &state) == (size_t)(-2))
149        if (mbsinit (&state))
150          return 1;
151    }
152  return 0;
153}]])],
154          [gl_cv_func_mbrtowc_incomplete_state=yes],
155          [gl_cv_func_mbrtowc_incomplete_state=no],
156          [:])
157      fi
158    ])
159])
160
161dnl Test whether mbrtowc works not worse than mbtowc.
162dnl Result is gl_cv_func_mbrtowc_sanitycheck.
163
164AC_DEFUN([gl_MBRTOWC_SANITYCHECK],
165[
166  AC_REQUIRE([AC_PROG_CC])
167  AC_REQUIRE([gt_LOCALE_ZH_CN])
168  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
169  AC_CACHE_CHECK([whether mbrtowc works as well as mbtowc],
170    [gl_cv_func_mbrtowc_sanitycheck],
171    [
172      dnl Initial guess, used when cross-compiling or when no suitable locale
173      dnl is present.
174changequote(,)dnl
175      case "$host_os" in
176                    # Guess no on Solaris 8.
177        solaris2.8) gl_cv_func_mbrtowc_sanitycheck="guessing no" ;;
178                    # Guess yes otherwise.
179        *)          gl_cv_func_mbrtowc_sanitycheck="guessing yes" ;;
180      esac
181changequote([,])dnl
182      if test $LOCALE_ZH_CN != none; then
183        AC_RUN_IFELSE(
184          [AC_LANG_SOURCE([[
185#include <locale.h>
186#include <stdlib.h>
187#include <string.h>
188/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
189   <wchar.h>.
190   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
191   included before <wchar.h>.  */
192#include <stddef.h>
193#include <stdio.h>
194#include <time.h>
195#include <wchar.h>
196int main ()
197{
198  /* This fails on Solaris 8:
199     mbrtowc returns 2, and sets wc to 0x00F0.
200     mbtowc returns 4 (correct) and sets wc to 0x5EDC.  */
201  if (setlocale (LC_ALL, "$LOCALE_ZH_CN") != NULL)
202    {
203      char input[] = "B\250\271\201\060\211\070er"; /* "Büßer" */
204      mbstate_t state;
205      wchar_t wc;
206
207      memset (&state, '\0', sizeof (mbstate_t));
208      if (mbrtowc (&wc, input + 3, 6, &state) != 4
209          && mbtowc (&wc, input + 3, 6) == 4)
210        return 1;
211    }
212  return 0;
213}]])],
214          [gl_cv_func_mbrtowc_sanitycheck=yes],
215          [gl_cv_func_mbrtowc_sanitycheck=no],
216          [:])
217      fi
218    ])
219])
220
221dnl Test whether mbrtowc supports a NULL pwc argument correctly.
222dnl Result is gl_cv_func_mbrtowc_null_arg1.
223
224AC_DEFUN([gl_MBRTOWC_NULL_ARG1],
225[
226  AC_REQUIRE([AC_PROG_CC])
227  AC_REQUIRE([gt_LOCALE_FR_UTF8])
228  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
229  AC_CACHE_CHECK([whether mbrtowc handles a NULL pwc argument],
230    [gl_cv_func_mbrtowc_null_arg1],
231    [
232      dnl Initial guess, used when cross-compiling or when no suitable locale
233      dnl is present.
234changequote(,)dnl
235      case "$host_os" in
236                  # Guess no on Solaris.
237        solaris*) gl_cv_func_mbrtowc_null_arg1="guessing no" ;;
238                  # Guess yes otherwise.
239        *)        gl_cv_func_mbrtowc_null_arg1="guessing yes" ;;
240      esac
241changequote([,])dnl
242      if test $LOCALE_FR_UTF8 != none; then
243        AC_RUN_IFELSE(
244          [AC_LANG_SOURCE([[
245#include <locale.h>
246#include <stdlib.h>
247#include <string.h>
248/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
249   <wchar.h>.
250   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
251   included before <wchar.h>.  */
252#include <stddef.h>
253#include <stdio.h>
254#include <time.h>
255#include <wchar.h>
256int main ()
257{
258  int result = 0;
259
260  if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
261    {
262      char input[] = "\303\237er";
263      mbstate_t state;
264      wchar_t wc;
265      size_t ret;
266
267      memset (&state, '\0', sizeof (mbstate_t));
268      wc = (wchar_t) 0xBADFACE;
269      ret = mbrtowc (&wc, input, 5, &state);
270      if (ret != 2)
271        result |= 1;
272      if (!mbsinit (&state))
273        result |= 2;
274
275      memset (&state, '\0', sizeof (mbstate_t));
276      ret = mbrtowc (NULL, input, 5, &state);
277      if (ret != 2) /* Solaris 7 fails here: ret is -1.  */
278        result |= 4;
279      if (!mbsinit (&state))
280        result |= 8;
281    }
282  return result;
283}]])],
284          [gl_cv_func_mbrtowc_null_arg1=yes],
285          [gl_cv_func_mbrtowc_null_arg1=no],
286          [:])
287      fi
288    ])
289])
290
291dnl Test whether mbrtowc supports a NULL string argument correctly.
292dnl Result is gl_cv_func_mbrtowc_null_arg2.
293
294AC_DEFUN([gl_MBRTOWC_NULL_ARG2],
295[
296  AC_REQUIRE([AC_PROG_CC])
297  AC_REQUIRE([gt_LOCALE_FR_UTF8])
298  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
299  AC_CACHE_CHECK([whether mbrtowc handles a NULL string argument],
300    [gl_cv_func_mbrtowc_null_arg2],
301    [
302      dnl Initial guess, used when cross-compiling or when no suitable locale
303      dnl is present.
304changequote(,)dnl
305      case "$host_os" in
306              # Guess no on OSF/1.
307        osf*) gl_cv_func_mbrtowc_null_arg2="guessing no" ;;
308              # Guess yes otherwise.
309        *)    gl_cv_func_mbrtowc_null_arg2="guessing yes" ;;
310      esac
311changequote([,])dnl
312      if test $LOCALE_FR_UTF8 != none; then
313        AC_RUN_IFELSE(
314          [AC_LANG_SOURCE([[
315#include <locale.h>
316#include <string.h>
317/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
318   <wchar.h>.
319   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
320   included before <wchar.h>.  */
321#include <stddef.h>
322#include <stdio.h>
323#include <time.h>
324#include <wchar.h>
325int main ()
326{
327  if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
328    {
329      mbstate_t state;
330      wchar_t wc;
331      int ret;
332
333      memset (&state, '\0', sizeof (mbstate_t));
334      wc = (wchar_t) 0xBADFACE;
335      mbrtowc (&wc, NULL, 5, &state);
336      /* Check that wc was not modified.  */
337      if (wc != (wchar_t) 0xBADFACE)
338        return 1;
339    }
340  return 0;
341}]])],
342          [gl_cv_func_mbrtowc_null_arg2=yes],
343          [gl_cv_func_mbrtowc_null_arg2=no],
344          [:])
345      fi
346    ])
347])
348
349dnl Test whether mbrtowc, when parsing the end of a multibyte character,
350dnl correctly returns the number of bytes that were needed to complete the
351dnl character (not the total number of bytes of the multibyte character).
352dnl Result is gl_cv_func_mbrtowc_retval.
353
354AC_DEFUN([gl_MBRTOWC_RETVAL],
355[
356  AC_REQUIRE([AC_PROG_CC])
357  AC_REQUIRE([gt_LOCALE_FR_UTF8])
358  AC_REQUIRE([gt_LOCALE_JA])
359  AC_REQUIRE([AC_CANONICAL_HOST])
360  AC_CACHE_CHECK([whether mbrtowc has a correct return value],
361    [gl_cv_func_mbrtowc_retval],
362    [
363      dnl Initial guess, used when cross-compiling or when no suitable locale
364      dnl is present.
365changequote(,)dnl
366      case "$host_os" in
367                                   # Guess no on HP-UX, Solaris, native Windows.
368        hpux* | solaris* | mingw*) gl_cv_func_mbrtowc_retval="guessing no" ;;
369                                   # Guess yes otherwise.
370        *)                         gl_cv_func_mbrtowc_retval="guessing yes" ;;
371      esac
372changequote([,])dnl
373      if test $LOCALE_FR_UTF8 != none || test $LOCALE_JA != none \
374         || { case "$host_os" in mingw*) true;; *) false;; esac; }; then
375        AC_RUN_IFELSE(
376          [AC_LANG_SOURCE([[
377#include <locale.h>
378#include <string.h>
379/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
380   <wchar.h>.
381   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
382   included before <wchar.h>.  */
383#include <stddef.h>
384#include <stdio.h>
385#include <time.h>
386#include <wchar.h>
387int main ()
388{
389  int result = 0;
390  int found_some_locale = 0;
391  /* This fails on Solaris.  */
392  if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
393    {
394      char input[] = "B\303\274\303\237er"; /* "Büßer" */
395      mbstate_t state;
396      wchar_t wc;
397
398      memset (&state, '\0', sizeof (mbstate_t));
399      if (mbrtowc (&wc, input + 1, 1, &state) == (size_t)(-2))
400        {
401          input[1] = '\0';
402          if (mbrtowc (&wc, input + 2, 5, &state) != 1)
403            result |= 1;
404        }
405      found_some_locale = 1;
406    }
407  /* This fails on HP-UX 11.11.  */
408  if (setlocale (LC_ALL, "$LOCALE_JA") != NULL)
409    {
410      char input[] = "B\217\253\344\217\251\316er"; /* "Büßer" */
411      mbstate_t state;
412      wchar_t wc;
413
414      memset (&state, '\0', sizeof (mbstate_t));
415      if (mbrtowc (&wc, input + 1, 1, &state) == (size_t)(-2))
416        {
417          input[1] = '\0';
418          if (mbrtowc (&wc, input + 2, 5, &state) != 2)
419            result |= 2;
420        }
421      found_some_locale = 1;
422    }
423  /* This fails on native Windows.  */
424  if (setlocale (LC_ALL, "Japanese_Japan.932") != NULL)
425    {
426      char input[] = "<\223\372\226\173\214\352>"; /* "<日本語>" */
427      mbstate_t state;
428      wchar_t wc;
429
430      memset (&state, '\0', sizeof (mbstate_t));
431      if (mbrtowc (&wc, input + 3, 1, &state) == (size_t)(-2))
432        {
433          input[3] = '\0';
434          if (mbrtowc (&wc, input + 4, 4, &state) != 1)
435            result |= 4;
436        }
437      found_some_locale = 1;
438    }
439  if (setlocale (LC_ALL, "Chinese_Taiwan.950") != NULL)
440    {
441      char input[] = "<\244\351\245\273\273\171>"; /* "<日本語>" */
442      mbstate_t state;
443      wchar_t wc;
444
445      memset (&state, '\0', sizeof (mbstate_t));
446      if (mbrtowc (&wc, input + 3, 1, &state) == (size_t)(-2))
447        {
448          input[3] = '\0';
449          if (mbrtowc (&wc, input + 4, 4, &state) != 1)
450            result |= 8;
451        }
452      found_some_locale = 1;
453    }
454  if (setlocale (LC_ALL, "Chinese_China.936") != NULL)
455    {
456      char input[] = "<\310\325\261\276\325\132>"; /* "<日本語>" */
457      mbstate_t state;
458      wchar_t wc;
459
460      memset (&state, '\0', sizeof (mbstate_t));
461      if (mbrtowc (&wc, input + 3, 1, &state) == (size_t)(-2))
462        {
463          input[3] = '\0';
464          if (mbrtowc (&wc, input + 4, 4, &state) != 1)
465            result |= 16;
466        }
467      found_some_locale = 1;
468    }
469  return (found_some_locale ? result : 77);
470}]])],
471          [gl_cv_func_mbrtowc_retval=yes],
472          [if test $? != 77; then
473             gl_cv_func_mbrtowc_retval=no
474           fi
475          ],
476          [:])
477      fi
478    ])
479])
480
481dnl Test whether mbrtowc, when parsing a NUL character, correctly returns 0.
482dnl Result is gl_cv_func_mbrtowc_nul_retval.
483
484AC_DEFUN([gl_MBRTOWC_NUL_RETVAL],
485[
486  AC_REQUIRE([AC_PROG_CC])
487  AC_REQUIRE([gt_LOCALE_ZH_CN])
488  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
489  AC_CACHE_CHECK([whether mbrtowc returns 0 when parsing a NUL character],
490    [gl_cv_func_mbrtowc_nul_retval],
491    [
492      dnl Initial guess, used when cross-compiling or when no suitable locale
493      dnl is present.
494changequote(,)dnl
495      case "$host_os" in
496                       # Guess no on Solaris 8 and 9.
497        solaris2.[89]) gl_cv_func_mbrtowc_nul_retval="guessing no" ;;
498                       # Guess yes otherwise.
499        *)             gl_cv_func_mbrtowc_nul_retval="guessing yes" ;;
500      esac
501changequote([,])dnl
502      if test $LOCALE_ZH_CN != none; then
503        AC_RUN_IFELSE(
504          [AC_LANG_SOURCE([[
505#include <locale.h>
506#include <string.h>
507/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
508   <wchar.h>.
509   BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
510   included before <wchar.h>.  */
511#include <stddef.h>
512#include <stdio.h>
513#include <time.h>
514#include <wchar.h>
515int main ()
516{
517  /* This fails on Solaris 8 and 9.  */
518  if (setlocale (LC_ALL, "$LOCALE_ZH_CN") != NULL)
519    {
520      mbstate_t state;
521      wchar_t wc;
522
523      memset (&state, '\0', sizeof (mbstate_t));
524      if (mbrtowc (&wc, "", 1, &state) != 0)
525        return 1;
526    }
527  return 0;
528}]])],
529          [gl_cv_func_mbrtowc_nul_retval=yes],
530          [gl_cv_func_mbrtowc_nul_retval=no],
531          [:])
532      fi
533    ])
534])
535
536# Prerequisites of lib/mbrtowc.c.
537AC_DEFUN([gl_PREREQ_MBRTOWC], [
538  :
539])
540
541
542dnl From Paul Eggert
543
544dnl This is an override of an autoconf macro.
545
546AC_DEFUN([AC_FUNC_MBRTOWC],
547[
548  dnl Same as AC_FUNC_MBRTOWC in autoconf-2.60.
549  AC_CACHE_CHECK([whether mbrtowc and mbstate_t are properly declared],
550    gl_cv_func_mbrtowc,
551    [AC_LINK_IFELSE(
552       [AC_LANG_PROGRAM(
553            [[/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be
554                 included before <wchar.h>.
555                 BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h>
556                 must be included before <wchar.h>.  */
557              #include <stddef.h>
558              #include <stdio.h>
559              #include <time.h>
560              #include <wchar.h>]],
561            [[wchar_t wc;
562              char const s[] = "";
563              size_t n = 1;
564              mbstate_t state;
565              return ! (sizeof state && (mbrtowc) (&wc, s, n, &state));]])],
566       gl_cv_func_mbrtowc=yes,
567       gl_cv_func_mbrtowc=no)])
568  if test $gl_cv_func_mbrtowc = yes; then
569    AC_DEFINE([HAVE_MBRTOWC], [1],
570      [Define to 1 if mbrtowc and mbstate_t are properly declared.])
571  fi
572])
573