root/lib/getdelim.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. alloc_failed
  2. getdelim

     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 }

/* [<][>][^][v][top][bottom][index][help] */