(root)/
tar-1.35/
gnu/
getdelim.c
       1  /* getdelim.c --- Implementation of replacement getdelim function.
       2     Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2023 Free Software
       3     Foundation, Inc.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     License, or (at your option) any later version.
       9  
      10     This file is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* Ported from glibc by Simon Josefsson. */
      19  
      20  /* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
      21     optimizes away the lineptr == NULL || n == NULL || fp == NULL tests below.  */
      22  #define _GL_ARG_NONNULL(params)
      23  
      24  #include <config.h>
      25  
      26  #include <stdio.h>
      27  
      28  #include <limits.h>
      29  #include <stdint.h>
      30  #include <stdlib.h>
      31  #include <errno.h>
      32  
      33  #if USE_UNLOCKED_IO
      34  # include "unlocked-io.h"
      35  # define getc_maybe_unlocked(fp)        getc(fp)
      36  #elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED
      37  # undef flockfile
      38  # undef funlockfile
      39  # define flockfile(x) ((void) 0)
      40  # define funlockfile(x) ((void) 0)
      41  # define getc_maybe_unlocked(fp)        getc(fp)
      42  #else
      43  # define getc_maybe_unlocked(fp)        getc_unlocked(fp)
      44  #endif
      45  
      46  static void
      47  alloc_failed (void)
      48  {
      49  #if defined _WIN32 && ! defined __CYGWIN__
      50    /* Avoid errno problem without using the realloc module; see:
      51       https://lists.gnu.org/r/bug-gnulib/2016-08/msg00025.html  */
      52    errno = ENOMEM;
      53  #endif
      54  }
      55  
      56  /* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
      57     NUL-terminate it).  *LINEPTR is a pointer returned from malloc (or
      58     NULL), pointing to *N characters of space.  It is realloc'ed as
      59     necessary.  Returns the number of characters read (not including
      60     the null terminator), or -1 on error or EOF.  */
      61  
      62  ssize_t
      63  getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
      64  {
      65    ssize_t result;
      66    size_t cur_len = 0;
      67  
      68    if (lineptr == NULL || n == NULL || fp == NULL)
      69      {
      70        errno = EINVAL;
      71        return -1;
      72      }
      73  
      74    flockfile (fp);
      75  
      76    if (*lineptr == NULL || *n == 0)
      77      {
      78        char *new_lineptr;
      79        *n = 120;
      80        new_lineptr = (char *) realloc (*lineptr, *n);
      81        if (new_lineptr == NULL)
      82          {
      83            alloc_failed ();
      84            result = -1;
      85            goto unlock_return;
      86          }
      87        *lineptr = new_lineptr;
      88      }
      89  
      90    for (;;)
      91      {
      92        int i;
      93  
      94        i = getc_maybe_unlocked (fp);
      95        if (i == EOF)
      96          {
      97            result = -1;
      98            break;
      99          }
     100  
     101        /* Make enough space for len+1 (for final NUL) bytes.  */
     102        if (cur_len + 1 >= *n)
     103          {
     104            size_t needed_max =
     105              SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
     106            size_t needed = 2 * *n + 1;   /* Be generous. */
     107            char *new_lineptr;
     108  
     109            if (needed_max < needed)
     110              needed = needed_max;
     111            if (cur_len + 1 >= needed)
     112              {
     113                result = -1;
     114                errno = EOVERFLOW;
     115                goto unlock_return;
     116              }
     117  
     118            new_lineptr = (char *) realloc (*lineptr, needed);
     119            if (new_lineptr == NULL)
     120              {
     121                alloc_failed ();
     122                result = -1;
     123                goto unlock_return;
     124              }
     125  
     126            *lineptr = new_lineptr;
     127            *n = needed;
     128          }
     129  
     130        (*lineptr)[cur_len] = i;
     131        cur_len++;
     132  
     133        if (i == delimiter)
     134          break;
     135      }
     136    (*lineptr)[cur_len] = '\0';
     137    result = cur_len ? cur_len : result;
     138  
     139   unlock_return:
     140    funlockfile (fp); /* doesn't set errno */
     141  
     142    return result;
     143  }