(root)/
coreutils-9.4/
gnulib-tests/
test-c32rtomb-w32.c
       1  /* Test of conversion of wide character to multibyte character.
       2     Copyright (C) 2008-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  #include <uchar.h>
      20  
      21  #include <locale.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  
      26  #include "localcharset.h"
      27  #include "macros.h"
      28  
      29  #if defined _WIN32 && !defined __CYGWIN__
      30  
      31  static int
      32  test_one_locale (const char *name, int codepage)
      33  {
      34    char buf[64];
      35    size_t ret;
      36  
      37  # if 1
      38    /* Portable code to set the locale.  */
      39    {
      40      char name_with_codepage[1024];
      41  
      42      sprintf (name_with_codepage, "%s.%d", name, codepage);
      43  
      44      /* Set the locale.  */
      45      if (setlocale (LC_ALL, name_with_codepage) == NULL)
      46        return 77;
      47    }
      48  # else
      49    /* Hacky way to set a locale.codepage combination that setlocale() refuses
      50       to set.  */
      51    {
      52      /* Codepage of the current locale, set with setlocale().
      53         Not necessarily the same as GetACP().  */
      54      extern __declspec(dllimport) unsigned int __lc_codepage;
      55  
      56      /* Set the locale.  */
      57      if (setlocale (LC_ALL, name) == NULL)
      58        return 77;
      59  
      60      /* Clobber the codepage and MB_CUR_MAX, both set by setlocale().  */
      61      __lc_codepage = codepage;
      62      switch (codepage)
      63        {
      64        case 1252:
      65        case 1256:
      66          MB_CUR_MAX = 1;
      67          break;
      68        case 932:
      69        case 950:
      70        case 936:
      71          MB_CUR_MAX = 2;
      72          break;
      73        case 54936:
      74        case 65001:
      75          MB_CUR_MAX = 4;
      76          break;
      77        }
      78  
      79      /* Test whether the codepage is really available.  */
      80      {
      81        mbstate_t state;
      82        wchar_t wc;
      83  
      84        memset (&state, '\0', sizeof (mbstate_t));
      85        if (mbrtowc (&wc, " ", 1, &state) == (size_t)(-1))
      86          return 77;
      87      }
      88    }
      89  # endif
      90  
      91    /* Test NUL character.  */
      92    {
      93      buf[0] = 'x';
      94      ret = c32rtomb (buf, 0, NULL);
      95      ASSERT (ret == 1);
      96      ASSERT (buf[0] == '\0');
      97    }
      98  
      99    /* Test single bytes.  */
     100    {
     101      int c;
     102  
     103      for (c = 0; c < 0x100; c++)
     104        switch (c)
     105          {
     106          case '\t': case '\v': case '\f':
     107          case ' ': case '!': case '"': case '#': case '%':
     108          case '&': case '\'': case '(': case ')': case '*':
     109          case '+': case ',': case '-': case '.': case '/':
     110          case '0': case '1': case '2': case '3': case '4':
     111          case '5': case '6': case '7': case '8': case '9':
     112          case ':': case ';': case '<': case '=': case '>':
     113          case '?':
     114          case 'A': case 'B': case 'C': case 'D': case 'E':
     115          case 'F': case 'G': case 'H': case 'I': case 'J':
     116          case 'K': case 'L': case 'M': case 'N': case 'O':
     117          case 'P': case 'Q': case 'R': case 'S': case 'T':
     118          case 'U': case 'V': case 'W': case 'X': case 'Y':
     119          case 'Z':
     120          case '[': case '\\': case ']': case '^': case '_':
     121          case 'a': case 'b': case 'c': case 'd': case 'e':
     122          case 'f': case 'g': case 'h': case 'i': case 'j':
     123          case 'k': case 'l': case 'm': case 'n': case 'o':
     124          case 'p': case 'q': case 'r': case 's': case 't':
     125          case 'u': case 'v': case 'w': case 'x': case 'y':
     126          case 'z': case '{': case '|': case '}': case '~':
     127            /* c is in the ISO C "basic character set".  */
     128            ret = c32rtomb (buf, btoc32 (c), NULL);
     129            ASSERT (ret == 1);
     130            ASSERT (buf[0] == (char) c);
     131            break;
     132          }
     133    }
     134  
     135    /* Test special calling convention, passing a NULL pointer.  */
     136    {
     137      ret = c32rtomb (NULL, '\0', NULL);
     138      ASSERT (ret == 1);
     139      ret = c32rtomb (NULL, btoc32 ('x'), NULL);
     140      ASSERT (ret == 1);
     141    }
     142  
     143    switch (codepage)
     144      {
     145      case 1252:
     146        /* Locale encoding is CP1252, an extension of ISO-8859-1.  */
     147        {
     148          /* Convert "B\374\337er": "Büßer" */
     149          memset (buf, 'x', 8);
     150          ret = c32rtomb (buf, 0x00FC, NULL);
     151          ASSERT (ret == 1);
     152          ASSERT (memcmp (buf, "\374", 1) == 0);
     153          ASSERT (buf[1] == 'x');
     154  
     155          memset (buf, 'x', 8);
     156          ret = c32rtomb (buf, 0x00DF, NULL);
     157          ASSERT (ret == 1);
     158          ASSERT (memcmp (buf, "\337", 1) == 0);
     159          ASSERT (buf[1] == 'x');
     160        }
     161        return 0;
     162  
     163      case 1256:
     164        /* Locale encoding is CP1256, not the same as ISO-8859-6.  */
     165        {
     166          /* Convert "x\302\341\346y": "xآلوy" */
     167          memset (buf, 'x', 8);
     168          ret = c32rtomb (buf, 0x0622, NULL);
     169          ASSERT (ret == 1);
     170          ASSERT (memcmp (buf, "\302", 1) == 0);
     171          ASSERT (buf[1] == 'x');
     172  
     173          memset (buf, 'x', 8);
     174          ret = c32rtomb (buf, 0x0644, NULL);
     175          ASSERT (ret == 1);
     176          ASSERT (memcmp (buf, "\341", 1) == 0);
     177          ASSERT (buf[1] == 'x');
     178  
     179          memset (buf, 'x', 8);
     180          ret = c32rtomb (buf, 0x0648, NULL);
     181          ASSERT (ret == 1);
     182          ASSERT (memcmp (buf, "\346", 1) == 0);
     183          ASSERT (buf[1] == 'x');
     184        }
     185        return 0;
     186  
     187      case 65001:
     188        /* Locale encoding is CP65001 = UTF-8.  */
     189        if (strcmp (locale_charset (), "UTF-8") != 0)
     190          return 77;
     191        {
     192          /* Convert "s\303\274\303\237\360\237\230\213!"; "süß😋!" */
     193          memset (buf, 'x', 8);
     194          ret = c32rtomb (buf, 0x00FC, NULL);
     195          ASSERT (ret == 2);
     196          ASSERT (memcmp (buf, "\303\274", 2) == 0);
     197          ASSERT (buf[2] == 'x');
     198  
     199          memset (buf, 'x', 8);
     200          ret = c32rtomb (buf, 0x00DF, NULL);
     201          ASSERT (ret == 2);
     202          ASSERT (memcmp (buf, "\303\237", 2) == 0);
     203          ASSERT (buf[2] == 'x');
     204  
     205          memset (buf, 'x', 8);
     206          ret = c32rtomb (buf, 0x1F60B, NULL);
     207          ASSERT (ret == 4);
     208          ASSERT (memcmp (buf, "\360\237\230\213", 4) == 0);
     209          ASSERT (buf[4] == 'x');
     210        }
     211        return 0;
     212  
     213      case 932:
     214        /* Locale encoding is CP932, similar to Shift_JIS.  */
     215        {
     216          /* Convert "<\223\372\226\173\214\352>": "<日本語>" */
     217          memset (buf, 'x', 8);
     218          ret = c32rtomb (buf, 0x65E5, NULL);
     219          ASSERT (ret == 2);
     220          ASSERT (memcmp (buf, "\223\372", 2) == 0);
     221          ASSERT (buf[2] == 'x');
     222  
     223          memset (buf, 'x', 8);
     224          ret = c32rtomb (buf, 0x672C, NULL);
     225          ASSERT (ret == 2);
     226          ASSERT (memcmp (buf, "\226\173", 2) == 0);
     227          ASSERT (buf[2] == 'x');
     228  
     229          memset (buf, 'x', 8);
     230          ret = c32rtomb (buf, 0x8A9E, NULL);
     231          ASSERT (ret == 2);
     232          ASSERT (memcmp (buf, "\214\352", 2) == 0);
     233          ASSERT (buf[2] == 'x');
     234        }
     235        return 0;
     236  
     237      case 950:
     238        /* Locale encoding is CP950, similar to Big5.  */
     239        {
     240          /* Convert "<\244\351\245\273\273\171>": "<日本語>" */
     241          memset (buf, 'x', 8);
     242          ret = c32rtomb (buf, 0x65E5, NULL);
     243          ASSERT (ret == 2);
     244          ASSERT (memcmp (buf, "\244\351", 2) == 0);
     245          ASSERT (buf[2] == 'x');
     246  
     247          memset (buf, 'x', 8);
     248          ret = c32rtomb (buf, 0x672C, NULL);
     249          ASSERT (ret == 2);
     250          ASSERT (memcmp (buf, "\245\273", 2) == 0);
     251          ASSERT (buf[2] == 'x');
     252  
     253          memset (buf, 'x', 8);
     254          ret = c32rtomb (buf, 0x8A9E, NULL);
     255          ASSERT (ret == 2);
     256          ASSERT (memcmp (buf, "\273\171", 2) == 0);
     257          ASSERT (buf[2] == 'x');
     258        }
     259        return 0;
     260  
     261      case 936:
     262        /* Locale encoding is CP936 = GBK, an extension of GB2312.  */
     263        {
     264          /* Convert "<\310\325\261\276\325\132>": "<日本語>" */
     265          memset (buf, 'x', 8);
     266          ret = c32rtomb (buf, 0x65E5, NULL);
     267          ASSERT (ret == 2);
     268          ASSERT (memcmp (buf, "\310\325", 2) == 0);
     269          ASSERT (buf[2] == 'x');
     270  
     271          memset (buf, 'x', 8);
     272          ret = c32rtomb (buf, 0x672C, NULL);
     273          ASSERT (ret == 2);
     274          ASSERT (memcmp (buf, "\261\276", 2) == 0);
     275          ASSERT (buf[2] == 'x');
     276  
     277          memset (buf, 'x', 8);
     278          ret = c32rtomb (buf, 0x8A9E, NULL);
     279          ASSERT (ret == 2);
     280          ASSERT (memcmp (buf, "\325\132", 2) == 0);
     281          ASSERT (buf[2] == 'x');
     282        }
     283        return 0;
     284  
     285      case 54936:
     286        /* Locale encoding is CP54936 = GB18030.  */
     287        if (strcmp (locale_charset (), "GB18030") != 0)
     288          return 77;
     289        {
     290          /* Convert "s\250\271\201\060\211\070\224\071\375\067!"; "süß😋!" */
     291          memset (buf, 'x', 8);
     292          ret = c32rtomb (buf, 0x00FC, NULL);
     293          ASSERT (ret == 2);
     294          ASSERT (memcmp (buf, "\250\271", 2) == 0);
     295          ASSERT (buf[2] == 'x');
     296  
     297          memset (buf, 'x', 8);
     298          ret = c32rtomb (buf, 0x00DF, NULL);
     299          ASSERT (ret == 4);
     300          ASSERT (memcmp (buf, "\201\060\211\070", 4) == 0);
     301          ASSERT (buf[4] == 'x');
     302  
     303          memset (buf, 'x', 8);
     304          ret = c32rtomb (buf, 0x1F60B, NULL);
     305          ASSERT (ret == 4);
     306          ASSERT (memcmp (buf, "\224\071\375\067", 4) == 0);
     307          ASSERT (buf[4] == 'x');
     308        }
     309        return 0;
     310  
     311      default:
     312        return 1;
     313      }
     314  }
     315  
     316  int
     317  main (int argc, char *argv[])
     318  {
     319    int codepage = atoi (argv[argc - 1]);
     320    int result;
     321    int i;
     322  
     323    result = 77;
     324    for (i = 1; i < argc - 1; i++)
     325      {
     326        int ret = test_one_locale (argv[i], codepage);
     327  
     328        if (ret != 77)
     329          result = ret;
     330      }
     331  
     332    if (result == 77)
     333      {
     334        fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
     335                 codepage);
     336      }
     337    return result;
     338  }
     339  
     340  #else
     341  
     342  int
     343  main (int argc, char *argv[])
     344  {
     345    fputs ("Skipping test: not a native Windows system\n", stderr);
     346    return 77;
     347  }
     348  
     349  #endif