Blame src/gl/getdelim.c

Packit aea12f
/* getdelim.c --- Implementation of replacement getdelim function.
Packit Service 991b93
   Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2020 Free Software
Packit aea12f
   Foundation, Inc.
Packit aea12f
Packit aea12f
   This program is free software; you can redistribute it and/or
Packit aea12f
   modify it under the terms of the GNU General Public License as
Packit aea12f
   published by the Free Software Foundation; either version 3, or (at
Packit aea12f
   your option) any later version.
Packit aea12f
Packit aea12f
   This program is distributed in the hope that it will be useful, but
Packit aea12f
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit aea12f
   General Public License for more details.
Packit aea12f
Packit aea12f
   You should have received a copy of the GNU General Public License
Packit aea12f
   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit aea12f
Packit aea12f
/* Ported from glibc by Simon Josefsson. */
Packit aea12f
Packit aea12f
/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
Packit aea12f
   optimizes away the lineptr == NULL || n == NULL || fp == NULL tests below.  */
Packit aea12f
#define _GL_ARG_NONNULL(params)
Packit aea12f
Packit aea12f
#include <config.h>
Packit aea12f
Packit aea12f
#include <stdio.h>
Packit aea12f
Packit aea12f
#include <limits.h>
Packit aea12f
#include <stdint.h>
Packit aea12f
#include <stdlib.h>
Packit aea12f
#include <errno.h>
Packit aea12f
Packit aea12f
#ifndef SSIZE_MAX
Packit aea12f
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#if USE_UNLOCKED_IO
Packit aea12f
# include "unlocked-io.h"
Packit aea12f
# define getc_maybe_unlocked(fp)        getc(fp)
Packit aea12f
#elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED
Packit aea12f
# undef flockfile
Packit aea12f
# undef funlockfile
Packit aea12f
# define flockfile(x) ((void) 0)
Packit aea12f
# define funlockfile(x) ((void) 0)
Packit aea12f
# define getc_maybe_unlocked(fp)        getc(fp)
Packit aea12f
#else
Packit aea12f
# define getc_maybe_unlocked(fp)        getc_unlocked(fp)
Packit aea12f
#endif
Packit aea12f
Packit aea12f
static void
Packit aea12f
alloc_failed (void)
Packit aea12f
{
Packit aea12f
#if defined _WIN32 && ! defined __CYGWIN__
Packit aea12f
  /* Avoid errno problem without using the realloc module; see:
Packit aea12f
     https://lists.gnu.org/r/bug-gnulib/2016-08/msg00025.html  */
Packit aea12f
  errno = ENOMEM;
Packit aea12f
#endif
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
Packit aea12f
   NUL-terminate it).  *LINEPTR is a pointer returned from malloc (or
Packit aea12f
   NULL), pointing to *N characters of space.  It is realloc'ed as
Packit aea12f
   necessary.  Returns the number of characters read (not including
Packit aea12f
   the null terminator), or -1 on error or EOF.  */
Packit aea12f
Packit aea12f
ssize_t
Packit aea12f
getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
Packit aea12f
{
Packit aea12f
  ssize_t result;
Packit aea12f
  size_t cur_len = 0;
Packit aea12f
Packit aea12f
  if (lineptr == NULL || n == NULL || fp == NULL)
Packit aea12f
    {
Packit aea12f
      errno = EINVAL;
Packit aea12f
      return -1;
Packit aea12f
    }
Packit aea12f
Packit aea12f
  flockfile (fp);
Packit aea12f
Packit aea12f
  if (*lineptr == NULL || *n == 0)
Packit aea12f
    {
Packit aea12f
      char *new_lineptr;
Packit aea12f
      *n = 120;
Packit aea12f
      new_lineptr = (char *) realloc (*lineptr, *n);
Packit aea12f
      if (new_lineptr == NULL)
Packit aea12f
        {
Packit aea12f
          alloc_failed ();
Packit aea12f
          result = -1;
Packit aea12f
          goto unlock_return;
Packit aea12f
        }
Packit aea12f
      *lineptr = new_lineptr;
Packit aea12f
    }
Packit aea12f
Packit aea12f
  for (;;)
Packit aea12f
    {
Packit aea12f
      int i;
Packit aea12f
Packit aea12f
      i = getc_maybe_unlocked (fp);
Packit aea12f
      if (i == EOF)
Packit aea12f
        {
Packit aea12f
          result = -1;
Packit aea12f
          break;
Packit aea12f
        }
Packit aea12f
Packit aea12f
      /* Make enough space for len+1 (for final NUL) bytes.  */
Packit aea12f
      if (cur_len + 1 >= *n)
Packit aea12f
        {
Packit aea12f
          size_t needed_max =
Packit aea12f
            SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
Packit aea12f
          size_t needed = 2 * *n + 1;   /* Be generous. */
Packit aea12f
          char *new_lineptr;
Packit aea12f
Packit aea12f
          if (needed_max < needed)
Packit aea12f
            needed = needed_max;
Packit aea12f
          if (cur_len + 1 >= needed)
Packit aea12f
            {
Packit aea12f
              result = -1;
Packit aea12f
              errno = EOVERFLOW;
Packit aea12f
              goto unlock_return;
Packit aea12f
            }
Packit aea12f
Packit aea12f
          new_lineptr = (char *) realloc (*lineptr, needed);
Packit aea12f
          if (new_lineptr == NULL)
Packit aea12f
            {
Packit aea12f
              alloc_failed ();
Packit aea12f
              result = -1;
Packit aea12f
              goto unlock_return;
Packit aea12f
            }
Packit aea12f
Packit aea12f
          *lineptr = new_lineptr;
Packit aea12f
          *n = needed;
Packit aea12f
        }
Packit aea12f
Packit aea12f
      (*lineptr)[cur_len] = i;
Packit aea12f
      cur_len++;
Packit aea12f
Packit aea12f
      if (i == delimiter)
Packit aea12f
        break;
Packit aea12f
    }
Packit aea12f
  (*lineptr)[cur_len] = '\0';
Packit aea12f
  result = cur_len ? cur_len : result;
Packit aea12f
Packit aea12f
 unlock_return:
Packit aea12f
  funlockfile (fp); /* doesn't set errno */
Packit aea12f
Packit aea12f
  return result;
Packit aea12f
}