(root)/
coreutils-9.4/
lib/
linebuffer.c
       1  /* linebuffer.c -- read arbitrarily long lines
       2  
       3     Copyright (C) 1986, 1991, 1998-1999, 2001, 2003-2004, 2006-2007, 2009-2023
       4     Free Software Foundation, Inc.
       5  
       6     This program is free software: you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation, either version 3 of the License, or
       9     (at your option) any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      18  
      19  /* Written by Richard Stallman. */
      20  
      21  #include <config.h>
      22  
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <sys/types.h>
      27  #include "linebuffer.h"
      28  #include "xalloc.h"
      29  
      30  #if USE_UNLOCKED_IO
      31  # include "unlocked-io.h"
      32  #endif
      33  
      34  /* Initialize linebuffer LINEBUFFER for use. */
      35  
      36  void
      37  initbuffer (struct linebuffer *linebuffer)
      38  {
      39    memset (linebuffer, 0, sizeof *linebuffer);
      40  }
      41  
      42  struct linebuffer *
      43  readlinebuffer (struct linebuffer *linebuffer, FILE *stream)
      44  {
      45    return readlinebuffer_delim (linebuffer, stream, '\n');
      46  }
      47  
      48  /* Read an arbitrarily long line of text from STREAM into LINEBUFFER.
      49     Consider lines to be terminated by DELIMITER.
      50     Keep the delimiter; append DELIMITER if it's the last line of a file
      51     that ends in a character other than DELIMITER.  Do not NUL-terminate.
      52     Therefore the stream can contain NUL bytes, and the length
      53     (including the delimiter) is returned in linebuffer->length.
      54     Return NULL when stream is empty.  Return NULL and set errno upon
      55     error; callers can distinguish this case from the empty case by
      56     invoking ferror (stream).
      57     Otherwise, return LINEBUFFER.  */
      58  struct linebuffer *
      59  readlinebuffer_delim (struct linebuffer *linebuffer, FILE *stream,
      60                        char delimiter)
      61  {
      62    int c;
      63    char *buffer = linebuffer->buffer;
      64    char *p = linebuffer->buffer;
      65    char *end = buffer + linebuffer->size; /* Sentinel. */
      66  
      67    if (feof (stream))
      68      return NULL;
      69  
      70    do
      71      {
      72        c = getc (stream);
      73        if (c == EOF)
      74          {
      75            if (p == buffer || ferror (stream))
      76              return NULL;
      77            if (p[-1] == delimiter)
      78              break;
      79            c = delimiter;
      80          }
      81        if (p == end)
      82          {
      83            idx_t oldsize = linebuffer->size;
      84            buffer = xpalloc (buffer, &linebuffer->size, 1, -1, 1);
      85            p = buffer + oldsize;
      86            linebuffer->buffer = buffer;
      87            end = buffer + linebuffer->size;
      88          }
      89        *p++ = c;
      90      }
      91    while (c != delimiter);
      92  
      93    linebuffer->length = p - buffer;
      94    return linebuffer;
      95  }
      96  
      97  /* Free the buffer that was allocated for linebuffer LINEBUFFER.  */
      98  
      99  void
     100  freebuffer (struct linebuffer *linebuffer)
     101  {
     102    free (linebuffer->buffer);
     103  }