(root)/
findutils-4.9.0/
gnulib-tests/
test-inttostr.c
       1  /* Test inttostr functions, and incidentally, INT_BUFSIZE_BOUND
       2     Copyright (C) 2010-2022 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  /* Written by Jim Meyering.  */
      18  
      19  #include <config.h>
      20  
      21  #include "inttostr.h"
      22  #include "intprops.h"
      23  #include <inttypes.h>
      24  #include <stdio.h>
      25  #include <stdlib.h>
      26  #include <string.h>
      27  
      28  #include "macros.h"
      29  
      30  #define STREQ(a, b) (strcmp (a, b) == 0)
      31  #define IS_TIGHT(T) (_GL_SIGNED_TYPE_OR_EXPR (T) == TYPE_SIGNED (T))
      32  #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
      33  
      34  /* Verify that an inttostr function works as advertised.
      35     Convert maximum and minimum (per-type, T) values using both snprintf --
      36     with a cast to intmax_t or uintmax_t -- and FN, and compare the
      37     resulting strings.  Use malloc for the inttostr buffer, so that if
      38     we ever exceed the usually-tight INT_BUFSIZE_BOUND, tools like
      39     valgrind will detect the failure. */
      40  #define CK(T, Fn)                                                       \
      41    do                                                                    \
      42      {                                                                   \
      43        char ref[100];                                                    \
      44        char *buf = malloc (INT_BUFSIZE_BOUND (T));                       \
      45        char const *p;                                                    \
      46        ASSERT (buf);                                                     \
      47        *buf = '\0';                                                      \
      48        ASSERT                                                            \
      49          ((TYPE_SIGNED (T)                                               \
      50            ? snprintf (ref, sizeof ref, "%jd", (intmax_t) TYPE_MINIMUM (T)) \
      51            : snprintf (ref, sizeof ref, "%ju", (uintmax_t) TYPE_MINIMUM (T))) \
      52           < sizeof ref);                                                 \
      53        ASSERT (STREQ ((p = Fn (TYPE_MINIMUM (T), buf)), ref));           \
      54        /* Ensure that INT_BUFSIZE_BOUND is tight for signed types.  */   \
      55        ASSERT (! TYPE_SIGNED (T) || (p == buf && *p == '-'));            \
      56        ASSERT                                                            \
      57          ((TYPE_SIGNED (T)                                               \
      58            ? snprintf (ref, sizeof ref, "%jd", (intmax_t) TYPE_MAXIMUM (T)) \
      59            : snprintf (ref, sizeof ref, "%ju", (uintmax_t) TYPE_MAXIMUM (T))) \
      60           < sizeof ref);                                                 \
      61        ASSERT (STREQ ((p = Fn (TYPE_MAXIMUM (T), buf)), ref));           \
      62        /* For unsigned types, the bound is not always tight.  */         \
      63        ASSERT (! IS_TIGHT (T) || TYPE_SIGNED (T)                         \
      64                || (p == buf && ISDIGIT (*p)));                           \
      65        free (buf);                                                       \
      66      }                                                                   \
      67    while (0)
      68  
      69  int
      70  main (void)
      71  {
      72    size_t b_size = 2;
      73    char *b = malloc (b_size);
      74    ASSERT (b);
      75  
      76    /* Ideally we would rely on the snprintf-posix module, in which case
      77       this guard would not be required, but due to limitations in gnulib's
      78       implementation (see modules/snprintf-posix), we cannot.  */
      79    if (snprintf (b, b_size, "%ju", (uintmax_t) 3) == 1
      80        && b[0] == '3' && b[1] == '\0')
      81      {
      82        CK (int,          inttostr);
      83        CK (unsigned int, uinttostr);
      84        CK (off_t,        offtostr);
      85        CK (uintmax_t,    umaxtostr);
      86        CK (intmax_t,     imaxtostr);
      87        free (b);
      88        return 0;
      89      }
      90  
      91    /* snprintf doesn't accept %ju; skip this test.  */
      92    free (b);
      93    return 77;
      94  }