(root)/
glibc-2.38/
stdio-common/
tst-vfprintf-user-type.c
       1  /* Test for user-defined types in vfprintf.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* This test contains a printf format specifier, %P, with a custom
      20     type which is a long/double pair.  If a precision is specified,
      21     this indicates the number of such pairs which constitute the
      22     argument.  */
      23  
      24  #include <array_length.h>
      25  #include <locale.h>
      26  #include <printf.h>
      27  #include <stdio.h>
      28  #include <stdlib.h>
      29  #include <string.h>
      30  #include <support/check.h>
      31  #include <support/support.h>
      32  #include <support/test-driver.h>
      33  #include <wchar.h>
      34  
      35  /* Initialized by do_test using register_printf_type.  */
      36  static int user_type;
      37  
      38  struct two_argument
      39  {
      40    long i;
      41    double d;
      42  };
      43  
      44  static void
      45  my_va_arg_function (void *mem, va_list *ap)
      46  {
      47    if (test_verbose > 0)
      48      printf ("info: %s (%p) called\n", __func__, mem);
      49  
      50    struct two_argument *pair = mem;
      51    pair->i = va_arg (*ap, long);
      52    pair->d = va_arg (*ap, double);
      53  }
      54  
      55  static int
      56  my_printf_function (FILE *fp, const struct printf_info *info,
      57                      const void *const *args)
      58  {
      59    if (test_verbose > 0)
      60      printf ("info: %s (%p, %p, {%p}@%p) called for %%%lc (prec %d)\n",
      61              __func__, fp, info, args[0], args, (wint_t) info->spec,
      62              info->prec);
      63  
      64    TEST_COMPARE (info->wide, fwide (fp, 0) > 0);
      65  
      66    TEST_VERIFY (info->spec == 'P');
      67    size_t nargs;
      68    int printed;
      69    if (info->prec >= 0)
      70      {
      71        if (info->wide)
      72          {
      73            if (fputwc (L'{', fp) < 0)
      74              return -1;
      75            }
      76        else
      77          {
      78            if (fputc ('{', fp) < 0)
      79              return -1;
      80          }
      81        nargs = info->prec;
      82        printed = 1;
      83      }
      84    else
      85      {
      86        nargs = 1;
      87        printed = 0;
      88      }
      89  
      90    for (size_t i = 0; i < nargs; ++i)
      91      {
      92        if (i != 0)
      93          {
      94            if (info->wide)
      95              {
      96                if (fputwc (L',', fp) < 0)
      97                  return -1;
      98              }
      99            else
     100              {
     101                if (fputc (',', fp) < 0)
     102                  return -1;
     103              }
     104            ++printed;
     105          }
     106  
     107        /* NB: Triple pointer indirection.  ARGS is an array of void *,
     108           and those pointers point to a pointer to the memory area
     109           supplied to my_va_arg_function.  */
     110        struct two_argument *pair = *(void **) args[i];
     111        int ret;
     112        if (info->wide)
     113          ret = fwprintf (fp, L"(%ld, %f)", pair->i, pair->d);
     114        else
     115          ret = fprintf (fp, "(%ld, %f)", pair->i, pair->d);
     116        if (ret < 0)
     117          return -1;
     118        printed += ret;
     119      }
     120    if (info->prec >= 0)
     121      {
     122        if (info->wide)
     123          {
     124            if (fputwc (L'}', fp) < 0)
     125              return -1;
     126          }
     127        else
     128          {
     129            if (fputc ('}', fp) < 0)
     130              return -1;
     131          }
     132        ++printed;
     133      }
     134    return printed;
     135  }
     136  
     137  static int
     138  my_arginfo_function (const struct printf_info *info,
     139                       size_t n, int *argtypes, int *size)
     140  {
     141    /* Avoid recursion.  */
     142    if (info->spec != 'P')
     143      return -1;
     144    if (test_verbose > 0)
     145      printf ("info: %s (%p, %zu, %p, %p) called for %%%lc (prec %d)\n",
     146              __func__, info, n, argtypes, size, (wint_t) info->spec,
     147              info->prec);
     148  
     149    TEST_VERIFY_EXIT (n >= 1);
     150    size_t nargs;
     151    if (info->prec >= 0)
     152      nargs = info->prec;
     153    else
     154      nargs = 1;
     155  
     156    size_t to_fill = nargs;
     157    if (to_fill > n)
     158      to_fill = n;
     159    for (size_t i = 0; i < to_fill; ++i)
     160      {
     161        argtypes[i] = user_type;
     162        size[i] = sizeof (struct two_argument);
     163      }
     164    if (test_verbose > 0)
     165      printf ("info:   %s return value: %zu\n", __func__, nargs);
     166    return nargs;
     167  }
     168  
     169  static int
     170  do_test (void)
     171  {
     172    user_type = register_printf_type (my_va_arg_function);
     173    if (test_verbose > 0)
     174      printf ("info: allocated user type: %d\n", user_type);
     175    TEST_VERIFY_EXIT (user_type >= PA_LAST);
     176    TEST_VERIFY_EXIT (register_printf_specifier
     177                      ('P', my_printf_function, my_arginfo_function) >= 0);
     178  
     179    /* Alias declaration for asprintf, to avoid the format string
     180       attribute and the associated warning.  */
     181  #if __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
     182    extern int asprintf_alias (char **, const char *, ...) __asm__ ("__asprintfieee128");
     183  #else
     184    extern int asprintf_alias (char **, const char *, ...) __asm__ ("asprintf");
     185  #endif
     186    TEST_VERIFY (asprintf_alias == asprintf);
     187    char *str = NULL;
     188    TEST_VERIFY (asprintf_alias (&str, "[[%P]]", 123L, 456.0) >= 0);
     189    TEST_COMPARE_STRING (str, "[[(123, 456.000000)]]");
     190    free (str);
     191  
     192    str = NULL;
     193    TEST_VERIFY (asprintf_alias (&str, "[[%1$P %1$P]]", 123L, 457.0) >= 0);
     194    TEST_COMPARE_STRING (str, "[[(123, 457.000000) (123, 457.000000)]]");
     195    free (str);
     196  
     197    str = NULL;
     198    TEST_VERIFY (asprintf_alias (&str, "[[%.1P]]", 1L, 2.0) >= 0);
     199    TEST_COMPARE_STRING (str, "[[{(1, 2.000000)}]]");
     200    free (str);
     201  
     202    str = NULL;
     203    TEST_VERIFY (asprintf_alias (&str, "[[%.2P]]", 1L, 2.0, 3L, 4.0) >= 0);
     204    TEST_COMPARE_STRING (str, "[[{(1, 2.000000),(3, 4.000000)}]]");
     205    free (str);
     206  
     207    str = NULL;
     208    TEST_VERIFY (asprintf_alias
     209                 (&str, "[[%.2P | %.3P]]",
     210                  /* argument 1: */ 1L, 2.0, 3L, 4.0,
     211                  /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0)
     212                 >= 0);
     213    TEST_COMPARE_STRING (str,
     214                         "[["
     215                         "{(1, 2.000000),(3, 4.000000)}"
     216                         " | "
     217                         "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}"
     218                         "]]");
     219    free (str);
     220  
     221    /* The following subtest fails due to bug 21534.  */
     222  #if 0
     223    str = NULL;
     224    TEST_VERIFY (asprintf_alias
     225                 (&str, "[[%1$.2P | %2$.3P | %1$.2P]]",
     226                  /* argument 1: */ 1L, 2.0, 3L, 4.0,
     227                  /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0)
     228                 >= 0);
     229    TEST_COMPARE_STRING (str,
     230                         "[["
     231                         "{(1, 2.000000),(3, 4.000000)}"
     232                         " | "
     233                         "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}"
     234                         " | "
     235                         "{(1, 2.000000),(3, 4.000000)}"
     236                         "]]");
     237    free (str);
     238  #endif
     239  
     240    /* Wide variants of the tests above.  */
     241  
     242    wchar_t buf[200];
     243    TEST_VERIFY (swprintf (buf, array_length (buf), L"[[%P]]", 123L, 456.0)
     244                 >= 0);
     245    TEST_COMPARE_STRING_WIDE (buf, L"[[(123, 456.000000)]]");
     246  
     247    TEST_VERIFY (swprintf (buf, array_length (buf), L"[[%1$P %1$P]]",
     248                           123L, 457.0) >= 0);
     249    TEST_COMPARE_STRING_WIDE (buf, L"[[(123, 457.000000) (123, 457.000000)]]");
     250  
     251    TEST_VERIFY (swprintf (buf, array_length (buf), L"[[%.1P]]", 1L, 2.0) >= 0);
     252    TEST_COMPARE_STRING_WIDE (buf, L"[[{(1, 2.000000)}]]");
     253  
     254    TEST_VERIFY (swprintf (buf, array_length (buf), L"[[%.2P]]",
     255                           1L, 2.0, 3L, 4.0) >= 0);
     256    TEST_COMPARE_STRING_WIDE (buf, L"[[{(1, 2.000000),(3, 4.000000)}]]");
     257  
     258    TEST_VERIFY (swprintf
     259                 (buf, array_length (buf), L"[[%.2P | %.3P]]",
     260                  /* argument 1: */ 1L, 2.0, 3L, 4.0,
     261                  /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0)
     262                 >= 0);
     263    TEST_COMPARE_STRING_WIDE (buf,
     264                              L"[["
     265                              "{(1, 2.000000),(3, 4.000000)}"
     266                              " | "
     267                              "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}"
     268                              "]]");
     269  
     270    /* The following subtest fails due to bug 21534.  */
     271  #if 0
     272    TEST_VERIFY (swprintf
     273                 (&buf, array_length (buf), L"[[%1$.2P | %2$.3P | %1$.2P]]",
     274                  /* argument 1: */ 1L, 2.0, 3L, 4.0,
     275                  /* argument 2: */ 5L, 6.0, 7L, 8.0, 9L, 10.0)
     276                 >= 0);
     277    TEST_COMPARE_STRING_WIDE (buf,
     278                              L"[["
     279                              "{(1, 2.000000),(3, 4.000000)}"
     280                              " | "
     281                              "{(5, 6.000000),(7, 8.000000),(9, 10.000000)}"
     282                              " | "
     283                              "{(1, 2.000000),(3, 4.000000)}"
     284                              "]]");
     285  #endif
     286  
     287    return 0;
     288  }
     289  
     290  #include <support/test-driver.c>