(root)/
tar-1.35/
gnu/
xvasprintf.c
       1  /* vasprintf and asprintf with out-of-memory checking.
       2     Copyright (C) 1999, 2002-2004, 2006-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  /* Specification.  */
      20  #include "xvasprintf.h"
      21  
      22  #include <errno.h>
      23  #include <limits.h>
      24  #include <string.h>
      25  #include <stdio.h>
      26  
      27  #include "xalloc.h"
      28  
      29  /* Checked size_t computations.  */
      30  #include "xsize.h"
      31  
      32  static char *
      33  xstrcat (size_t argcount, va_list args)
      34  {
      35    char *result;
      36    va_list ap;
      37    size_t totalsize;
      38    size_t i;
      39    char *p;
      40  
      41    /* Determine the total size.  */
      42    totalsize = 0;
      43    va_copy (ap, args);
      44    for (i = argcount; i > 0; i--)
      45      {
      46        const char *next = va_arg (ap, const char *);
      47        totalsize = xsum (totalsize, strlen (next));
      48      }
      49    va_end (ap);
      50  
      51    /* Test for overflow in the summing pass above or in (totalsize + 1) below.
      52       Also, don't return a string longer than INT_MAX, for consistency with
      53       vasprintf().  */
      54    if (totalsize == SIZE_MAX || totalsize > INT_MAX)
      55      {
      56        errno = EOVERFLOW;
      57        return NULL;
      58      }
      59  
      60    /* Allocate and fill the result string.  */
      61    result = XNMALLOC (totalsize + 1, char);
      62    p = result;
      63    for (i = argcount; i > 0; i--)
      64      {
      65        const char *next = va_arg (args, const char *);
      66        size_t len = strlen (next);
      67        memcpy (p, next, len);
      68        p += len;
      69      }
      70    *p = '\0';
      71  
      72    return result;
      73  }
      74  
      75  char *
      76  xvasprintf (const char *format, va_list args)
      77  {
      78    char *result;
      79  
      80    /* Recognize the special case format = "%s...%s".  It is a frequently used
      81       idiom for string concatenation and needs to be fast.  We don't want to
      82       have a separate function xstrcat() for this purpose.  */
      83    {
      84      size_t argcount = 0;
      85      const char *f;
      86  
      87      for (f = format;;)
      88        {
      89          if (*f == '\0')
      90            /* Recognized the special case of string concatenation.  */
      91            return xstrcat (argcount, args);
      92          if (*f != '%')
      93            break;
      94          f++;
      95          if (*f != 's')
      96            break;
      97          f++;
      98          argcount++;
      99        }
     100    }
     101  
     102    if (vasprintf (&result, format, args) < 0)
     103      {
     104        if (errno == ENOMEM)
     105          xalloc_die ();
     106        return NULL;
     107      }
     108  
     109    return result;
     110  }