Simplify the install goal and rename $(PROGS) to $(EXE)
[tig.git] / io.c
blobe3b95d281f82ac40de4fb5063e218056bc2cbd39
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 static char *
225 encoding_convert_string(iconv_t iconv_cd, 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(iconv_cd, &inbuf, &inlen, &outbuf, &outlen);
236 return (ret != (size_t) -1) ? out_buffer : line;
239 char *
240 encoding_convert(struct encoding *encoding, char *line)
242 return encoding_convert_string(encoding->cd, line);
245 const char *
246 encoding_iconv(iconv_t iconv_cd, const char *string)
248 char *instr = strdup(string);
249 const char *ret = encoding_convert_string(iconv_cd, instr);
251 free(instr);
252 return ret == instr ? string : ret;
256 * Executing external commands.
259 static void
260 io_init(struct io *io)
262 memset(io, 0, sizeof(*io));
263 io->pipe = -1;
266 bool
267 io_open(struct io *io, const char *fmt, ...)
269 char name[SIZEOF_STR] = "";
270 int retval;
272 io_init(io);
274 FORMAT_BUFFER(name, sizeof(name), fmt, retval, FALSE);
275 if (retval < 0) {
276 io->error = ENAMETOOLONG;
277 return FALSE;
280 io->pipe = *name ? open(name, O_RDONLY) : dup(STDIN_FILENO);
281 if (io->pipe == -1)
282 io->error = errno;
283 return io->pipe != -1;
286 bool
287 io_kill(struct io *io)
289 return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
292 bool
293 io_done(struct io *io)
295 pid_t pid = io->pid;
297 if (io->pipe != -1)
298 close(io->pipe);
299 free(io->buf);
300 io_init(io);
302 while (pid > 0) {
303 int status;
304 pid_t waiting = waitpid(pid, &status, 0);
306 if (waiting < 0) {
307 if (errno == EINTR)
308 continue;
309 io->error = errno;
310 return FALSE;
313 if (WEXITSTATUS(status)) {
314 io->status = WEXITSTATUS(status);
317 return waiting == pid &&
318 !WIFSIGNALED(status) &&
319 !io->status;
322 return TRUE;
325 static int
326 open_trace(int devnull, const char *argv[])
328 static const char *trace_file;
330 if (!trace_file) {
331 trace_file = getenv("TIG_TRACE");
332 if (!trace_file)
333 trace_file = "";
336 if (*trace_file) {
337 int fd = open(trace_file, O_RDWR | O_CREAT | O_APPEND, 0666);
338 int i;
340 for (i = 0; argv[i]; i++) {
341 if (write(fd, argv[i], strlen(argv[i])) == -1
342 || write(fd, " ", 1) == -1)
343 break;
345 if (argv[i] || write(fd, "\n", 1) == -1) {
346 close(fd);
347 return devnull;
350 return fd;
353 return devnull;
356 bool
357 io_run(struct io *io, enum io_type type, const char *dir, char * const env[], const char *argv[], ...)
359 int pipefds[2] = { -1, -1 };
360 va_list args;
361 bool read_from_stdin = type == IO_RD_STDIN;
363 io_init(io);
365 if (read_from_stdin)
366 type = IO_RD;
368 if (dir && !strcmp(dir, argv[0]))
369 return io_open(io, "%s%s", dir, argv[1]);
371 if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
372 io->error = errno;
373 return FALSE;
374 } else if (type == IO_AP) {
375 va_start(args, argv);
376 pipefds[1] = va_arg(args, int);
377 va_end(args);
380 if ((io->pid = fork())) {
381 if (io->pid == -1)
382 io->error = errno;
383 if (pipefds[!(type == IO_WR)] != -1)
384 close(pipefds[!(type == IO_WR)]);
385 if (io->pid != -1) {
386 io->pipe = pipefds[!!(type == IO_WR)];
387 return TRUE;
390 } else {
391 if (type != IO_FG) {
392 int devnull = open("/dev/null", O_RDWR);
393 int readfd = type == IO_WR ? pipefds[0] : devnull;
394 int writefd = (type == IO_RD || type == IO_AP)
395 ? pipefds[1] : devnull;
396 int errorfd = open_trace(devnull, argv);
398 /* Inject stdin given on the command line. */
399 if (read_from_stdin)
400 readfd = dup(STDIN_FILENO);
402 dup2(readfd, STDIN_FILENO);
403 dup2(writefd, STDOUT_FILENO);
404 dup2(errorfd, STDERR_FILENO);
406 if (devnull != errorfd)
407 close(errorfd);
408 close(devnull);
409 if (pipefds[0] != -1)
410 close(pipefds[0]);
411 if (pipefds[1] != -1)
412 close(pipefds[1]);
415 if (dir && *dir && chdir(dir) == -1)
416 exit(errno);
418 if (env) {
419 int i;
421 for (i = 0; env[i]; i++)
422 if (*env[i])
423 putenv(env[i]);
426 execvp(argv[0], (char *const*) argv);
427 exit(errno);
430 if (pipefds[!!(type == IO_WR)] != -1)
431 close(pipefds[!!(type == IO_WR)]);
432 return FALSE;
435 bool
436 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
438 struct io io;
440 return io_run(&io, type, dir, NULL, argv, fd) && io_done(&io);
443 bool
444 io_run_bg(const char **argv)
446 return io_complete(IO_BG, argv, NULL, -1);
449 bool
450 io_run_fg(const char **argv, const char *dir)
452 return io_complete(IO_FG, argv, dir, -1);
455 bool
456 io_run_append(const char **argv, int fd)
458 return io_complete(IO_AP, argv, NULL, fd);
461 bool
462 io_eof(struct io *io)
464 return io->eof;
468 io_error(struct io *io)
470 return io->error;
473 char *
474 io_strerror(struct io *io)
476 return strerror(io->error);
479 bool
480 io_can_read(struct io *io, bool can_block)
482 struct timeval tv = { 0, 500 };
483 fd_set fds;
485 FD_ZERO(&fds);
486 FD_SET(io->pipe, &fds);
488 return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
491 ssize_t
492 io_read(struct io *io, void *buf, size_t bufsize)
494 do {
495 ssize_t readsize = read(io->pipe, buf, bufsize);
497 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
498 continue;
499 else if (readsize == -1)
500 io->error = errno;
501 else if (readsize == 0)
502 io->eof = 1;
503 return readsize;
504 } while (1);
507 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
509 char *
510 io_get(struct io *io, int c, bool can_read)
512 char *eol;
513 ssize_t readsize;
515 while (TRUE) {
516 if (io->bufsize > 0) {
517 eol = memchr(io->bufpos, c, io->bufsize);
518 if (eol) {
519 char *line = io->bufpos;
521 *eol = 0;
522 io->bufpos = eol + 1;
523 io->bufsize -= io->bufpos - line;
524 return line;
528 if (io_eof(io)) {
529 if (io->bufsize) {
530 io->bufpos[io->bufsize] = 0;
531 io->bufsize = 0;
532 return io->bufpos;
534 return NULL;
537 if (!can_read)
538 return NULL;
540 if (io->bufsize > 0 && io->bufpos > io->buf)
541 memmove(io->buf, io->bufpos, io->bufsize);
543 if (io->bufalloc == io->bufsize) {
544 if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
545 return NULL;
546 io->bufalloc += BUFSIZ;
549 io->bufpos = io->buf;
550 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
551 if (io_error(io))
552 return NULL;
553 io->bufsize += readsize;
557 bool
558 io_write(struct io *io, const void *buf, size_t bufsize)
560 size_t written = 0;
562 while (!io_error(io) && written < bufsize) {
563 ssize_t size;
565 size = write(io->pipe, buf + written, bufsize - written);
566 if (size < 0 && (errno == EAGAIN || errno == EINTR))
567 continue;
568 else if (size == -1)
569 io->error = errno;
570 else
571 written += size;
574 return written == bufsize;
577 bool
578 io_printf(struct io *io, const char *fmt, ...)
580 char buf[SIZEOF_STR] = "";
581 int retval;
583 FORMAT_BUFFER(buf, sizeof(buf), fmt, retval, FALSE);
584 if (retval < 0) {
585 io->error = ENAMETOOLONG;
586 return FALSE;
589 return io_write(io, buf, retval);
592 bool
593 io_read_buf(struct io *io, char buf[], size_t bufsize)
595 char *result = io_get(io, '\n', TRUE);
597 if (result) {
598 result = chomp_string(result);
599 string_ncopy_do(buf, bufsize, result, strlen(result));
602 return io_done(io) && result;
605 bool
606 io_run_buf(const char **argv, char buf[], size_t bufsize)
608 struct io io;
610 return io_run(&io, IO_RD, NULL, NULL, argv) && io_read_buf(&io, buf, bufsize);
614 io_load(struct io *io, const char *separators,
615 io_read_fn read_property, void *data)
617 char *name;
618 int state = OK;
620 while (state == OK && (name = io_get(io, '\n', TRUE))) {
621 char *value;
622 size_t namelen;
623 size_t valuelen;
625 name = chomp_string(name);
626 namelen = strcspn(name, separators);
628 if (name[namelen]) {
629 name[namelen] = 0;
630 value = chomp_string(name + namelen + 1);
631 valuelen = strlen(value);
633 } else {
634 value = "";
635 valuelen = 0;
638 state = read_property(name, namelen, value, valuelen, data);
641 if (state != ERR && io_error(io))
642 state = ERR;
643 io_done(io);
645 return state;
649 io_run_load(const char **argv, const char *separators,
650 io_read_fn read_property, void *data)
652 struct io io;
654 if (!io_run(&io, IO_RD, NULL, NULL, argv))
655 return ERR;
656 return io_load(&io, separators, read_property, data);
659 /* vim: set ts=8 sw=8 noexpandtab: */