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