Blame lib/xvasprintf.c

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