Code

Add specialized open methods for each view
[tig.git] / io.c
1 /* Copyright (c) 2006-2010 Jonas Fonseca <fonseca@diku.dk>
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License as
5  * published by the Free Software Foundation; either version 2 of
6  * the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
14 #include "tig.h"
15 #include "io.h"
17 bool
18 argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
19 {
20         int valuelen;
22         while (*cmd && *argc < SIZEOF_ARG && (valuelen = strcspn(cmd, " \t"))) {
23                 bool advance = cmd[valuelen] != 0;
25                 cmd[valuelen] = 0;
26                 argv[(*argc)++] = chomp_string(cmd);
27                 cmd = chomp_string(cmd + valuelen + advance);
28         }
30         if (*argc < SIZEOF_ARG)
31                 argv[*argc] = NULL;
32         return *argc < SIZEOF_ARG;
33 }
35 bool
36 argv_from_env(const char **argv, const char *name)
37 {
38         char *env = argv ? getenv(name) : NULL;
39         int argc = 0;
41         if (env && *env)
42                 env = strdup(env);
43         return !env || argv_from_string(argv, &argc, env);
44 }
46 void
47 argv_free(const char *argv[])
48 {
49         int argc;
51         if (!argv)
52                 return;
53         for (argc = 0; argv[argc]; argc++)
54                 free((void *) argv[argc]);
55         argv[0] = NULL;
56 }
58 size_t
59 argv_size(const char **argv)
60 {
61         int argc = 0;
63         while (argv && argv[argc])
64                 argc++;
66         return argc;
67 }
69 DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
71 bool
72 argv_append(const char ***argv, const char *arg)
73 {
74         size_t argc = argv_size(*argv);
76         if (!argv_realloc(argv, argc, 2))
77                 return FALSE;
79         (*argv)[argc++] = strdup(arg);
80         (*argv)[argc] = NULL;
81         return TRUE;
82 }
84 bool
85 argv_append_array(const char ***dst_argv, const char *src_argv[])
86 {
87         int i;
89         for (i = 0; src_argv && src_argv[i]; i++)
90                 if (!argv_append(dst_argv, src_argv[i]))
91                         return FALSE;
92         return TRUE;
93 }
95 bool
96 argv_copy(const char ***dst, const char *src[])
97 {
98         int argc;
100         for (argc = 0; src[argc]; argc++)
101                 if (!argv_append(dst, src[argc]))
102                         return FALSE;
103         return TRUE;
107 /*
108  * Executing external commands.
109  */
111 static void
112 io_init(struct io *io)
114         memset(io, 0, sizeof(*io));
115         io->pipe = -1;
118 bool
119 io_open(struct io *io, const char *fmt, ...)
121         char name[SIZEOF_STR] = "";
122         bool fits;
123         va_list args;
125         io_init(io);
127         va_start(args, fmt);
128         fits = vsnprintf(name, sizeof(name), fmt, args) < sizeof(name);
129         va_end(args);
131         if (!fits) {
132                 io->error = ENAMETOOLONG;
133                 return FALSE;
134         }
135         io->pipe = *name ? open(name, O_RDONLY) : STDIN_FILENO;
136         if (io->pipe == -1)
137                 io->error = errno;
138         return io->pipe != -1;
141 bool
142 io_kill(struct io *io)
144         return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
147 bool
148 io_done(struct io *io)
150         pid_t pid = io->pid;
152         if (io->pipe != -1)
153                 close(io->pipe);
154         free(io->buf);
155         io_init(io);
157         while (pid > 0) {
158                 int status;
159                 pid_t waiting = waitpid(pid, &status, 0);
161                 if (waiting < 0) {
162                         if (errno == EINTR)
163                                 continue;
164                         io->error = errno;
165                         return FALSE;
166                 }
168                 return waiting == pid &&
169                        !WIFSIGNALED(status) &&
170                        WIFEXITED(status) &&
171                        !WEXITSTATUS(status);
172         }
174         return TRUE;
177 bool
178 io_run(struct io *io, enum io_type type, const char *dir, const char *argv[], ...)
180         int pipefds[2] = { -1, -1 };
181         va_list args;
183         io_init(io);
185         if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
186                 io->error = errno;
187                 return FALSE;
188         } else if (type == IO_AP) {
189                 va_start(args, argv);
190                 pipefds[1] = va_arg(args, int);
191                 va_end(args);
192         }
194         if ((io->pid = fork())) {
195                 if (io->pid == -1)
196                         io->error = errno;
197                 if (pipefds[!(type == IO_WR)] != -1)
198                         close(pipefds[!(type == IO_WR)]);
199                 if (io->pid != -1) {
200                         io->pipe = pipefds[!!(type == IO_WR)];
201                         return TRUE;
202                 }
204         } else {
205                 if (type != IO_FG) {
206                         int devnull = open("/dev/null", O_RDWR);
207                         int readfd  = type == IO_WR ? pipefds[0] : devnull;
208                         int writefd = (type == IO_RD || type == IO_AP)
209                                                         ? pipefds[1] : devnull;
211                         dup2(readfd,  STDIN_FILENO);
212                         dup2(writefd, STDOUT_FILENO);
213                         dup2(devnull, STDERR_FILENO);
215                         close(devnull);
216                         if (pipefds[0] != -1)
217                                 close(pipefds[0]);
218                         if (pipefds[1] != -1)
219                                 close(pipefds[1]);
220                 }
222                 if (dir && *dir && chdir(dir) == -1)
223                         exit(errno);
225                 execvp(argv[0], (char *const*) argv);
226                 exit(errno);
227         }
229         if (pipefds[!!(type == IO_WR)] != -1)
230                 close(pipefds[!!(type == IO_WR)]);
231         return FALSE;
234 bool
235 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
237         struct io io;
239         return io_run(&io, type, dir, argv, fd) && io_done(&io);
242 bool
243 io_run_bg(const char **argv)
245         return io_complete(IO_BG, argv, NULL, -1);
248 bool
249 io_run_fg(const char **argv, const char *dir)
251         return io_complete(IO_FG, argv, dir, -1);
254 bool
255 io_run_append(const char **argv, int fd)
257         return io_complete(IO_AP, argv, NULL, fd);
260 bool
261 io_eof(struct io *io)
263         return io->eof;
266 int
267 io_error(struct io *io)
269         return io->error;
272 char *
273 io_strerror(struct io *io)
275         return strerror(io->error);
278 bool
279 io_can_read(struct io *io, bool can_block)
281         struct timeval tv = { 0, 500 };
282         fd_set fds;
284         FD_ZERO(&fds);
285         FD_SET(io->pipe, &fds);
287         return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
290 ssize_t
291 io_read(struct io *io, void *buf, size_t bufsize)
293         do {
294                 ssize_t readsize = read(io->pipe, buf, bufsize);
296                 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
297                         continue;
298                 else if (readsize == -1)
299                         io->error = errno;
300                 else if (readsize == 0)
301                         io->eof = 1;
302                 return readsize;
303         } while (1);
306 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
308 char *
309 io_get(struct io *io, int c, bool can_read)
311         char *eol;
312         ssize_t readsize;
314         while (TRUE) {
315                 if (io->bufsize > 0) {
316                         eol = memchr(io->bufpos, c, io->bufsize);
317                         if (eol) {
318                                 char *line = io->bufpos;
320                                 *eol = 0;
321                                 io->bufpos = eol + 1;
322                                 io->bufsize -= io->bufpos - line;
323                                 return line;
324                         }
325                 }
327                 if (io_eof(io)) {
328                         if (io->bufsize) {
329                                 io->bufpos[io->bufsize] = 0;
330                                 io->bufsize = 0;
331                                 return io->bufpos;
332                         }
333                         return NULL;
334                 }
336                 if (!can_read)
337                         return NULL;
339                 if (io->bufsize > 0 && io->bufpos > io->buf)
340                         memmove(io->buf, io->bufpos, io->bufsize);
342                 if (io->bufalloc == io->bufsize) {
343                         if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
344                                 return NULL;
345                         io->bufalloc += BUFSIZ;
346                 }
348                 io->bufpos = io->buf;
349                 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
350                 if (io_error(io))
351                         return NULL;
352                 io->bufsize += readsize;
353         }
356 bool
357 io_write(struct io *io, const void *buf, size_t bufsize)
359         size_t written = 0;
361         while (!io_error(io) && written < bufsize) {
362                 ssize_t size;
364                 size = write(io->pipe, buf + written, bufsize - written);
365                 if (size < 0 && (errno == EAGAIN || errno == EINTR))
366                         continue;
367                 else if (size == -1)
368                         io->error = errno;
369                 else
370                         written += size;
371         }
373         return written == bufsize;
376 bool
377 io_read_buf(struct io *io, char buf[], size_t bufsize)
379         char *result = io_get(io, '\n', TRUE);
381         if (result) {
382                 result = chomp_string(result);
383                 string_ncopy_do(buf, bufsize, result, strlen(result));
384         }
386         return io_done(io) && result;
389 bool
390 io_run_buf(const char **argv, char buf[], size_t bufsize)
392         struct io io;
394         return io_run(&io, IO_RD, NULL, argv) && io_read_buf(&io, buf, bufsize);
397 int
398 io_load(struct io *io, const char *separators,
399         io_read_fn read_property, void *data)
401         char *name;
402         int state = OK;
404         while (state == OK && (name = io_get(io, '\n', TRUE))) {
405                 char *value;
406                 size_t namelen;
407                 size_t valuelen;
409                 name = chomp_string(name);
410                 namelen = strcspn(name, separators);
412                 if (name[namelen]) {
413                         name[namelen] = 0;
414                         value = chomp_string(name + namelen + 1);
415                         valuelen = strlen(value);
417                 } else {
418                         value = "";
419                         valuelen = 0;
420                 }
422                 state = read_property(name, namelen, value, valuelen, data);
423         }
425         if (state != ERR && io_error(io))
426                 state = ERR;
427         io_done(io);
429         return state;
432 int
433 io_run_load(const char **argv, const char *separators,
434             io_read_fn read_property, void *data)
436         struct io io;
438         if (!io_run(&io, IO_RD, NULL, argv))
439                 return ERR;
440         return io_load(&io, separators, read_property, data);