Code

get_author_initials: various fixes
[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         argv_free(*dst);
101         for (argc = 0; src[argc]; argc++)
102                 if (!argv_append(dst, src[argc]))
103                         return FALSE;
104         return TRUE;
108 /*
109  * Executing external commands.
110  */
112 static void
113 io_init(struct io *io)
115         memset(io, 0, sizeof(*io));
116         io->pipe = -1;
119 bool
120 io_open(struct io *io, const char *fmt, ...)
122         char name[SIZEOF_STR] = "";
123         bool fits;
124         va_list args;
126         io_init(io);
128         va_start(args, fmt);
129         fits = vsnprintf(name, sizeof(name), fmt, args) < sizeof(name);
130         va_end(args);
132         if (!fits) {
133                 io->error = ENAMETOOLONG;
134                 return FALSE;
135         }
136         io->pipe = *name ? open(name, O_RDONLY) : STDIN_FILENO;
137         if (io->pipe == -1)
138                 io->error = errno;
139         return io->pipe != -1;
142 bool
143 io_kill(struct io *io)
145         return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
148 bool
149 io_done(struct io *io)
151         pid_t pid = io->pid;
153         if (io->pipe != -1)
154                 close(io->pipe);
155         free(io->buf);
156         io_init(io);
158         while (pid > 0) {
159                 int status;
160                 pid_t waiting = waitpid(pid, &status, 0);
162                 if (waiting < 0) {
163                         if (errno == EINTR)
164                                 continue;
165                         io->error = errno;
166                         return FALSE;
167                 }
169                 return waiting == pid &&
170                        !WIFSIGNALED(status) &&
171                        WIFEXITED(status) &&
172                        !WEXITSTATUS(status);
173         }
175         return TRUE;
178 bool
179 io_run(struct io *io, enum io_type type, const char *dir, const char *argv[], ...)
181         int pipefds[2] = { -1, -1 };
182         va_list args;
184         io_init(io);
186         if (dir && !strcmp(dir, argv[0]))
187                 return io_open(io, "%s%s", dir, argv[1]);
189         if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
190                 io->error = errno;
191                 return FALSE;
192         } else if (type == IO_AP) {
193                 va_start(args, argv);
194                 pipefds[1] = va_arg(args, int);
195                 va_end(args);
196         }
198         if ((io->pid = fork())) {
199                 if (io->pid == -1)
200                         io->error = errno;
201                 if (pipefds[!(type == IO_WR)] != -1)
202                         close(pipefds[!(type == IO_WR)]);
203                 if (io->pid != -1) {
204                         io->pipe = pipefds[!!(type == IO_WR)];
205                         return TRUE;
206                 }
208         } else {
209                 if (type != IO_FG) {
210                         int devnull = open("/dev/null", O_RDWR);
211                         int readfd  = type == IO_WR ? pipefds[0] : devnull;
212                         int writefd = (type == IO_RD || type == IO_AP)
213                                                         ? pipefds[1] : devnull;
215                         dup2(readfd,  STDIN_FILENO);
216                         dup2(writefd, STDOUT_FILENO);
217                         dup2(devnull, STDERR_FILENO);
219                         close(devnull);
220                         if (pipefds[0] != -1)
221                                 close(pipefds[0]);
222                         if (pipefds[1] != -1)
223                                 close(pipefds[1]);
224                 }
226                 if (dir && *dir && chdir(dir) == -1)
227                         exit(errno);
229                 execvp(argv[0], (char *const*) argv);
230                 exit(errno);
231         }
233         if (pipefds[!!(type == IO_WR)] != -1)
234                 close(pipefds[!!(type == IO_WR)]);
235         return FALSE;
238 bool
239 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
241         struct io io;
243         return io_run(&io, type, dir, argv, fd) && io_done(&io);
246 bool
247 io_run_bg(const char **argv)
249         return io_complete(IO_BG, argv, NULL, -1);
252 bool
253 io_run_fg(const char **argv, const char *dir)
255         return io_complete(IO_FG, argv, dir, -1);
258 bool
259 io_run_append(const char **argv, int fd)
261         return io_complete(IO_AP, argv, NULL, fd);
264 bool
265 io_eof(struct io *io)
267         return io->eof;
270 int
271 io_error(struct io *io)
273         return io->error;
276 char *
277 io_strerror(struct io *io)
279         return strerror(io->error);
282 bool
283 io_can_read(struct io *io, bool can_block)
285         struct timeval tv = { 0, 500 };
286         fd_set fds;
288         FD_ZERO(&fds);
289         FD_SET(io->pipe, &fds);
291         return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
294 ssize_t
295 io_read(struct io *io, void *buf, size_t bufsize)
297         do {
298                 ssize_t readsize = read(io->pipe, buf, bufsize);
300                 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
301                         continue;
302                 else if (readsize == -1)
303                         io->error = errno;
304                 else if (readsize == 0)
305                         io->eof = 1;
306                 return readsize;
307         } while (1);
310 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
312 char *
313 io_get(struct io *io, int c, bool can_read)
315         char *eol;
316         ssize_t readsize;
318         while (TRUE) {
319                 if (io->bufsize > 0) {
320                         eol = memchr(io->bufpos, c, io->bufsize);
321                         if (eol) {
322                                 char *line = io->bufpos;
324                                 *eol = 0;
325                                 io->bufpos = eol + 1;
326                                 io->bufsize -= io->bufpos - line;
327                                 return line;
328                         }
329                 }
331                 if (io_eof(io)) {
332                         if (io->bufsize) {
333                                 io->bufpos[io->bufsize] = 0;
334                                 io->bufsize = 0;
335                                 return io->bufpos;
336                         }
337                         return NULL;
338                 }
340                 if (!can_read)
341                         return NULL;
343                 if (io->bufsize > 0 && io->bufpos > io->buf)
344                         memmove(io->buf, io->bufpos, io->bufsize);
346                 if (io->bufalloc == io->bufsize) {
347                         if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
348                                 return NULL;
349                         io->bufalloc += BUFSIZ;
350                 }
352                 io->bufpos = io->buf;
353                 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
354                 if (io_error(io))
355                         return NULL;
356                 io->bufsize += readsize;
357         }
360 bool
361 io_write(struct io *io, const void *buf, size_t bufsize)
363         size_t written = 0;
365         while (!io_error(io) && written < bufsize) {
366                 ssize_t size;
368                 size = write(io->pipe, buf + written, bufsize - written);
369                 if (size < 0 && (errno == EAGAIN || errno == EINTR))
370                         continue;
371                 else if (size == -1)
372                         io->error = errno;
373                 else
374                         written += size;
375         }
377         return written == bufsize;
380 bool
381 io_read_buf(struct io *io, char buf[], size_t bufsize)
383         char *result = io_get(io, '\n', TRUE);
385         if (result) {
386                 result = chomp_string(result);
387                 string_ncopy_do(buf, bufsize, result, strlen(result));
388         }
390         return io_done(io) && result;
393 bool
394 io_run_buf(const char **argv, char buf[], size_t bufsize)
396         struct io io;
398         return io_run(&io, IO_RD, NULL, argv) && io_read_buf(&io, buf, bufsize);
401 int
402 io_load(struct io *io, const char *separators,
403         io_read_fn read_property, void *data)
405         char *name;
406         int state = OK;
408         while (state == OK && (name = io_get(io, '\n', TRUE))) {
409                 char *value;
410                 size_t namelen;
411                 size_t valuelen;
413                 name = chomp_string(name);
414                 namelen = strcspn(name, separators);
416                 if (name[namelen]) {
417                         name[namelen] = 0;
418                         value = chomp_string(name + namelen + 1);
419                         valuelen = strlen(value);
421                 } else {
422                         value = "";
423                         valuelen = 0;
424                 }
426                 state = read_property(name, namelen, value, valuelen, data);
427         }
429         if (state != ERR && io_error(io))
430                 state = ERR;
431         io_done(io);
433         return state;
436 int
437 io_run_load(const char **argv, const char *separators,
438             io_read_fn read_property, void *data)
440         struct io io;
442         if (!io_run(&io, IO_RD, NULL, argv))
443                 return ERR;
444         return io_load(&io, separators, read_property, data);