summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 609028f)
raw | patch | inline | side by side (parent: 609028f)
author | Jonas Fonseca <fonseca@diku.dk> | |
Mon, 22 Mar 2010 02:16:58 +0000 (22:16 -0400) | ||
committer | Jonas Fonseca <fonseca@diku.dk> | |
Mon, 7 Mar 2011 01:18:15 +0000 (20:18 -0500) |
Makefile | patch | blob | history | |
io.c | [new file with mode: 0644] | patch | blob |
io.h | [new file with mode: 0644] | patch | blob |
tig.c | patch | blob | history |
diff --git a/Makefile b/Makefile
index e9670fb376449af9ed85ca1886bafaca4932efda..78131f515223e224935d942ab638886c5654ee54 100644 (file)
--- a/Makefile
+++ b/Makefile
CFLAGS ?= -Wall -O2
DFLAGS = -g -DDEBUG -Werror -O0
PROGS = tig
-SOURCE = tig.c tig.h
+SOURCE = tig.c tig.h io.c io.h
TXTDOC = tig.1.txt tigrc.5.txt manual.txt NEWS README INSTALL BUGS TODO
MANDOC = tig.1 tigrc.5 tigmanual.7
HTMLDOC = tig.1.html tigrc.5.html manual.html README.html NEWS.html
.PHONY: all all-debug doc doc-man doc-html install install-doc \
install-doc-man install-doc-html clean spell-check dist rpm
-tig.o: tig.c tig.h
-tig: tig.o
+io.o: io.c io.h tig.h
+tig.o: tig.c tig.h io.h
+tig: tig.o io.o
tig.spec: contrib/tig.spec.in
sed -e 's/@@VERSION@@/$(RPM_VERSION)/g' \
diff --git a/io.c b/io.c
--- /dev/null
+++ b/io.c
@@ -0,0 +1,441 @@
+/* Copyright (c) 2006-2010 Jonas Fonseca <fonseca@diku.dk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "tig.h"
+#include "io.h"
+
+bool
+argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
+{
+ int valuelen;
+
+ while (*cmd && *argc < SIZEOF_ARG && (valuelen = strcspn(cmd, " \t"))) {
+ bool advance = cmd[valuelen] != 0;
+
+ cmd[valuelen] = 0;
+ argv[(*argc)++] = chomp_string(cmd);
+ cmd = chomp_string(cmd + valuelen + advance);
+ }
+
+ if (*argc < SIZEOF_ARG)
+ argv[*argc] = NULL;
+ return *argc < SIZEOF_ARG;
+}
+
+bool
+argv_from_env(const char **argv, const char *name)
+{
+ char *env = argv ? getenv(name) : NULL;
+ int argc = 0;
+
+ if (env && *env)
+ env = strdup(env);
+ return !env || argv_from_string(argv, &argc, env);
+}
+
+void
+argv_free(const char *argv[])
+{
+ int argc;
+
+ if (!argv)
+ return;
+ for (argc = 0; argv[argc]; argc++)
+ free((void *) argv[argc]);
+ argv[0] = NULL;
+}
+
+size_t
+argv_size(const char **argv)
+{
+ int argc = 0;
+
+ while (argv && argv[argc])
+ argc++;
+
+ return argc;
+}
+
+DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
+
+bool
+argv_append(const char ***argv, const char *arg)
+{
+ size_t argc = argv_size(*argv);
+
+ if (!argv_realloc(argv, argc, 2))
+ return FALSE;
+
+ (*argv)[argc++] = strdup(arg);
+ (*argv)[argc] = NULL;
+ return TRUE;
+}
+
+bool
+argv_append_array(const char ***dst_argv, const char *src_argv[])
+{
+ int i;
+
+ for (i = 0; src_argv && src_argv[i]; i++)
+ if (!argv_append(dst_argv, src_argv[i]))
+ return FALSE;
+ return TRUE;
+}
+
+bool
+argv_copy(const char ***dst, const char *src[])
+{
+ int argc;
+
+ for (argc = 0; src[argc]; argc++)
+ if (!argv_append(dst, src[argc]))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+ * Executing external commands.
+ */
+
+static void
+io_init(struct io *io)
+{
+ memset(io, 0, sizeof(*io));
+ io->pipe = -1;
+}
+
+bool
+io_open(struct io *io, const char *fmt, ...)
+{
+ char name[SIZEOF_STR] = "";
+ bool fits;
+ va_list args;
+
+ io_init(io);
+
+ va_start(args, fmt);
+ fits = vsnprintf(name, sizeof(name), fmt, args) < sizeof(name);
+ va_end(args);
+
+ if (!fits) {
+ io->error = ENAMETOOLONG;
+ return FALSE;
+ }
+ io->pipe = *name ? open(name, O_RDONLY) : STDIN_FILENO;
+ if (io->pipe == -1)
+ io->error = errno;
+ return io->pipe != -1;
+}
+
+bool
+io_kill(struct io *io)
+{
+ return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
+}
+
+bool
+io_done(struct io *io)
+{
+ pid_t pid = io->pid;
+
+ if (io->pipe != -1)
+ close(io->pipe);
+ free(io->buf);
+ io_init(io);
+
+ while (pid > 0) {
+ int status;
+ pid_t waiting = waitpid(pid, &status, 0);
+
+ if (waiting < 0) {
+ if (errno == EINTR)
+ continue;
+ io->error = errno;
+ return FALSE;
+ }
+
+ return waiting == pid &&
+ !WIFSIGNALED(status) &&
+ WIFEXITED(status) &&
+ !WEXITSTATUS(status);
+ }
+
+ return TRUE;
+}
+
+bool
+io_run(struct io *io, enum io_type type, const char *dir, const char *argv[], ...)
+{
+ int pipefds[2] = { -1, -1 };
+ va_list args;
+
+ io_init(io);
+
+ if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
+ io->error = errno;
+ return FALSE;
+ } else if (type == IO_AP) {
+ va_start(args, argv);
+ pipefds[1] = va_arg(args, int);
+ va_end(args);
+ }
+
+ if ((io->pid = fork())) {
+ if (io->pid == -1)
+ io->error = errno;
+ if (pipefds[!(type == IO_WR)] != -1)
+ close(pipefds[!(type == IO_WR)]);
+ if (io->pid != -1) {
+ io->pipe = pipefds[!!(type == IO_WR)];
+ return TRUE;
+ }
+
+ } else {
+ if (type != IO_FG) {
+ int devnull = open("/dev/null", O_RDWR);
+ int readfd = type == IO_WR ? pipefds[0] : devnull;
+ int writefd = (type == IO_RD || type == IO_AP)
+ ? pipefds[1] : devnull;
+
+ dup2(readfd, STDIN_FILENO);
+ dup2(writefd, STDOUT_FILENO);
+ dup2(devnull, STDERR_FILENO);
+
+ close(devnull);
+ if (pipefds[0] != -1)
+ close(pipefds[0]);
+ if (pipefds[1] != -1)
+ close(pipefds[1]);
+ }
+
+ if (dir && *dir && chdir(dir) == -1)
+ exit(errno);
+
+ execvp(argv[0], (char *const*) argv);
+ exit(errno);
+ }
+
+ if (pipefds[!!(type == IO_WR)] != -1)
+ close(pipefds[!!(type == IO_WR)]);
+ return FALSE;
+}
+
+bool
+io_complete(enum io_type type, const char **argv, const char *dir, int fd)
+{
+ struct io io;
+
+ return io_run(&io, type, dir, argv, fd) && io_done(&io);
+}
+
+bool
+io_run_bg(const char **argv)
+{
+ return io_complete(IO_BG, argv, NULL, -1);
+}
+
+bool
+io_run_fg(const char **argv, const char *dir)
+{
+ return io_complete(IO_FG, argv, dir, -1);
+}
+
+bool
+io_run_append(const char **argv, int fd)
+{
+ return io_complete(IO_AP, argv, NULL, fd);
+}
+
+bool
+io_eof(struct io *io)
+{
+ return io->eof;
+}
+
+int
+io_error(struct io *io)
+{
+ return io->error;
+}
+
+char *
+io_strerror(struct io *io)
+{
+ return strerror(io->error);
+}
+
+bool
+io_can_read(struct io *io)
+{
+ struct timeval tv = { 0, 500 };
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(io->pipe, &fds);
+
+ return select(io->pipe + 1, &fds, NULL, NULL, &tv) > 0;
+}
+
+ssize_t
+io_read(struct io *io, void *buf, size_t bufsize)
+{
+ do {
+ ssize_t readsize = read(io->pipe, buf, bufsize);
+
+ if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
+ continue;
+ else if (readsize == -1)
+ io->error = errno;
+ else if (readsize == 0)
+ io->eof = 1;
+ return readsize;
+ } while (1);
+}
+
+DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
+
+char *
+io_get(struct io *io, int c, bool can_read)
+{
+ char *eol;
+ ssize_t readsize;
+
+ while (TRUE) {
+ if (io->bufsize > 0) {
+ eol = memchr(io->bufpos, c, io->bufsize);
+ if (eol) {
+ char *line = io->bufpos;
+
+ *eol = 0;
+ io->bufpos = eol + 1;
+ io->bufsize -= io->bufpos - line;
+ return line;
+ }
+ }
+
+ if (io_eof(io)) {
+ if (io->bufsize) {
+ io->bufpos[io->bufsize] = 0;
+ io->bufsize = 0;
+ return io->bufpos;
+ }
+ return NULL;
+ }
+
+ if (!can_read)
+ return NULL;
+
+ if (io->bufsize > 0 && io->bufpos > io->buf)
+ memmove(io->buf, io->bufpos, io->bufsize);
+
+ if (io->bufalloc == io->bufsize) {
+ if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
+ return NULL;
+ io->bufalloc += BUFSIZ;
+ }
+
+ io->bufpos = io->buf;
+ readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
+ if (io_error(io))
+ return NULL;
+ io->bufsize += readsize;
+ }
+}
+
+bool
+io_write(struct io *io, const void *buf, size_t bufsize)
+{
+ size_t written = 0;
+
+ while (!io_error(io) && written < bufsize) {
+ ssize_t size;
+
+ size = write(io->pipe, buf + written, bufsize - written);
+ if (size < 0 && (errno == EAGAIN || errno == EINTR))
+ continue;
+ else if (size == -1)
+ io->error = errno;
+ else
+ written += size;
+ }
+
+ return written == bufsize;
+}
+
+bool
+io_read_buf(struct io *io, char buf[], size_t bufsize)
+{
+ char *result = io_get(io, '\n', TRUE);
+
+ if (result) {
+ result = chomp_string(result);
+ string_ncopy_do(buf, bufsize, result, strlen(result));
+ }
+
+ return io_done(io) && result;
+}
+
+bool
+io_run_buf(const char **argv, char buf[], size_t bufsize)
+{
+ struct io io;
+
+ return io_run(&io, IO_RD, NULL, argv) && io_read_buf(&io, buf, bufsize);
+}
+
+int
+io_load(struct io *io, const char *separators,
+ io_read_fn read_property, void *data)
+{
+ char *name;
+ int state = OK;
+
+ while (state == OK && (name = io_get(io, '\n', TRUE))) {
+ char *value;
+ size_t namelen;
+ size_t valuelen;
+
+ name = chomp_string(name);
+ namelen = strcspn(name, separators);
+
+ if (name[namelen]) {
+ name[namelen] = 0;
+ value = chomp_string(name + namelen + 1);
+ valuelen = strlen(value);
+
+ } else {
+ value = "";
+ valuelen = 0;
+ }
+
+ state = read_property(name, namelen, value, valuelen, data);
+ }
+
+ if (state != ERR && io_error(io))
+ state = ERR;
+ io_done(io);
+
+ return state;
+}
+
+int
+io_run_load(const char **argv, const char *separators,
+ io_read_fn read_property, void *data)
+{
+ struct io io;
+
+ if (!io_run(&io, IO_RD, NULL, argv))
+ return ERR;
+ return io_load(&io, separators, read_property, data);
+}
diff --git a/io.h b/io.h
--- /dev/null
+++ b/io.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2006-2010 Jonas Fonseca <fonseca@diku.dk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef TIG_IO_H
+#define TIG_IO_H
+
+/*
+ * Argument array helpers.
+ */
+
+bool argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd);
+bool argv_from_env(const char **argv, const char *name);
+void argv_free(const char *argv[]);
+size_t argv_size(const char **argv);
+bool argv_append(const char ***argv, const char *arg);
+bool argv_append_array(const char ***dst_argv, const char *src_argv[]);
+bool argv_copy(const char ***dst, const char *src[]);
+
+/*
+ * Executing external commands.
+ */
+
+enum io_type {
+ IO_FD, /* File descriptor based IO. */
+ IO_BG, /* Execute command in the background. */
+ IO_FG, /* Execute command with same std{in,out,err}. */
+ IO_RD, /* Read only fork+exec IO. */
+ IO_WR, /* Write only fork+exec IO. */
+ IO_AP, /* Append fork+exec output to file. */
+};
+
+struct io {
+ int pipe; /* Pipe end for reading or writing. */
+ pid_t pid; /* PID of spawned process. */
+ int error; /* Error status. */
+ char *buf; /* Read buffer. */
+ size_t bufalloc; /* Allocated buffer size. */
+ size_t bufsize; /* Buffer content size. */
+ char *bufpos; /* Current buffer position. */
+ unsigned int eof:1; /* Has end of file been reached. */
+};
+
+typedef int (*io_read_fn)(char *, size_t, char *, size_t, void *data);
+
+bool io_open(struct io *io, const char *fmt, ...);
+bool io_kill(struct io *io);
+bool io_done(struct io *io);
+bool io_run(struct io *io, enum io_type type, const char *dir, const char *argv[], ...);
+bool io_run_bg(const char **argv);
+bool io_run_fg(const char **argv, const char *dir);
+bool io_run_append(const char **argv, int fd);
+bool io_eof(struct io *io);
+int io_error(struct io *io);
+char * io_strerror(struct io *io);
+bool io_can_read(struct io *io);
+ssize_t io_read(struct io *io, void *buf, size_t bufsize);
+char * io_get(struct io *io, int c, bool can_read);
+bool io_write(struct io *io, const void *buf, size_t bufsize);
+bool io_read_buf(struct io *io, char buf[], size_t bufsize);
+bool io_run_buf(const char **argv, char buf[], size_t bufsize);
+int io_load(struct io *io, const char *separators,
+ io_read_fn read_property, void *data);
+int io_run_load(const char **argv, const char *separators,
+ io_read_fn read_property, void *data);
+
+#endif
index 718e6c2d186254f5cca36a5fcee1742d7b9265ed..6ad9c57953182e4d54d4ad3fdca66d61e8dfc4b3 100644 (file)
--- a/tig.c
+++ b/tig.c
*/
#include "tig.h"
+#include "io.h"
static void __NORETURN die(const char *err, ...);
static void warn(const char *msg, ...);
}
-static bool
-argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
-{
- int valuelen;
-
- while (*cmd && *argc < SIZEOF_ARG && (valuelen = strcspn(cmd, " \t"))) {
- bool advance = cmd[valuelen] != 0;
-
- cmd[valuelen] = 0;
- argv[(*argc)++] = chomp_string(cmd);
- cmd = chomp_string(cmd + valuelen + advance);
- }
-
- if (*argc < SIZEOF_ARG)
- argv[*argc] = NULL;
- return *argc < SIZEOF_ARG;
-}
-
-static bool
-argv_from_env(const char **argv, const char *name)
-{
- char *env = argv ? getenv(name) : NULL;
- int argc = 0;
-
- if (env && *env)
- env = strdup(env);
- return !env || argv_from_string(argv, &argc, env);
-}
-
-static void
-argv_free(const char *argv[])
-{
- int argc;
-
- if (!argv)
- return;
- for (argc = 0; argv[argc]; argc++)
- free((void *) argv[argc]);
- argv[0] = NULL;
-}
-
-static size_t
-argv_size(const char **argv)
-{
- int argc = 0;
-
- while (argv && argv[argc])
- argc++;
-
- return argc;
-}
-
-DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
-
-static bool
-argv_append(const char ***argv, const char *arg)
-{
- size_t argc = argv_size(*argv);
-
- if (!argv_realloc(argv, argc, 2))
- return FALSE;
-
- (*argv)[argc++] = strdup(arg);
- (*argv)[argc] = NULL;
- return TRUE;
-}
-
-static bool
-argv_append_array(const char ***dst_argv, const char *src_argv[])
-{
- int i;
-
- for (i = 0; src_argv && src_argv[i]; i++)
- if (!argv_append(dst_argv, src_argv[i]))
- return FALSE;
- return TRUE;
-}
-
-static bool
-argv_copy(const char ***dst, const char *src[])
-{
- int argc;
-
- for (argc = 0; src[argc]; argc++)
- if (!argv_append(dst, src[argc]))
- return FALSE;
- return TRUE;
-}
-
-
-/*
- * Executing external commands.
- */
-
-enum io_type {
- IO_FD, /* File descriptor based IO. */
- IO_BG, /* Execute command in the background. */
- IO_FG, /* Execute command with same std{in,out,err}. */
- IO_RD, /* Read only fork+exec IO. */
- IO_WR, /* Write only fork+exec IO. */
- IO_AP, /* Append fork+exec output to file. */
-};
-
-struct io {
- int pipe; /* Pipe end for reading or writing. */
- pid_t pid; /* PID of spawned process. */
- int error; /* Error status. */
- char *buf; /* Read buffer. */
- size_t bufalloc; /* Allocated buffer size. */
- size_t bufsize; /* Buffer content size. */
- char *bufpos; /* Current buffer position. */
- unsigned int eof:1; /* Has end of file been reached. */
-};
-
-static void
-io_init(struct io *io)
-{
- memset(io, 0, sizeof(*io));
- io->pipe = -1;
-}
-
-static bool
-io_open(struct io *io, const char *fmt, ...)
-{
- char name[SIZEOF_STR] = "";
- bool fits;
- va_list args;
-
- io_init(io);
-
- va_start(args, fmt);
- fits = vsnprintf(name, sizeof(name), fmt, args) < sizeof(name);
- va_end(args);
-
- if (!fits) {
- io->error = ENAMETOOLONG;
- return FALSE;
- }
- io->pipe = *name ? open(name, O_RDONLY) : STDIN_FILENO;
- if (io->pipe == -1)
- io->error = errno;
- return io->pipe != -1;
-}
-
-static bool
-io_kill(struct io *io)
-{
- return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
-}
-
-static bool
-io_done(struct io *io)
-{
- pid_t pid = io->pid;
-
- if (io->pipe != -1)
- close(io->pipe);
- free(io->buf);
- io_init(io);
-
- while (pid > 0) {
- int status;
- pid_t waiting = waitpid(pid, &status, 0);
-
- if (waiting < 0) {
- if (errno == EINTR)
- continue;
- io->error = errno;
- return FALSE;
- }
-
- return waiting == pid &&
- !WIFSIGNALED(status) &&
- WIFEXITED(status) &&
- !WEXITSTATUS(status);
- }
-
- return TRUE;
-}
-
-static bool
-io_run(struct io *io, enum io_type type, const char *dir, const char *argv[], ...)
-{
- int pipefds[2] = { -1, -1 };
- va_list args;
-
- io_init(io);
-
- if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
- io->error = errno;
- return FALSE;
- } else if (type == IO_AP) {
- va_start(args, argv);
- pipefds[1] = va_arg(args, int);
- va_end(args);
- }
-
- if ((io->pid = fork())) {
- if (io->pid == -1)
- io->error = errno;
- if (pipefds[!(type == IO_WR)] != -1)
- close(pipefds[!(type == IO_WR)]);
- if (io->pid != -1) {
- io->pipe = pipefds[!!(type == IO_WR)];
- return TRUE;
- }
-
- } else {
- if (type != IO_FG) {
- int devnull = open("/dev/null", O_RDWR);
- int readfd = type == IO_WR ? pipefds[0] : devnull;
- int writefd = (type == IO_RD || type == IO_AP)
- ? pipefds[1] : devnull;
-
- dup2(readfd, STDIN_FILENO);
- dup2(writefd, STDOUT_FILENO);
- dup2(devnull, STDERR_FILENO);
-
- close(devnull);
- if (pipefds[0] != -1)
- close(pipefds[0]);
- if (pipefds[1] != -1)
- close(pipefds[1]);
- }
-
- if (dir && *dir && chdir(dir) == -1)
- exit(errno);
-
- execvp(argv[0], (char *const*) argv);
- exit(errno);
- }
-
- if (pipefds[!!(type == IO_WR)] != -1)
- close(pipefds[!!(type == IO_WR)]);
- return FALSE;
-}
-
-static bool
-io_complete(enum io_type type, const char **argv, const char *dir, int fd)
-{
- struct io io;
-
- return io_run(&io, type, dir, argv, fd) && io_done(&io);
-}
-
-static bool
-io_run_bg(const char **argv)
-{
- return io_complete(IO_BG, argv, NULL, -1);
-}
-
-static bool
-io_run_fg(const char **argv, const char *dir)
-{
- return io_complete(IO_FG, argv, dir, -1);
-}
-
-static bool
-io_run_append(const char **argv, int fd)
-{
- return io_complete(IO_AP, argv, NULL, fd);
-}
-
-static bool
-io_eof(struct io *io)
-{
- return io->eof;
-}
-
-static int
-io_error(struct io *io)
-{
- return io->error;
-}
-
-static char *
-io_strerror(struct io *io)
-{
- return strerror(io->error);
-}
-
-static bool
-io_can_read(struct io *io)
-{
- struct timeval tv = { 0, 500 };
- fd_set fds;
-
- FD_ZERO(&fds);
- FD_SET(io->pipe, &fds);
-
- return select(io->pipe + 1, &fds, NULL, NULL, &tv) > 0;
-}
-
-static ssize_t
-io_read(struct io *io, void *buf, size_t bufsize)
-{
- do {
- ssize_t readsize = read(io->pipe, buf, bufsize);
-
- if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
- continue;
- else if (readsize == -1)
- io->error = errno;
- else if (readsize == 0)
- io->eof = 1;
- return readsize;
- } while (1);
-}
-
-DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
-
-static char *
-io_get(struct io *io, int c, bool can_read)
-{
- char *eol;
- ssize_t readsize;
-
- while (TRUE) {
- if (io->bufsize > 0) {
- eol = memchr(io->bufpos, c, io->bufsize);
- if (eol) {
- char *line = io->bufpos;
-
- *eol = 0;
- io->bufpos = eol + 1;
- io->bufsize -= io->bufpos - line;
- return line;
- }
- }
-
- if (io_eof(io)) {
- if (io->bufsize) {
- io->bufpos[io->bufsize] = 0;
- io->bufsize = 0;
- return io->bufpos;
- }
- return NULL;
- }
-
- if (!can_read)
- return NULL;
-
- if (io->bufsize > 0 && io->bufpos > io->buf)
- memmove(io->buf, io->bufpos, io->bufsize);
-
- if (io->bufalloc == io->bufsize) {
- if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
- return NULL;
- io->bufalloc += BUFSIZ;
- }
-
- io->bufpos = io->buf;
- readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
- if (io_error(io))
- return NULL;
- io->bufsize += readsize;
- }
-}
-
-static bool
-io_write(struct io *io, const void *buf, size_t bufsize)
-{
- size_t written = 0;
-
- while (!io_error(io) && written < bufsize) {
- ssize_t size;
-
- size = write(io->pipe, buf + written, bufsize - written);
- if (size < 0 && (errno == EAGAIN || errno == EINTR))
- continue;
- else if (size == -1)
- io->error = errno;
- else
- written += size;
- }
-
- return written == bufsize;
-}
-
-static bool
-io_read_buf(struct io *io, char buf[], size_t bufsize)
-{
- char *result = io_get(io, '\n', TRUE);
-
- if (result) {
- result = chomp_string(result);
- string_ncopy_do(buf, bufsize, result, strlen(result));
- }
-
- return io_done(io) && result;
-}
-
-static bool
-io_run_buf(const char **argv, char buf[], size_t bufsize)
-{
- struct io io;
-
- return io_run(&io, IO_RD, NULL, argv) && io_read_buf(&io, buf, bufsize);
-}
-
-typedef int (*io_read_fn)(char *, size_t, char *, size_t, void *data);
-
-static int
-io_load(struct io *io, const char *separators,
- io_read_fn read_property, void *data)
-{
- char *name;
- int state = OK;
-
- while (state == OK && (name = io_get(io, '\n', TRUE))) {
- char *value;
- size_t namelen;
- size_t valuelen;
-
- name = chomp_string(name);
- namelen = strcspn(name, separators);
-
- if (name[namelen]) {
- name[namelen] = 0;
- value = chomp_string(name + namelen + 1);
- valuelen = strlen(value);
-
- } else {
- value = "";
- valuelen = 0;
- }
-
- state = read_property(name, namelen, value, valuelen, data);
- }
-
- if (state != ERR && io_error(io))
- state = ERR;
- io_done(io);
-
- return state;
-}
-
-static int
-io_run_load(const char **argv, const char *separators,
- io_read_fn read_property, void *data)
-{
- struct io io;
-
- if (!io_run(&io, IO_RD, NULL, argv))
- return ERR;
- return io_load(&io, separators, read_property, data);
-}
-
-
/*
* User requests
*/