xref: /netbsd-src/external/gpl2/xcvs/dist/lib/getdelim.c (revision 5a6c14c844c4c665da5632061aebde7bb2cb5766)
1a7c91847Schristos /* getdelim.c --- Implementation of replacement getdelim function.
2a7c91847Schristos    Copyright (C) 1994, 1996, 1997, 1998, 2001, 2003, 2005 Free
3a7c91847Schristos    Software Foundation, Inc.
4a7c91847Schristos 
5a7c91847Schristos    This program is free software; you can redistribute it and/or
6a7c91847Schristos    modify it under the terms of the GNU General Public License as
7a7c91847Schristos    published by the Free Software Foundation; either version 2, or (at
8a7c91847Schristos    your option) any later version.
9a7c91847Schristos 
10a7c91847Schristos    This program is distributed in the hope that it will be useful, but
11a7c91847Schristos    WITHOUT ANY WARRANTY; without even the implied warranty of
12a7c91847Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13a7c91847Schristos    General Public License for more details.
14a7c91847Schristos 
15a7c91847Schristos    You should have received a copy of the GNU General Public License
16a7c91847Schristos    along with this program; if not, write to the Free Software
17a7c91847Schristos    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18a7c91847Schristos    02110-1301, USA.  */
19*5a6c14c8Schristos #include <sys/cdefs.h>
20*5a6c14c8Schristos __RCSID("$NetBSD: getdelim.c,v 1.2 2016/05/17 14:00:09 christos Exp $");
21*5a6c14c8Schristos 
22a7c91847Schristos 
23a7c91847Schristos /* Ported from glibc by Simon Josefsson. */
24a7c91847Schristos 
25a7c91847Schristos #ifdef HAVE_CONFIG_H
26a7c91847Schristos # include <config.h>
27a7c91847Schristos #endif
28a7c91847Schristos 
29a7c91847Schristos #include <stdlib.h>
30a7c91847Schristos #include <errno.h>
31a7c91847Schristos 
32a7c91847Schristos #include "getdelim.h"
33a7c91847Schristos 
34a7c91847Schristos #if !HAVE_FLOCKFILE
35a7c91847Schristos # undef flockfile
36a7c91847Schristos # define flockfile(x) ((void) 0)
37a7c91847Schristos #endif
38a7c91847Schristos #if !HAVE_FUNLOCKFILE
39a7c91847Schristos # undef funlockfile
40a7c91847Schristos # define funlockfile(x) ((void) 0)
41a7c91847Schristos #endif
42a7c91847Schristos 
43a7c91847Schristos /* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
44a7c91847Schristos    NUL-terminate it).  *LINEPTR is a pointer returned from malloc (or
45a7c91847Schristos    NULL), pointing to *N characters of space.  It is realloc'ed as
46a7c91847Schristos    necessary.  Returns the number of characters read (not including
47a7c91847Schristos    the null terminator), or -1 on error or EOF.  */
48a7c91847Schristos 
49a7c91847Schristos ssize_t
getdelim(char ** lineptr,size_t * n,int delimiter,FILE * fp)50a7c91847Schristos getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
51a7c91847Schristos {
52a7c91847Schristos   int result = 0;
53a7c91847Schristos   ssize_t cur_len = 0;
54a7c91847Schristos   ssize_t len;
55a7c91847Schristos 
56a7c91847Schristos   if (lineptr == NULL || n == NULL || fp == NULL)
57a7c91847Schristos     {
58a7c91847Schristos       errno = EINVAL;
59a7c91847Schristos       return -1;
60a7c91847Schristos     }
61a7c91847Schristos 
62a7c91847Schristos   flockfile (fp);
63a7c91847Schristos 
64a7c91847Schristos   if (*lineptr == NULL || *n == 0)
65a7c91847Schristos     {
66a7c91847Schristos       *n = 120;
67a7c91847Schristos       *lineptr = (char *) malloc (*n);
68a7c91847Schristos       if (*lineptr == NULL)
69a7c91847Schristos 	{
70a7c91847Schristos 	  result = -1;
71a7c91847Schristos 	  goto unlock_return;
72a7c91847Schristos 	}
73a7c91847Schristos     }
74a7c91847Schristos 
75a7c91847Schristos   for (;;)
76a7c91847Schristos     {
77a7c91847Schristos       char *t;
78a7c91847Schristos       int i;
79a7c91847Schristos 
80a7c91847Schristos       i = getc (fp);
81a7c91847Schristos       if (i == EOF)
82a7c91847Schristos       {
83a7c91847Schristos 	result = -1;
84a7c91847Schristos 	break;
85a7c91847Schristos       }
86a7c91847Schristos 
87a7c91847Schristos       /* Make enough space for len+1 (for final NUL) bytes.  */
88a7c91847Schristos       if (cur_len + 1 >= *n)
89a7c91847Schristos 	{
90a7c91847Schristos 	  size_t needed = 2 * (cur_len + 1) + 1;   /* Be generous. */
91a7c91847Schristos 	  char *new_lineptr;
92a7c91847Schristos 
93a7c91847Schristos 	  if (needed < cur_len)
94a7c91847Schristos 	    {
95a7c91847Schristos 	      result = -1;
96a7c91847Schristos 	      goto unlock_return;
97a7c91847Schristos 	    }
98a7c91847Schristos 
99a7c91847Schristos 	  new_lineptr = (char *) realloc (*lineptr, needed);
100a7c91847Schristos 	  if (new_lineptr == NULL)
101a7c91847Schristos 	    {
102a7c91847Schristos 	      result = -1;
103a7c91847Schristos 	      goto unlock_return;
104a7c91847Schristos 	    }
105a7c91847Schristos 
106a7c91847Schristos 	  *lineptr = new_lineptr;
107a7c91847Schristos 	  *n = needed;
108a7c91847Schristos 	}
109a7c91847Schristos 
110a7c91847Schristos       (*lineptr)[cur_len] = i;
111a7c91847Schristos       cur_len++;
112a7c91847Schristos 
113a7c91847Schristos       if (i == delimiter)
114a7c91847Schristos 	break;
115a7c91847Schristos     }
116a7c91847Schristos   (*lineptr)[cur_len] = '\0';
117a7c91847Schristos   result = cur_len ? cur_len : result;
118a7c91847Schristos 
119a7c91847Schristos  unlock_return:
120a7c91847Schristos   funlockfile (fp);
121a7c91847Schristos   return result;
122a7c91847Schristos }
123