summaryrefslogtreecommitdiffstats
path: root/gl/getdelim.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/getdelim.c')
-rw-r--r--gl/getdelim.c111
1 files changed, 59 insertions, 52 deletions
diff --git a/gl/getdelim.c b/gl/getdelim.c
index 2576d376..21f3abc2 100644
--- a/gl/getdelim.c
+++ b/gl/getdelim.c
@@ -1,5 +1,5 @@
1/* getdelim.c --- Implementation of replacement getdelim function. 1/* getdelim.c --- Implementation of replacement getdelim function.
2 Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2025 Free Software 2 Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2026 Free Software
3 Foundation, Inc. 3 Foundation, Inc.
4 4
5 This file is free software: you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
@@ -62,10 +62,13 @@ alloc_failed (void)
62ssize_t 62ssize_t
63getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp) 63getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
64{ 64{
65 ssize_t result; 65 if (lineptr == NULL || n == NULL
66 size_t cur_len = 0; 66 /* glibc already declares this function as __nonnull ((4)).
67 67 Avoid a gcc warning "‘nonnull’ argument ‘fp’ compared to NULL". */
68 if (lineptr == NULL || n == NULL || fp == NULL) 68#if !(__GLIBC__ >= 2)
69 || fp == NULL
70#endif
71 )
69 { 72 {
70 errno = EINVAL; 73 errno = EINVAL;
71 return -1; 74 return -1;
@@ -73,6 +76,8 @@ getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
73 76
74 flockfile (fp); 77 flockfile (fp);
75 78
79 ssize_t result;
80
76 if (*lineptr == NULL || *n == 0) 81 if (*lineptr == NULL || *n == 0)
77 { 82 {
78 char *new_lineptr; 83 char *new_lineptr;
@@ -87,54 +92,56 @@ getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
87 *lineptr = new_lineptr; 92 *lineptr = new_lineptr;
88 } 93 }
89 94
90 for (;;) 95 {
91 { 96 size_t cur_len = 0;
92 int i; 97 for (;;)
93 98 {
94 i = getc_maybe_unlocked (fp); 99 int i;
95 if (i == EOF) 100
96 { 101 i = getc_maybe_unlocked (fp);
97 result = -1; 102 if (i == EOF)
103 {
104 result = -1;
105 break;
106 }
107
108 /* Make enough space for len+1 (for final NUL) bytes. */
109 if (cur_len + 1 >= *n)
110 {
111 size_t needed_max =
112 SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
113 size_t needed = 2 * *n + 1; /* Be generous. */
114
115 if (needed_max < needed)
116 needed = needed_max;
117 if (cur_len + 1 >= needed)
118 {
119 result = -1;
120 errno = EOVERFLOW;
121 goto unlock_return;
122 }
123
124 char *new_lineptr = (char *) realloc (*lineptr, needed);
125 if (new_lineptr == NULL)
126 {
127 alloc_failed ();
128 result = -1;
129 goto unlock_return;
130 }
131
132 *lineptr = new_lineptr;
133 *n = needed;
134 }
135
136 (*lineptr)[cur_len] = i;
137 cur_len++;
138
139 if (i == delimiter)
98 break; 140 break;
99 } 141 }
100 142 (*lineptr)[cur_len] = '\0';
101 /* Make enough space for len+1 (for final NUL) bytes. */ 143 result = cur_len ? cur_len : result;
102 if (cur_len + 1 >= *n) 144 }
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 145
139 unlock_return: 146 unlock_return:
140 funlockfile (fp); /* doesn't set errno */ 147 funlockfile (fp); /* doesn't set errno */