Blame lib/xvasprintf.c

Packit Service fdd496
/* vasprintf and asprintf with out-of-memory checking.
Packit Service fdd496
   Copyright (C) 1999, 2002-2004, 2006-2017 Free Software Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   This program is free software: you can redistribute it and/or modify
Packit Service fdd496
   it under the terms of the GNU General Public License as published by
Packit Service fdd496
   the Free Software Foundation; either version 3 of the License, or
Packit Service fdd496
   (at your option) any later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License
Packit Service fdd496
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
#include <config.h>
Packit Service fdd496
Packit Service fdd496
/* Specification.  */
Packit Service fdd496
#include "xvasprintf.h"
Packit Service fdd496
Packit Service fdd496
#include <errno.h>
Packit Service fdd496
#include <limits.h>
Packit Service fdd496
#include <string.h>
Packit Service fdd496
#include <stdio.h>
Packit Service fdd496
Packit Service fdd496
#include "xalloc.h"
Packit Service fdd496
Packit Service fdd496
/* Checked size_t computations.  */
Packit Service fdd496
#include "xsize.h"
Packit Service fdd496
Packit Service fdd496
static char *
Packit Service fdd496
xstrcat (size_t argcount, va_list args)
Packit Service fdd496
{
Packit Service fdd496
  char *result;
Packit Service fdd496
  va_list ap;
Packit Service fdd496
  size_t totalsize;
Packit Service fdd496
  size_t i;
Packit Service fdd496
  char *p;
Packit Service fdd496
Packit Service fdd496
  /* Determine the total size.  */
Packit Service fdd496
  totalsize = 0;
Packit Service fdd496
  va_copy (ap, args);
Packit Service fdd496
  for (i = argcount; i > 0; i--)
Packit Service fdd496
    {
Packit Service fdd496
      const char *next = va_arg (ap, const char *);
Packit Service fdd496
      totalsize = xsum (totalsize, strlen (next));
Packit Service fdd496
    }
Packit Service fdd496
  va_end (ap);
Packit Service fdd496
Packit Service fdd496
  /* Test for overflow in the summing pass above or in (totalsize + 1) below.
Packit Service fdd496
     Also, don't return a string longer than INT_MAX, for consistency with
Packit Service fdd496
     vasprintf().  */
Packit Service fdd496
  if (totalsize == SIZE_MAX || totalsize > INT_MAX)
Packit Service fdd496
    {
Packit Service fdd496
      errno = EOVERFLOW;
Packit Service fdd496
      return NULL;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* Allocate and fill the result string.  */
Packit Service fdd496
  result = XNMALLOC (totalsize + 1, char);
Packit Service fdd496
  p = result;
Packit Service fdd496
  for (i = argcount; i > 0; i--)
Packit Service fdd496
    {
Packit Service fdd496
      const char *next = va_arg (args, const char *);
Packit Service fdd496
      size_t len = strlen (next);
Packit Service fdd496
      memcpy (p, next, len);
Packit Service fdd496
      p += len;
Packit Service fdd496
    }
Packit Service fdd496
  *p = '\0';
Packit Service fdd496
Packit Service fdd496
  return result;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
char *
Packit Service fdd496
xvasprintf (const char *format, va_list args)
Packit Service fdd496
{
Packit Service fdd496
  char *result;
Packit Service fdd496
Packit Service fdd496
  /* Recognize the special case format = "%s...%s".  It is a frequently used
Packit Service fdd496
     idiom for string concatenation and needs to be fast.  We don't want to
Packit Service fdd496
     have a separate function xstrcat() for this purpose.  */
Packit Service fdd496
  {
Packit Service fdd496
    size_t argcount = 0;
Packit Service fdd496
    const char *f;
Packit Service fdd496
Packit Service fdd496
    for (f = format;;)
Packit Service fdd496
      {
Packit Service fdd496
        if (*f == '\0')
Packit Service fdd496
          /* Recognized the special case of string concatenation.  */
Packit Service fdd496
          return xstrcat (argcount, args);
Packit Service fdd496
        if (*f != '%')
Packit Service fdd496
          break;
Packit Service fdd496
        f++;
Packit Service fdd496
        if (*f != 's')
Packit Service fdd496
          break;
Packit Service fdd496
        f++;
Packit Service fdd496
        argcount++;
Packit Service fdd496
      }
Packit Service fdd496
  }
Packit Service fdd496
Packit Service fdd496
  if (vasprintf (&result, format, args) < 0)
Packit Service fdd496
    {
Packit Service fdd496
      if (errno == ENOMEM)
Packit Service fdd496
        xalloc_die ();
Packit Service fdd496
      return NULL;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return result;
Packit Service fdd496
}