|
37 | 37 | * the buffer to find a string terminated with a '\n'. It terminates |
38 | 38 | * the string with a 0 and returns it. It updates current to point |
39 | 39 | * to where it left off. On the next read it starts there and tries to |
40 | | - * find a '\n'. If it can't find one, it slides the buffer down and |
41 | | - * fills as much as it can from the descriptor. If the descriptor |
42 | | - * becomes invalid or there is an error reading, it makes eof true. |
43 | | - * The variable eptr marks the end of the buffer. It never changes. |
| 40 | + * find a '\n'. If it can't find one, it advances the buffer pointer |
| 41 | + * and only compacts the unread data when there is no room left for |
| 42 | + * the next read. If the descriptor becomes invalid or there is an |
| 43 | + * error reading, it makes eof true. The variable eptr marks the end |
| 44 | + * of the buffer. It never changes. |
44 | 45 | */ |
45 | 46 |
|
46 | 47 | #define BUF_SIZE 8192 |
@@ -82,10 +83,10 @@ struct auplugin_fgets_state *auplugin_fgets_init(void) |
82 | 83 |
|
83 | 84 | void auplugin_fgets_destroy(struct auplugin_fgets_state *st) |
84 | 85 | { |
85 | | - if (st->buffer != st->internal) { |
| 86 | + if (st->buffer != st->internal || st->orig != st->internal) { |
86 | 87 | switch (st->mem_type) { |
87 | 88 | case MEM_MALLOC: |
88 | | - free(st->buffer); |
| 89 | + free(st->orig); |
89 | 90 | break; |
90 | 91 | case MEM_MMAP: |
91 | 92 | case MEM_MMAP_FILE: |
@@ -115,6 +116,7 @@ void auplugin_fgets_clear_r(struct auplugin_fgets_state *st) |
115 | 116 | st->buffer = st->orig; |
116 | 117 | st->current = st->eptr; |
117 | 118 | } else { |
| 119 | + st->buffer = st->orig; |
118 | 120 | st->buffer[0] = 0; |
119 | 121 | st->current = st->buffer; |
120 | 122 | } |
@@ -155,25 +157,37 @@ int auplugin_fgets_r(struct auplugin_fgets_state *st, char *buf, size_t blen, in |
155 | 157 | line_end = memchr(st->buffer, '\n', avail); |
156 | 158 |
|
157 | 159 | /* 2) If not, and we still can read more, pull in more data */ |
158 | | - if (line_end == NULL && !st->eof && st->current != st->eptr) { |
159 | | - do { |
160 | | - nread = read(fd, st->current, st->eptr - st->current); |
161 | | - } while (nread < 0 && errno == EINTR); |
162 | | - |
163 | | - if (nread < 0) |
164 | | - return -1; |
165 | | - |
166 | | - if (nread == 0) |
167 | | - st->eof = 1; |
168 | | - else { |
169 | | - size_t got = (size_t)nread; |
170 | | - st->current[got] = '\0'; |
171 | | - st->current += got; |
172 | | - avail += got; |
| 160 | + if (line_end == NULL && !st->eof) { |
| 161 | + if (st->current == st->eptr && st->buffer != st->orig) { |
| 162 | + size_t used = (size_t)(st->current - st->buffer); |
| 163 | + |
| 164 | + memmove(st->orig, st->buffer, used); |
| 165 | + st->buffer = st->orig; |
| 166 | + st->current = st->buffer + used; |
| 167 | + avail = used; |
| 168 | + *st->current = '\0'; |
173 | 169 | } |
174 | 170 |
|
175 | | - /* see if a newline arrived in that chunk */ |
176 | | - line_end = memchr(st->buffer, '\n', avail); |
| 171 | + if (st->current != st->eptr) { |
| 172 | + do { |
| 173 | + nread = read(fd, st->current, st->eptr - st->current); |
| 174 | + } while (nread < 0 && errno == EINTR); |
| 175 | + |
| 176 | + if (nread < 0) |
| 177 | + return -1; |
| 178 | + |
| 179 | + if (nread == 0) |
| 180 | + st->eof = 1; |
| 181 | + else { |
| 182 | + size_t got = (size_t)nread; |
| 183 | + st->current[got] = '\0'; |
| 184 | + st->current += got; |
| 185 | + avail += got; |
| 186 | + } |
| 187 | + |
| 188 | + /* see if a newline arrived in that chunk */ |
| 189 | + line_end = memchr(st->buffer, '\n', avail); |
| 190 | + } |
177 | 191 | } |
178 | 192 |
|
179 | 193 | /* 3) Do we now have enough to return? */ |
@@ -203,14 +217,15 @@ int auplugin_fgets_r(struct auplugin_fgets_state *st, char *buf, size_t blen, in |
203 | 217 | buf[line_len] = '\0'; |
204 | 218 |
|
205 | 219 | size_t remainder = avail - line_len; |
206 | | - /* For MEM_MMAP_FILE, can't slide it down, so move buffer beginning */ |
| 220 | + /* For MEM_MMAP_FILE we advance over the returned data permanently. |
| 221 | + * For other modes we defer compaction until there is no write room |
| 222 | + * left for the next read. */ |
207 | 223 | if (st->mem_type == MEM_MMAP_FILE) { |
208 | 224 | st->buffer += line_len; |
209 | 225 | if (st->buffer >= st->eptr) |
210 | 226 | st->eof = 1; |
211 | 227 | } else { |
212 | | - if (remainder > 0) |
213 | | - memmove(st->buffer, st->buffer + line_len, remainder); |
| 228 | + st->buffer += line_len; |
214 | 229 | } |
215 | 230 |
|
216 | 231 | st->current = st->buffer + remainder; |
|
0 commit comments