105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* getdelim.c --- Implementation of replacement getdelim function.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2012 Free Software
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Foundation, Inc.
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software; you can redistribute it and/or
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   modify it under the terms of the GNU General Public License as
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   published by the Free Software Foundation; either version 3, or (at
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   your option) any later version.
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful, but
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   WITHOUT ANY WARRANTY; without even the implied warranty of
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   General Public License for more details.
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Ported from glibc by Simon Josefsson. */
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   optimizes away the lineptr == NULL || n == NULL || fp == NULL tests below.  */
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define _GL_ARG_NONNULL(params)
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdio.h>
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <limits.h>
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdint.h>
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdlib.h>
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <errno.h>
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef SSIZE_MAX
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if USE_UNLOCKED_IO
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include "unlocked-io.h"
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define getc_maybe_unlocked(fp)        getc(fp)
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# undef flockfile
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# undef funlockfile
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define flockfile(x) ((void) 0)
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define funlockfile(x) ((void) 0)
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define getc_maybe_unlocked(fp)        getc(fp)
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define getc_maybe_unlocked(fp)        getc_unlocked(fp)
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   NUL-terminate it).  *LINEPTR is a pointer returned from malloc (or
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   NULL), pointing to *N characters of space.  It is realloc'ed as
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   necessary.  Returns the number of characters read (not including
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the null terminator), or -1 on error or EOF.  */
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wangssize_t
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wanggetdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  ssize_t result;
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t cur_len = 0;
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (lineptr == NULL || n == NULL || fp == NULL)
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      errno = EINVAL;
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return -1;
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  flockfile (fp);
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (*lineptr == NULL || *n == 0)
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      char *new_lineptr;
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      *n = 120;
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      new_lineptr = (char *) realloc (*lineptr, *n);
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (new_lineptr == NULL)
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = -1;
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          goto unlock_return;
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      *lineptr = new_lineptr;
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  for (;;)
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int i;
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      i = getc_maybe_unlocked (fp);
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (i == EOF)
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = -1;
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          break;
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Make enough space for len+1 (for final NUL) bytes.  */
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (cur_len + 1 >= *n)
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          size_t needed_max =
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          size_t needed = 2 * *n + 1;   /* Be generous. */
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          char *new_lineptr;
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (needed_max < needed)
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            needed = needed_max;
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (cur_len + 1 >= needed)
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              result = -1;
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              errno = EOVERFLOW;
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              goto unlock_return;
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          new_lineptr = (char *) realloc (*lineptr, needed);
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (new_lineptr == NULL)
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              result = -1;
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              goto unlock_return;
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          *lineptr = new_lineptr;
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          *n = needed;
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      (*lineptr)[cur_len] = i;
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      cur_len++;
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (i == delimiter)
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        break;
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  (*lineptr)[cur_len] = '\0';
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  result = cur_len ? cur_len : result;
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang unlock_return:
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  funlockfile (fp); /* doesn't set errno */
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return result;
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
136