diff options
Diffstat (limited to 'gl/getdelim.c')
| -rw-r--r-- | gl/getdelim.c | 111 |
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) | |||
| 62 | ssize_t | 62 | ssize_t |
| 63 | getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp) | 63 | getdelim (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 */ |
