tig(1): document the Git commands supported by the pager mode
[tig.git] / io.c
blob7f8b4d2899ff631668e6a4aa20db393ca9fef46b
1 /* Copyright (c) 2006-2013 Jonas Fonseca <fonseca@diku.dk>
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.
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.
14 #include "tig.h"
15 #include "io.h"
17 bool
18 argv_to_string(const char *argv[SIZEOF_ARG], char *buf, size_t buflen, const char *sep)
20 size_t bufpos, argc;
22 for (bufpos = 0, argc = 0; argv[argc]; argc++)
23 if (!string_nformat(buf, buflen, &bufpos, "%s%s",
24 argc ? sep : "", argv[argc]))
25 return FALSE;
27 return TRUE;
30 static inline int
31 get_arg_valuelen(const char *arg, char *quoted)
33 if (*arg == '"' || *arg == '\'') {
34 const char *end = *arg == '"' ? "\"" : "'";
35 int valuelen = strcspn(arg + 1, end);
37 if (quoted)
38 *quoted = *arg;
39 return valuelen > 0 ? valuelen + 2 : strlen(arg);
40 } else {
41 if (quoted)
42 *quoted = 0;
43 return strcspn(arg, " \t");
47 static bool
48 split_argv_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd, bool remove_quotes)
50 while (*cmd && *argc < SIZEOF_ARG) {
51 char quoted = 0;
52 int valuelen = get_arg_valuelen(cmd, &quoted);
53 bool advance = cmd[valuelen] != 0;
54 int quote_offset = !!(quoted && remove_quotes);
56 cmd[valuelen - quote_offset] = 0;
57 argv[(*argc)++] = chomp_string(cmd + quote_offset);
58 cmd = chomp_string(cmd + valuelen + advance);
61 if (*argc < SIZEOF_ARG)
62 argv[*argc] = NULL;
63 return *argc < SIZEOF_ARG;
66 bool
67 argv_from_string_no_quotes(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
69 return split_argv_string(argv, argc, cmd, TRUE);
72 bool
73 argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
75 return split_argv_string(argv, argc, cmd, FALSE);
78 bool
79 argv_from_env(const char **argv, const char *name)
81 char *env = argv ? getenv(name) : NULL;
82 int argc = 0;
84 if (env && *env)
85 env = strdup(env);
86 return !env || argv_from_string(argv, &argc, env);
89 void
90 argv_free(const char *argv[])
92 int argc;
94 if (!argv)
95 return;
96 for (argc = 0; argv[argc]; argc++)
97 free((void *) argv[argc]);
98 argv[0] = NULL;
101 size_t
102 argv_size(const char **argv)
104 int argc = 0;
106 while (argv && argv[argc])
107 argc++;
109 return argc;
112 bool
113 argv_contains(const char **argv, const char *arg)
115 int i;
117 for (i = 0; argv && argv[i]; i++)
118 if (!strcmp(argv[i], arg))
119 return TRUE;
120 return FALSE;
123 DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
125 bool
126 argv_append(const char ***argv, const char *arg)
128 size_t argc = argv_size(*argv);
129 char *alloc;
131 if (!*arg && argc > 0)
132 return TRUE;
134 if (!argv_realloc(argv, argc, 2))
135 return FALSE;
137 alloc = strdup(arg);
139 (*argv)[argc++] = alloc;
140 (*argv)[argc] = NULL;
142 return alloc != NULL;
145 bool
146 argv_append_array(const char ***dst_argv, const char *src_argv[])
148 int i;
150 for (i = 0; src_argv && src_argv[i]; i++)
151 if (!argv_append(dst_argv, src_argv[i]))
152 return FALSE;
153 return TRUE;
156 bool
157 argv_remove_quotes(const char *argv[])
159 int argc;
161 for (argc = 0; argv[argc]; argc++) {
162 char quoted = 0;
163 const char *arg = argv[argc];
164 int arglen = get_arg_valuelen(arg, &quoted);
165 int unquotedlen = arglen - 1 - (arg[arglen - 1] == quoted);
166 char *unquoted;
168 if (!quoted)
169 continue;
171 unquoted = malloc(unquotedlen + 1);
172 if (!unquoted)
173 return FALSE;
174 strncpy(unquoted, arg + 1, unquotedlen);
175 unquoted[unquotedlen] = 0;
176 free((void *) arg);
177 argv[argc] = unquoted;
180 return TRUE;
183 bool
184 argv_copy(const char ***dst, const char *src[])
186 int argc;
188 argv_free(*dst);
189 for (argc = 0; src[argc]; argc++)
190 if (!argv_append(dst, src[argc]))
191 return FALSE;
192 return TRUE;
196 * Encoding conversion.
199 struct encoding {
200 struct encoding *next;
201 iconv_t cd;
202 char fromcode[1];
205 static struct encoding *encodings;
207 struct encoding *
208 encoding_open(const char *fromcode)
210 struct encoding *encoding;
211 size_t len = strlen(fromcode);
213 if (!*fromcode)
214 return NULL;
216 for (encoding = encodings; encoding; encoding = encoding->next) {
217 if (!strcasecmp(encoding->fromcode, fromcode))
218 return encoding;
221 encoding = calloc(1, sizeof(*encoding) + len);
222 strncpy(encoding->fromcode, fromcode, len);
223 encoding->cd = iconv_open(ENCODING_UTF8, fromcode);
224 if (encoding->cd == ICONV_NONE) {
225 free(encoding);
226 return NULL;
229 encoding->next = encodings;
230 encodings = encoding;
232 return encoding;
235 static char *
236 encoding_convert_string(iconv_t iconv_cd, char *line)
238 static char out_buffer[BUFSIZ * 2];
239 ICONV_CONST char *inbuf = line;
240 size_t inlen = strlen(line) + 1;
242 char *outbuf = out_buffer;
243 size_t outlen = sizeof(out_buffer);
245 size_t ret = iconv(iconv_cd, &inbuf, &inlen, &outbuf, &outlen);
247 return (ret != (size_t) -1) ? out_buffer : line;
250 char *
251 encoding_convert(struct encoding *encoding, char *line)
253 return encoding_convert_string(encoding->cd, line);
256 const char *
257 encoding_iconv(iconv_t iconv_cd, const char *string)
259 char *instr = strdup(string);
260 const char *ret = encoding_convert_string(iconv_cd, instr);
262 free(instr);
263 return ret == instr ? string : ret;
267 * Executing external commands.
270 static void
271 io_init(struct io *io)
273 memset(io, 0, sizeof(*io));
274 io->pipe = -1;
277 bool
278 io_open(struct io *io, const char *fmt, ...)
280 char name[SIZEOF_STR] = "";
281 int retval;
283 io_init(io);
285 FORMAT_BUFFER(name, sizeof(name), fmt, retval, FALSE);
286 if (retval < 0) {
287 io->error = ENAMETOOLONG;
288 return FALSE;
291 io->pipe = *name ? open(name, O_RDONLY) : dup(STDIN_FILENO);
292 if (io->pipe == -1)
293 io->error = errno;
294 return io->pipe != -1;
297 bool
298 io_kill(struct io *io)
300 return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
303 bool
304 io_done(struct io *io)
306 pid_t pid = io->pid;
308 if (io->pipe != -1)
309 close(io->pipe);
310 free(io->buf);
311 io_init(io);
313 while (pid > 0) {
314 int status;
315 pid_t waiting = waitpid(pid, &status, 0);
317 if (waiting < 0) {
318 if (errno == EINTR)
319 continue;
320 io->error = errno;
321 return FALSE;
324 if (WEXITSTATUS(status)) {
325 io->status = WEXITSTATUS(status);
328 return waiting == pid &&
329 !WIFSIGNALED(status) &&
330 !io->status;
333 return TRUE;
336 static int
337 open_trace(int devnull, const char *argv[])
339 static const char *trace_file;
341 if (!trace_file) {
342 trace_file = getenv("TIG_TRACE");
343 if (!trace_file)
344 trace_file = "";
347 if (*trace_file) {
348 int fd = open(trace_file, O_RDWR | O_CREAT | O_APPEND, 0666);
349 int i;
351 for (i = 0; argv[i]; i++) {
352 if (write(fd, argv[i], strlen(argv[i])) == -1
353 || write(fd, " ", 1) == -1)
354 break;
356 if (argv[i] || write(fd, "\n", 1) == -1) {
357 close(fd);
358 return devnull;
361 return fd;
364 return devnull;
367 bool
368 io_run(struct io *io, enum io_type type, const char *dir, char * const env[], const char *argv[], ...)
370 int pipefds[2] = { -1, -1 };
371 va_list args;
372 bool read_from_stdin = type == IO_RD_STDIN;
374 io_init(io);
376 if (read_from_stdin)
377 type = IO_RD;
379 if (dir && !strcmp(dir, argv[0]))
380 return io_open(io, "%s%s", dir, argv[1]);
382 if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
383 io->error = errno;
384 return FALSE;
385 } else if (type == IO_AP) {
386 va_start(args, argv);
387 pipefds[1] = va_arg(args, int);
388 va_end(args);
391 if ((io->pid = fork())) {
392 if (io->pid == -1)
393 io->error = errno;
394 if (pipefds[!(type == IO_WR)] != -1)
395 close(pipefds[!(type == IO_WR)]);
396 if (io->pid != -1) {
397 io->pipe = pipefds[!!(type == IO_WR)];
398 return TRUE;
401 } else {
402 if (type != IO_FG) {
403 int devnull = open("/dev/null", O_RDWR);
404 int readfd = type == IO_WR ? pipefds[0] : devnull;
405 int writefd = (type == IO_RD || type == IO_AP)
406 ? pipefds[1] : devnull;
407 int errorfd = open_trace(devnull, argv);
409 /* Inject stdin given on the command line. */
410 if (read_from_stdin)
411 readfd = dup(STDIN_FILENO);
413 dup2(readfd, STDIN_FILENO);
414 dup2(writefd, STDOUT_FILENO);
415 dup2(errorfd, STDERR_FILENO);
417 if (devnull != errorfd)
418 close(errorfd);
419 close(devnull);
420 if (pipefds[0] != -1)
421 close(pipefds[0]);
422 if (pipefds[1] != -1)
423 close(pipefds[1]);
426 if (dir && *dir && chdir(dir) == -1)
427 exit(errno);
429 if (env) {
430 int i;
432 for (i = 0; env[i]; i++)
433 if (*env[i])
434 putenv(env[i]);
437 execvp(argv[0], (char *const*) argv);
438 exit(errno);
441 if (pipefds[!!(type == IO_WR)] != -1)
442 close(pipefds[!!(type == IO_WR)]);
443 return FALSE;
446 bool
447 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
449 struct io io;
451 return io_run(&io, type, dir, NULL, argv, fd) && io_done(&io);
454 bool
455 io_run_bg(const char **argv)
457 return io_complete(IO_BG, argv, NULL, -1);
460 bool
461 io_run_fg(const char **argv, const char *dir)
463 return io_complete(IO_FG, argv, dir, -1);
466 bool
467 io_run_append(const char **argv, int fd)
469 return io_complete(IO_AP, argv, NULL, fd);
472 bool
473 io_eof(struct io *io)
475 return io->eof;
479 io_error(struct io *io)
481 return io->error;
484 char *
485 io_strerror(struct io *io)
487 return strerror(io->error);
490 bool
491 io_can_read(struct io *io, bool can_block)
493 struct timeval tv = { 0, 500 };
494 fd_set fds;
496 FD_ZERO(&fds);
497 FD_SET(io->pipe, &fds);
499 return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
502 ssize_t
503 io_read(struct io *io, void *buf, size_t bufsize)
505 do {
506 ssize_t readsize = read(io->pipe, buf, bufsize);
508 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
509 continue;
510 else if (readsize == -1)
511 io->error = errno;
512 else if (readsize == 0)
513 io->eof = 1;
514 return readsize;
515 } while (1);
518 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
520 char *
521 io_get(struct io *io, int c, bool can_read)
523 char *eol;
524 ssize_t readsize;
526 while (TRUE) {
527 if (io->bufsize > 0) {
528 eol = memchr(io->bufpos, c, io->bufsize);
529 if (eol) {
530 char *line = io->bufpos;
532 *eol = 0;
533 io->bufpos = eol + 1;
534 io->bufsize -= io->bufpos - line;
535 return line;
539 if (io_eof(io)) {
540 if (io->bufsize) {
541 io->bufpos[io->bufsize] = 0;
542 io->bufsize = 0;
543 return io->bufpos;
545 return NULL;
548 if (!can_read)
549 return NULL;
551 if (io->bufsize > 0 && io->bufpos > io->buf)
552 memmove(io->buf, io->bufpos, io->bufsize);
554 if (io->bufalloc == io->bufsize) {
555 if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
556 return NULL;
557 io->bufalloc += BUFSIZ;
560 io->bufpos = io->buf;
561 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
562 if (io_error(io))
563 return NULL;
564 io->bufsize += readsize;
568 bool
569 io_write(struct io *io, const void *buf, size_t bufsize)
571 size_t written = 0;
573 while (!io_error(io) && written < bufsize) {
574 ssize_t size;
576 size = write(io->pipe, buf + written, bufsize - written);
577 if (size < 0 && (errno == EAGAIN || errno == EINTR))
578 continue;
579 else if (size == -1)
580 io->error = errno;
581 else
582 written += size;
585 return written == bufsize;
588 bool
589 io_printf(struct io *io, const char *fmt, ...)
591 char buf[SIZEOF_STR] = "";
592 int retval;
594 FORMAT_BUFFER(buf, sizeof(buf), fmt, retval, FALSE);
595 if (retval < 0) {
596 io->error = ENAMETOOLONG;
597 return FALSE;
600 return io_write(io, buf, retval);
603 bool
604 io_read_buf(struct io *io, char buf[], size_t bufsize)
606 char *result = io_get(io, '\n', TRUE);
608 if (result) {
609 result = chomp_string(result);
610 string_ncopy_do(buf, bufsize, result, strlen(result));
613 return io_done(io) && result;
616 bool
617 io_run_buf(const char **argv, char buf[], size_t bufsize)
619 struct io io;
621 return io_run(&io, IO_RD, NULL, NULL, argv) && io_read_buf(&io, buf, bufsize);
625 io_load(struct io *io, const char *separators,
626 io_read_fn read_property, void *data)
628 char *name;
629 int state = OK;
631 while (state == OK && (name = io_get(io, '\n', TRUE))) {
632 char *value;
633 size_t namelen;
634 size_t valuelen;
636 name = chomp_string(name);
637 namelen = strcspn(name, separators);
639 if (name[namelen]) {
640 name[namelen] = 0;
641 value = chomp_string(name + namelen + 1);
642 valuelen = strlen(value);
644 } else {
645 value = "";
646 valuelen = 0;
649 state = read_property(name, namelen, value, valuelen, data);
652 if (state != ERR && io_error(io))
653 state = ERR;
654 io_done(io);
656 return state;
660 io_run_load(const char **argv, const char *separators,
661 io_read_fn read_property, void *data)
663 struct io io;
665 if (!io_run(&io, IO_RD, NULL, NULL, argv))
666 return ERR;
667 return io_load(&io, separators, read_property, data);
670 /* vim: set ts=8 sw=8 noexpandtab: */