2 * procio.c -- Replace stdio for read and write on files below
3 * proc to be able to read and write large buffers as well.
5 * Copyright (C) 2017 Werner Fink
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 #include <sys/types.h>
35 typedef struct pcookie {
45 static ssize_t proc_read(void *, char *, size_t);
46 static ssize_t proc_write(void *, const char *, size_t);
47 static int proc_close(void *);
50 static cookie_io_functions_t procio = {
57 FILE *fprocopen(const char *path, const char *mode)
59 pcookie_t *cookie = NULL;
65 if (!mode || !(len = strlen(mode))) {
70 /* No append mode possible */
76 flags |= O_WRONLY|O_TRUNC;
83 delim = ','; /* default delimeter is the colon */
84 for (c = 1; c < len; c++) {
100 if (mode[c] == ' ' || (mode[c] >= ',' && mode[c] <= '.') || mode[c] == ':')
111 cookie = (pcookie_t *)malloc(sizeof(pcookie_t));
114 cookie->count = BUFSIZ;
115 cookie->buf = (char *)malloc(cookie->count);
125 cookie->delim = delim;
127 cookie->fd = openat(AT_FDCWD, path, flags);
128 if (cookie->fd < 0) {
136 handle = fopencookie(cookie, mode, procio);
150 ssize_t proc_read(void *c, char *buf, size_t count)
152 pcookie_t *cookie = c;
156 if (cookie->count < count) {
157 ptr = realloc(cookie->buf, count);
161 cookie->count = count;
164 while (!cookie->final) {
165 len = read(cookie->fd, cookie->buf, cookie->count);
171 cookie->buf[cookie->length] = '\0';
174 goto out; /* error or done */
177 cookie->length = len;
179 if (cookie->length < cookie->count)
182 /* Likly to small buffer here */
184 lseek(cookie->fd, 0, SEEK_SET); /* reset for a retry */
186 ptr = realloc(cookie->buf, cookie->count += BUFSIZ);
193 if (cookie->length - cookie->offset < len)
194 len = cookie->length - cookie->offset;
200 (void)memcpy(buf, cookie->buf+cookie->offset, len);
201 cookie->offset += len;
211 ssize_t proc_write(void *c, const char *buf, size_t count)
213 pcookie_t *cookie = c;
222 /* NL is the final input */
223 cookie->final = memrchr(buf, '\n', count) ? 1 : 0;
225 while (cookie->count < cookie->offset + count) {
226 ptr = realloc(cookie->buf, cookie->count += count);
233 (void)memcpy(cookie->buf+cookie->offset, buf, count);
234 cookie->offset += count;
237 len = write(cookie->fd, cookie->buf, cookie->offset);
238 if (len < 0 && errno == EINVAL) {
243 * Oops buffer might be to large, split buffer into
244 * pieces at delimeter if provided
247 goto out; /* Hey dude?! */
251 if (cookie->offset > LINELEN)
252 token = (char*)memrchr(cookie->buf+offset, cookie->delim, LINELEN);
254 token = (char*)memrchr(cookie->buf+offset, '\n', cookie->offset);
260 goto out; /* Wrong/Missing delimeter? */
263 lseek(cookie->fd, 1, SEEK_CUR);
265 amount = token-(cookie->buf+offset)+1;
266 ptr = cookie->buf+offset;
268 len = write(cookie->fd, ptr, amount);
269 if (len < 1 || len >= cookie->offset)
273 cookie->offset -= len;
275 } while (cookie->offset > 0);
285 int proc_close(void *c)
287 pcookie_t *cookie = c;