Fix the help tests
[tig.git] / src / io.c
blobe2eb162cad96f99d8bbc108c3b1a687242b174cc
1 /* Copyright (c) 2006-2015 Jonas Fonseca <jonas.fonseca@gmail.com>
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/tig.h"
15 #include "tig/util.h"
16 #include "tig/io.h"
19 * Encoding conversion.
22 #define ENCODING_SEP ": encoding: "
23 #define ENCODING_ARG "--encoding=" ENCODING_UTF8
25 #define CHARSET_SEP "; charset="
27 struct encoding {
28 struct encoding *next;
29 iconv_t cd;
30 char fromcode[1];
33 char encoding_arg[] = ENCODING_ARG;
34 struct encoding *default_encoding;
35 static struct encoding *encodings;
37 struct encoding *
38 encoding_open(const char *fromcode)
40 struct encoding *encoding;
41 size_t len = strlen(fromcode);
43 if (!*fromcode)
44 return NULL;
46 for (encoding = encodings; encoding; encoding = encoding->next) {
47 if (!strcasecmp(encoding->fromcode, fromcode))
48 return encoding;
51 encoding = calloc(1, sizeof(*encoding) + len);
52 strncpy(encoding->fromcode, fromcode, len);
53 encoding->cd = iconv_open(ENCODING_UTF8, fromcode);
54 if (encoding->cd == ICONV_NONE) {
55 free(encoding);
56 return NULL;
59 encoding->next = encodings;
60 encodings = encoding;
62 return encoding;
65 static bool
66 encoding_convert_string(iconv_t iconv_cd, struct buffer *buf)
68 static char out_buffer[BUFSIZ * 2];
69 ICONV_CONST char *inbuf = buf->data;
70 size_t inlen = buf->size + 1;
72 char *outbuf = out_buffer;
73 size_t outlen = sizeof(out_buffer);
75 size_t ret = iconv(iconv_cd, &inbuf, &inlen, &outbuf, &outlen);
76 if (ret != (size_t) -1) {
77 buf->data = out_buffer;
78 buf->size = sizeof(out_buffer) - outlen;
81 return (ret != (size_t) -1);
84 bool
85 encoding_convert(struct encoding *encoding, struct buffer *buf)
87 return encoding_convert_string(encoding->cd, buf);
90 const char *
91 encoding_iconv(iconv_t iconv_cd, const char *string, size_t length)
93 char *instr = strndup(string, length);
94 struct buffer buf = { instr, length };
95 const char *ret = buf.data && encoding_convert_string(iconv_cd, &buf) ? buf.data : string;
97 free(instr);
98 return ret == instr ? string : ret;
101 struct encoding *
102 get_path_encoding(const char *path, struct encoding *default_encoding)
104 const char *check_attr_argv[] = {
105 "git", "check-attr", "encoding", "--", path, NULL
107 char buf[SIZEOF_STR];
108 char *encoding;
110 /* <path>: encoding: <encoding> */
112 if (!*path || !io_run_buf(check_attr_argv, buf, sizeof(buf), false)
113 || !(encoding = strstr(buf, ENCODING_SEP)))
114 return default_encoding;
116 encoding += STRING_SIZE(ENCODING_SEP);
117 if (!strcmp(encoding, ENCODING_UTF8)
118 || !strcmp(encoding, "unspecified")
119 || !strcmp(encoding, "set")) {
120 const char *file_argv[] = {
121 "file", "-I", "--", path, NULL
124 if (!*path || !io_run_buf(file_argv, buf, sizeof(buf), false)
125 || !(encoding = strstr(buf, CHARSET_SEP)))
126 return default_encoding;
128 encoding += STRING_SIZE(CHARSET_SEP);
131 return encoding_open(encoding);
135 * Executing external commands.
138 static void
139 io_init(struct io *io)
141 memset(io, 0, sizeof(*io));
142 io->pipe = -1;
145 bool
146 io_open(struct io *io, const char *fmt, ...)
148 char name[SIZEOF_STR] = "";
149 int retval;
151 io_init(io);
153 FORMAT_BUFFER(name, sizeof(name), fmt, retval, false);
154 if (retval < 0) {
155 io->error = ENAMETOOLONG;
156 return false;
159 io->pipe = *name ? open(name, O_RDONLY) : dup(STDIN_FILENO);
160 if (io->pipe == -1)
161 io->error = errno;
162 return io->pipe != -1;
165 bool
166 io_kill(struct io *io)
168 return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
171 bool
172 io_done(struct io *io)
174 pid_t pid = io->pid;
176 if (io->pipe != -1)
177 close(io->pipe);
178 free(io->buf);
179 io_init(io);
181 while (pid > 0) {
182 int status;
183 pid_t waiting = waitpid(pid, &status, 0);
185 if (waiting < 0) {
186 if (errno == EINTR)
187 continue;
188 io->error = errno;
189 return false;
192 if (WEXITSTATUS(status)) {
193 io->status = WEXITSTATUS(status);
196 return waiting == pid &&
197 !WIFSIGNALED(status) &&
198 !io->status;
201 return true;
204 static int
205 open_trace(int devnull, const char *argv[])
207 static const char *trace_file;
209 if (!trace_file) {
210 trace_file = getenv("TIG_TRACE");
211 if (!trace_file)
212 trace_file = "";
215 if (*trace_file) {
216 int fd = open(trace_file, O_RDWR | O_CREAT | O_APPEND, 0666);
217 int i;
219 for (i = 0; argv[i]; i++) {
220 if (write(fd, argv[i], strlen(argv[i])) == -1
221 || write(fd, " ", 1) == -1)
222 break;
224 if (argv[i] || write(fd, "\n", 1) == -1) {
225 close(fd);
226 return devnull;
229 return fd;
232 return devnull;
235 bool
236 io_trace(const char *fmt, ...)
238 static FILE *trace_out; /* Intensionally leaked. */
239 va_list args;
240 int retval;
242 if (!trace_out) {
243 const char *trace_file = getenv("TIG_TRACE");
245 if (trace_file)
246 trace_out = fopen(trace_file, "a");
247 if (!trace_out)
248 return false;
251 va_start(args, fmt);
252 retval = vfprintf(trace_out, fmt, args);
253 va_end(args);
254 fflush(trace_out);
256 return retval != -1;
259 bool
260 io_exec(struct io *io, enum io_type type, const char *dir, char * const env[], const char *argv[], int custom)
262 int pipefds[2] = { -1, -1 };
263 bool read_from_stdin = type == IO_RD && (custom & IO_RD_FORWARD_STDIN);
264 bool read_with_stderr = type == IO_RD && (custom & IO_RD_WITH_STDERR);
266 io_init(io);
268 if (dir && !strcmp(dir, argv[0]))
269 return io_open(io, "%s%s", dir, argv[1]);
271 if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
272 io->error = errno;
273 return false;
274 } else if (type == IO_AP) {
275 pipefds[1] = custom;
278 if ((io->pid = fork())) {
279 if (io->pid == -1)
280 io->error = errno;
281 if (pipefds[!(type == IO_WR)] != -1)
282 close(pipefds[!(type == IO_WR)]);
283 if (io->pid != -1) {
284 io->pipe = pipefds[!!(type == IO_WR)];
285 return true;
288 } else {
289 if (type != IO_FG) {
290 int devnull = open("/dev/null", O_RDWR);
291 int readfd = type == IO_WR ? pipefds[0] : devnull;
292 int writefd = (type == IO_RD || type == IO_AP)
293 ? pipefds[1] : devnull;
294 int errorfd = open_trace(devnull, argv);
296 /* Inject stdin given on the command line. */
297 if (read_from_stdin)
298 readfd = dup(STDIN_FILENO);
300 dup2(readfd, STDIN_FILENO);
301 dup2(writefd, STDOUT_FILENO);
302 if (read_with_stderr)
303 dup2(writefd, STDERR_FILENO);
304 else
305 dup2(errorfd, STDERR_FILENO);
307 if (devnull != errorfd)
308 close(errorfd);
309 close(devnull);
310 if (pipefds[0] != -1)
311 close(pipefds[0]);
312 if (pipefds[1] != -1)
313 close(pipefds[1]);
316 if (dir && *dir && chdir(dir) == -1)
317 exit(errno);
319 if (env) {
320 int i;
322 for (i = 0; env[i]; i++)
323 if (*env[i])
324 putenv(env[i]);
327 execvp(argv[0], (char *const*) argv);
328 exit(errno);
331 if (pipefds[!!(type == IO_WR)] != -1)
332 close(pipefds[!!(type == IO_WR)]);
333 return false;
336 bool
337 io_run(struct io *io, enum io_type type, const char *dir, char * const env[], const char *argv[])
339 return io_exec(io, type, dir, env, argv, 0);
342 bool
343 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
345 struct io io;
347 return io_exec(&io, type, dir, NULL, argv, fd) && io_done(&io);
350 bool
351 io_run_bg(const char **argv, const char *dir)
353 return io_complete(IO_BG, argv, dir, -1);
356 bool
357 io_run_fg(const char **argv, const char *dir)
359 return io_complete(IO_FG, argv, dir, -1);
362 bool
363 io_run_append(const char **argv, int fd)
365 return io_complete(IO_AP, argv, NULL, fd);
368 bool
369 io_eof(struct io *io)
371 return io->eof;
375 io_error(struct io *io)
377 return io->error;
380 char *
381 io_strerror(struct io *io)
383 return strerror(io->error);
386 bool
387 io_can_read(struct io *io, bool can_block)
389 struct timeval tv = { 0, 500 };
390 fd_set fds;
392 FD_ZERO(&fds);
393 FD_SET(io->pipe, &fds);
395 return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
398 ssize_t
399 io_read(struct io *io, void *buf, size_t bufsize)
401 do {
402 ssize_t readsize = read(io->pipe, buf, bufsize);
404 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
405 continue;
406 else if (readsize == -1)
407 io->error = errno;
408 else if (readsize == 0)
409 io->eof = 1;
410 return readsize;
411 } while (1);
414 char *
415 io_memchr(struct buffer *buf, char *data, int c)
417 char *pos;
419 if (!buf || data < buf->data || buf->data + buf->size <= data)
420 return NULL;
422 pos = memchr(data, c, buf->size - (data - buf->data));
423 return pos ? pos + 1 : NULL;
426 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
428 static bool
429 io_get_line(struct io *io, struct buffer *buf, int c, size_t *lineno, bool can_read)
431 char *eol;
432 ssize_t readsize;
434 while (true) {
435 if (io->bufsize > 0) {
436 eol = memchr(io->bufpos, c, io->bufsize);
438 while (io->span && io->bufpos < eol && eol[-1] == '\\') {
439 if (lineno)
440 (*lineno)++;
441 eol[-1] = eol[0] = ' ';
442 eol = memchr(io->bufpos, c, io->bufsize);
444 if (eol) {
445 buf->data = io->bufpos;
446 buf->size = eol - buf->data;
448 *eol = 0;
449 io->bufpos = eol + 1;
450 io->bufsize -= io->bufpos - buf->data;
451 if (lineno)
452 (*lineno)++;
453 return true;
457 if (io_eof(io)) {
458 if (io->bufsize) {
459 buf->data = io->bufpos;
460 buf->size = io->bufsize;
462 io->bufpos[io->bufsize] = 0;
463 io->bufpos += io->bufsize;
464 io->bufsize = 0;
465 if (lineno)
466 (*lineno)++;
467 return true;
469 return false;
472 if (!can_read)
473 return false;
475 if (io->bufsize > 0 && io->bufpos > io->buf)
476 memmove(io->buf, io->bufpos, io->bufsize);
478 if (io->bufalloc == io->bufsize) {
479 if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
480 return false;
481 io->bufalloc += BUFSIZ;
484 io->bufpos = io->buf;
485 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
486 if (io_error(io))
487 return NULL;
488 io->bufsize += readsize;
492 bool
493 io_get(struct io *io, struct buffer *buf, int c, bool can_read)
495 return io_get_line(io, buf, c, NULL, can_read);
498 bool
499 io_write(struct io *io, const void *buf, size_t bufsize)
501 const char *bytes = buf;
502 size_t written = 0;
504 while (!io_error(io) && written < bufsize) {
505 ssize_t size;
507 size = write(io->pipe, bytes + written, bufsize - written);
508 if (size < 0 && (errno == EAGAIN || errno == EINTR))
509 continue;
510 else if (size == -1)
511 io->error = errno;
512 else
513 written += size;
516 return written == bufsize;
519 bool
520 io_printf(struct io *io, const char *fmt, ...)
522 char buf[SIZEOF_STR] = "";
523 int retval;
525 FORMAT_BUFFER(buf, sizeof(buf), fmt, retval, false);
526 if (retval < 0) {
527 io->error = ENAMETOOLONG;
528 return false;
531 return io_write(io, buf, retval);
534 bool
535 io_read_buf(struct io *io, char buf[], size_t bufsize, bool allow_empty)
537 struct buffer result = {0};
539 if (io_get(io, &result, '\n', true)) {
540 result.data = chomp_string(result.data);
541 string_ncopy_do(buf, bufsize, result.data, strlen(result.data));
544 return io_done(io) && (result.data || allow_empty);
547 bool
548 io_run_buf(const char **argv, char buf[], size_t bufsize, bool allow_empty)
550 struct io io;
552 return io_run(&io, IO_RD, NULL, NULL, argv) && io_read_buf(&io, buf, bufsize, allow_empty);
555 bool
556 io_from_string(struct io *io, const char *str)
558 size_t len = strlen(str);
560 io_init(io);
562 if (!io_realloc_buf(&io->buf, io->bufalloc, len))
563 return false;
565 io->bufsize = io->bufalloc = len;
566 io->bufpos = io->buf;
567 io->eof = true;
568 strncpy(io->buf, str, len);
570 return true;
573 static enum status_code
574 io_load_file(struct io *io, const char *separators,
575 size_t *lineno, io_read_fn read_property, void *data)
577 struct buffer buf;
578 enum status_code state = SUCCESS;
580 while (state == SUCCESS && io_get_line(io, &buf, '\n', lineno, true)) {
581 char *name;
582 char *value;
583 size_t namelen;
584 size_t valuelen;
586 name = chomp_string(buf.data);
587 namelen = strcspn(name, separators);
589 if (name[namelen]) {
590 name[namelen] = 0;
591 value = chomp_string(name + namelen + 1);
592 valuelen = strlen(value);
594 } else {
595 value = "";
596 valuelen = 0;
599 state = read_property(name, namelen, value, valuelen, data);
602 if (state == SUCCESS && io_error(io))
603 state = error("%s", io_strerror(io));
604 io_done(io);
606 return state;
609 enum status_code
610 io_load_span(struct io *io, const char *separators, size_t *lineno,
611 io_read_fn read_property, void *data)
613 io->span = true;
614 return io_load_file(io, separators, lineno, read_property, data);
617 enum status_code
618 io_load(struct io *io, const char *separators,
619 io_read_fn read_property, void *data)
621 return io_load_file(io, separators, NULL, read_property, data);
624 enum status_code
625 io_run_load(const char **argv, const char *separators,
626 io_read_fn read_property, void *data)
628 struct io io;
630 if (!io_run(&io, IO_RD, NULL, NULL, argv))
631 return error("Failed to open IO");
632 return io_load(&io, separators, read_property, data);
635 bool
636 io_fprintf(FILE *file, const char *fmt, ...)
638 va_list args;
639 int fmtlen, retval;
641 va_start(args, fmt);
642 fmtlen = vsnprintf(NULL, 0, fmt, args);
643 va_end(args);
645 va_start(args, fmt);
646 retval = vfprintf(file, fmt, args);
647 va_end(args);
649 return fmtlen == retval;
652 const char *
653 get_temp_dir(void)
655 static const char *tmp;
657 if (tmp)
658 return tmp;
660 if (!tmp)
661 tmp = getenv("TMPDIR");
662 if (!tmp)
663 tmp = getenv("TEMP");
664 if (!tmp)
665 tmp = getenv("TMP");
666 if (!tmp)
667 tmp = "/tmp";
669 return tmp;
672 /* vim: set ts=8 sw=8 noexpandtab: */