Blame gl/getdelim.c

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