Code

Move IO API to src/io.[ch]
authorJonas Fonseca <fonseca@diku.dk>
Mon, 22 Mar 2010 02:16:58 +0000 (22:16 -0400)
committerJonas Fonseca <fonseca@diku.dk>
Mon, 7 Mar 2011 01:18:15 +0000 (20:18 -0500)
Makefile
io.c [new file with mode: 0644]
io.h [new file with mode: 0644]
tig.c

index e9670fb376449af9ed85ca1886bafaca4932efda..78131f515223e224935d942ab638886c5654ee54 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ LDLIBS ?= -lcurses
 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
@@ -149,8 +149,9 @@ configure: configure.ac acinclude.m4
 .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
new file mode 100644 (file)
index 0000000..685ffb6
--- /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
new file mode 100644 (file)
index 0000000..9a68a5e
--- /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
diff --git a/tig.c b/tig.c
index 718e6c2d186254f5cca36a5fcee1742d7b9265ed..6ad9c57953182e4d54d4ad3fdca66d61e8dfc4b3 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -12,6 +12,7 @@
  */
 
 #include "tig.h"
+#include "io.h"
 
 static void __NORETURN die(const char *err, ...);
 static void warn(const char *msg, ...);
@@ -192,455 +193,6 @@ get_author_initials(const char *author)
 }
 
 
-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
  */