Only set LINES and COLUMNS environment variables for external commands
[tig.git] / io.c
blobabed22e2266272577a19cba0128979257463c9a3
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 DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
114 bool
115 argv_append(const char ***argv, const char *arg)
117 size_t argc = argv_size(*argv);
118 char *alloc;
120 if (!*arg && argc > 0)
121 return TRUE;
123 if (!argv_realloc(argv, argc, 2))
124 return FALSE;
126 alloc = strdup(arg);
128 (*argv)[argc++] = alloc;
129 (*argv)[argc] = NULL;
131 return alloc != NULL;
134 bool
135 argv_append_array(const char ***dst_argv, const char *src_argv[])
137 int i;
139 for (i = 0; src_argv && src_argv[i]; i++)
140 if (!argv_append(dst_argv, src_argv[i]))
141 return FALSE;
142 return TRUE;
145 bool
146 argv_remove_quotes(const char *argv[])
148 int argc;
150 for (argc = 0; argv[argc]; argc++) {
151 char quoted = 0;
152 const char *arg = argv[argc];
153 int arglen = get_arg_valuelen(arg, &quoted);
154 int unquotedlen = arglen - 1 - (arg[arglen - 1] == quoted);
155 char *unquoted;
157 if (!quoted)
158 continue;
160 unquoted = malloc(unquotedlen + 1);
161 if (!unquoted)
162 return FALSE;
163 strncpy(unquoted, arg + 1, unquotedlen);
164 unquoted[unquotedlen] = 0;
165 free((void *) arg);
166 argv[argc] = unquoted;
169 return TRUE;
172 bool
173 argv_copy(const char ***dst, const char *src[])
175 int argc;
177 argv_free(*dst);
178 for (argc = 0; src[argc]; argc++)
179 if (!argv_append(dst, src[argc]))
180 return FALSE;
181 return TRUE;
185 * Encoding conversion.
188 struct encoding {
189 struct encoding *next;
190 iconv_t cd;
191 char fromcode[1];
194 static struct encoding *encodings;
196 struct encoding *
197 encoding_open(const char *fromcode)
199 struct encoding *encoding;
200 size_t len = strlen(fromcode);
202 if (!*fromcode)
203 return NULL;
205 for (encoding = encodings; encoding; encoding = encoding->next) {
206 if (!strcasecmp(encoding->fromcode, fromcode))
207 return encoding;
210 encoding = calloc(1, sizeof(*encoding) + len);
211 strncpy(encoding->fromcode, fromcode, len);
212 encoding->cd = iconv_open(ENCODING_UTF8, fromcode);
213 if (encoding->cd == ICONV_NONE) {
214 free(encoding);
215 return NULL;
218 encoding->next = encodings;
219 encodings = encoding;
221 return encoding;
224 char *
225 encoding_convert(struct encoding *encoding, char *line)
227 static char out_buffer[BUFSIZ * 2];
228 ICONV_CONST char *inbuf = line;
229 size_t inlen = strlen(line) + 1;
231 char *outbuf = out_buffer;
232 size_t outlen = sizeof(out_buffer);
234 size_t ret = iconv(encoding->cd, &inbuf, &inlen, &outbuf, &outlen);
236 return (ret != (size_t) -1) ? out_buffer : line;
240 * Executing external commands.
243 static void
244 io_init(struct io *io)
246 memset(io, 0, sizeof(*io));
247 io->pipe = -1;
250 bool
251 io_open(struct io *io, const char *fmt, ...)
253 char name[SIZEOF_STR] = "";
254 int retval;
256 io_init(io);
258 FORMAT_BUFFER(name, sizeof(name), fmt, retval, FALSE);
259 if (retval < 0) {
260 io->error = ENAMETOOLONG;
261 return FALSE;
264 io->pipe = *name ? open(name, O_RDONLY) : dup(STDIN_FILENO);
265 if (io->pipe == -1)
266 io->error = errno;
267 return io->pipe != -1;
270 bool
271 io_kill(struct io *io)
273 return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
276 bool
277 io_done(struct io *io)
279 pid_t pid = io->pid;
281 if (io->pipe != -1)
282 close(io->pipe);
283 free(io->buf);
284 io_init(io);
286 while (pid > 0) {
287 int status;
288 pid_t waiting = waitpid(pid, &status, 0);
290 if (waiting < 0) {
291 if (errno == EINTR)
292 continue;
293 io->error = errno;
294 return FALSE;
297 if (WEXITSTATUS(status)) {
298 io->status = WEXITSTATUS(status);
301 return waiting == pid &&
302 !WIFSIGNALED(status) &&
303 !io->status;
306 return TRUE;
309 static int
310 open_trace(int devnull, const char *argv[])
312 static const char *trace_file;
314 if (!trace_file) {
315 trace_file = getenv("TIG_TRACE");
316 if (!trace_file)
317 trace_file = "";
320 if (*trace_file) {
321 int fd = open(trace_file, O_RDWR | O_CREAT | O_APPEND, 0666);
322 int i;
324 for (i = 0; argv[i]; i++) {
325 if (write(fd, argv[i], strlen(argv[i])) == -1
326 || write(fd, " ", 1) == -1)
327 break;
329 if (argv[i] || write(fd, "\n", 1) == -1) {
330 close(fd);
331 return devnull;
334 return fd;
337 return devnull;
340 bool
341 io_run(struct io *io, enum io_type type, const char *dir, char * const env[], const char *argv[], ...)
343 int pipefds[2] = { -1, -1 };
344 va_list args;
345 bool read_from_stdin = type == IO_RD_STDIN;
347 io_init(io);
349 if (read_from_stdin)
350 type = IO_RD;
352 if (dir && !strcmp(dir, argv[0]))
353 return io_open(io, "%s%s", dir, argv[1]);
355 if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
356 io->error = errno;
357 return FALSE;
358 } else if (type == IO_AP) {
359 va_start(args, argv);
360 pipefds[1] = va_arg(args, int);
361 va_end(args);
364 if ((io->pid = fork())) {
365 if (io->pid == -1)
366 io->error = errno;
367 if (pipefds[!(type == IO_WR)] != -1)
368 close(pipefds[!(type == IO_WR)]);
369 if (io->pid != -1) {
370 io->pipe = pipefds[!!(type == IO_WR)];
371 return TRUE;
374 } else {
375 if (type != IO_FG) {
376 int devnull = open("/dev/null", O_RDWR);
377 int readfd = type == IO_WR ? pipefds[0] : devnull;
378 int writefd = (type == IO_RD || type == IO_AP)
379 ? pipefds[1] : devnull;
380 int errorfd = open_trace(devnull, argv);
382 /* Inject stdin given on the command line. */
383 if (read_from_stdin)
384 readfd = dup(STDIN_FILENO);
386 dup2(readfd, STDIN_FILENO);
387 dup2(writefd, STDOUT_FILENO);
388 dup2(errorfd, STDERR_FILENO);
390 if (devnull != errorfd)
391 close(errorfd);
392 close(devnull);
393 if (pipefds[0] != -1)
394 close(pipefds[0]);
395 if (pipefds[1] != -1)
396 close(pipefds[1]);
399 if (dir && *dir && chdir(dir) == -1)
400 exit(errno);
402 if (env) {
403 int i;
405 for (i = 0; env[i]; i++)
406 if (*env[i])
407 putenv(env[i]);
410 execvp(argv[0], (char *const*) argv);
411 exit(errno);
414 if (pipefds[!!(type == IO_WR)] != -1)
415 close(pipefds[!!(type == IO_WR)]);
416 return FALSE;
419 bool
420 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
422 struct io io;
424 return io_run(&io, type, dir, NULL, argv, fd) && io_done(&io);
427 bool
428 io_run_bg(const char **argv)
430 return io_complete(IO_BG, argv, NULL, -1);
433 bool
434 io_run_fg(const char **argv, const char *dir)
436 return io_complete(IO_FG, argv, dir, -1);
439 bool
440 io_run_append(const char **argv, int fd)
442 return io_complete(IO_AP, argv, NULL, fd);
445 bool
446 io_eof(struct io *io)
448 return io->eof;
452 io_error(struct io *io)
454 return io->error;
457 char *
458 io_strerror(struct io *io)
460 return strerror(io->error);
463 bool
464 io_can_read(struct io *io, bool can_block)
466 struct timeval tv = { 0, 500 };
467 fd_set fds;
469 FD_ZERO(&fds);
470 FD_SET(io->pipe, &fds);
472 return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
475 ssize_t
476 io_read(struct io *io, void *buf, size_t bufsize)
478 do {
479 ssize_t readsize = read(io->pipe, buf, bufsize);
481 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
482 continue;
483 else if (readsize == -1)
484 io->error = errno;
485 else if (readsize == 0)
486 io->eof = 1;
487 return readsize;
488 } while (1);
491 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
493 char *
494 io_get(struct io *io, int c, bool can_read)
496 char *eol;
497 ssize_t readsize;
499 while (TRUE) {
500 if (io->bufsize > 0) {
501 eol = memchr(io->bufpos, c, io->bufsize);
502 if (eol) {
503 char *line = io->bufpos;
505 *eol = 0;
506 io->bufpos = eol + 1;
507 io->bufsize -= io->bufpos - line;
508 return line;
512 if (io_eof(io)) {
513 if (io->bufsize) {
514 io->bufpos[io->bufsize] = 0;
515 io->bufsize = 0;
516 return io->bufpos;
518 return NULL;
521 if (!can_read)
522 return NULL;
524 if (io->bufsize > 0 && io->bufpos > io->buf)
525 memmove(io->buf, io->bufpos, io->bufsize);
527 if (io->bufalloc == io->bufsize) {
528 if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
529 return NULL;
530 io->bufalloc += BUFSIZ;
533 io->bufpos = io->buf;
534 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
535 if (io_error(io))
536 return NULL;
537 io->bufsize += readsize;
541 bool
542 io_write(struct io *io, const void *buf, size_t bufsize)
544 size_t written = 0;
546 while (!io_error(io) && written < bufsize) {
547 ssize_t size;
549 size = write(io->pipe, buf + written, bufsize - written);
550 if (size < 0 && (errno == EAGAIN || errno == EINTR))
551 continue;
552 else if (size == -1)
553 io->error = errno;
554 else
555 written += size;
558 return written == bufsize;
561 bool
562 io_printf(struct io *io, const char *fmt, ...)
564 char buf[SIZEOF_STR] = "";
565 int retval;
567 FORMAT_BUFFER(buf, sizeof(buf), fmt, retval, FALSE);
568 if (retval < 0) {
569 io->error = ENAMETOOLONG;
570 return FALSE;
573 return io_write(io, buf, retval);
576 bool
577 io_read_buf(struct io *io, char buf[], size_t bufsize)
579 char *result = io_get(io, '\n', TRUE);
581 if (result) {
582 result = chomp_string(result);
583 string_ncopy_do(buf, bufsize, result, strlen(result));
586 return io_done(io) && result;
589 bool
590 io_run_buf(const char **argv, char buf[], size_t bufsize)
592 struct io io;
594 return io_run(&io, IO_RD, NULL, NULL, argv) && io_read_buf(&io, buf, bufsize);
598 io_load(struct io *io, const char *separators,
599 io_read_fn read_property, void *data)
601 char *name;
602 int state = OK;
604 while (state == OK && (name = io_get(io, '\n', TRUE))) {
605 char *value;
606 size_t namelen;
607 size_t valuelen;
609 name = chomp_string(name);
610 namelen = strcspn(name, separators);
612 if (name[namelen]) {
613 name[namelen] = 0;
614 value = chomp_string(name + namelen + 1);
615 valuelen = strlen(value);
617 } else {
618 value = "";
619 valuelen = 0;
622 state = read_property(name, namelen, value, valuelen, data);
625 if (state != ERR && io_error(io))
626 state = ERR;
627 io_done(io);
629 return state;
633 io_run_load(const char **argv, const char *separators,
634 io_read_fn read_property, void *data)
636 struct io io;
638 if (!io_run(&io, IO_RD, NULL, NULL, argv))
639 return ERR;
640 return io_load(&io, separators, read_property, data);
643 /* vim: set ts=8 sw=8 noexpandtab: */