Replace strndup(3) usage with malloc + strncpy
[tig.git] / io.c
blob2d96aeb4934331e221e5fa8a73428501402fbfe5
1 /* Copyright (c) 2006-2012 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, const char *argv[], ...)
343 int pipefds[2] = { -1, -1 };
344 va_list args;
346 io_init(io);
348 if (dir && !strcmp(dir, argv[0]))
349 return io_open(io, "%s%s", dir, argv[1]);
351 if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
352 io->error = errno;
353 return FALSE;
354 } else if (type == IO_AP) {
355 va_start(args, argv);
356 pipefds[1] = va_arg(args, int);
357 va_end(args);
360 if ((io->pid = fork())) {
361 if (io->pid == -1)
362 io->error = errno;
363 if (pipefds[!(type == IO_WR)] != -1)
364 close(pipefds[!(type == IO_WR)]);
365 if (io->pid != -1) {
366 io->pipe = pipefds[!!(type == IO_WR)];
367 return TRUE;
370 } else {
371 if (type != IO_FG) {
372 int devnull = open("/dev/null", O_RDWR);
373 int readfd = type == IO_WR ? pipefds[0] : devnull;
374 int writefd = (type == IO_RD || type == IO_AP)
375 ? pipefds[1] : devnull;
376 int errorfd = open_trace(devnull, argv);
378 dup2(readfd, STDIN_FILENO);
379 dup2(writefd, STDOUT_FILENO);
380 dup2(errorfd, STDERR_FILENO);
382 if (devnull != errorfd)
383 close(errorfd);
384 close(devnull);
385 if (pipefds[0] != -1)
386 close(pipefds[0]);
387 if (pipefds[1] != -1)
388 close(pipefds[1]);
391 if (dir && *dir && chdir(dir) == -1)
392 exit(errno);
394 execvp(argv[0], (char *const*) argv);
395 exit(errno);
398 if (pipefds[!!(type == IO_WR)] != -1)
399 close(pipefds[!!(type == IO_WR)]);
400 return FALSE;
403 bool
404 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
406 struct io io;
408 return io_run(&io, type, dir, argv, fd) && io_done(&io);
411 bool
412 io_run_bg(const char **argv)
414 return io_complete(IO_BG, argv, NULL, -1);
417 bool
418 io_run_fg(const char **argv, const char *dir)
420 return io_complete(IO_FG, argv, dir, -1);
423 bool
424 io_run_append(const char **argv, int fd)
426 return io_complete(IO_AP, argv, NULL, fd);
429 bool
430 io_eof(struct io *io)
432 return io->eof;
436 io_error(struct io *io)
438 return io->error;
441 char *
442 io_strerror(struct io *io)
444 return strerror(io->error);
447 bool
448 io_can_read(struct io *io, bool can_block)
450 struct timeval tv = { 0, 500 };
451 fd_set fds;
453 FD_ZERO(&fds);
454 FD_SET(io->pipe, &fds);
456 return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
459 ssize_t
460 io_read(struct io *io, void *buf, size_t bufsize)
462 do {
463 ssize_t readsize = read(io->pipe, buf, bufsize);
465 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
466 continue;
467 else if (readsize == -1)
468 io->error = errno;
469 else if (readsize == 0)
470 io->eof = 1;
471 return readsize;
472 } while (1);
475 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
477 char *
478 io_get(struct io *io, int c, bool can_read)
480 char *eol;
481 ssize_t readsize;
483 while (TRUE) {
484 if (io->bufsize > 0) {
485 eol = memchr(io->bufpos, c, io->bufsize);
486 if (eol) {
487 char *line = io->bufpos;
489 *eol = 0;
490 io->bufpos = eol + 1;
491 io->bufsize -= io->bufpos - line;
492 return line;
496 if (io_eof(io)) {
497 if (io->bufsize) {
498 io->bufpos[io->bufsize] = 0;
499 io->bufsize = 0;
500 return io->bufpos;
502 return NULL;
505 if (!can_read)
506 return NULL;
508 if (io->bufsize > 0 && io->bufpos > io->buf)
509 memmove(io->buf, io->bufpos, io->bufsize);
511 if (io->bufalloc == io->bufsize) {
512 if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
513 return NULL;
514 io->bufalloc += BUFSIZ;
517 io->bufpos = io->buf;
518 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
519 if (io_error(io))
520 return NULL;
521 io->bufsize += readsize;
525 bool
526 io_write(struct io *io, const void *buf, size_t bufsize)
528 size_t written = 0;
530 while (!io_error(io) && written < bufsize) {
531 ssize_t size;
533 size = write(io->pipe, buf + written, bufsize - written);
534 if (size < 0 && (errno == EAGAIN || errno == EINTR))
535 continue;
536 else if (size == -1)
537 io->error = errno;
538 else
539 written += size;
542 return written == bufsize;
545 bool
546 io_printf(struct io *io, const char *fmt, ...)
548 char buf[SIZEOF_STR] = "";
549 int retval;
551 FORMAT_BUFFER(buf, sizeof(buf), fmt, retval, FALSE);
552 if (retval < 0) {
553 io->error = ENAMETOOLONG;
554 return FALSE;
557 return io_write(io, buf, retval);
560 bool
561 io_read_buf(struct io *io, char buf[], size_t bufsize)
563 char *result = io_get(io, '\n', TRUE);
565 if (result) {
566 result = chomp_string(result);
567 string_ncopy_do(buf, bufsize, result, strlen(result));
570 return io_done(io) && result;
573 bool
574 io_run_buf(const char **argv, char buf[], size_t bufsize)
576 struct io io;
578 return io_run(&io, IO_RD, NULL, argv) && io_read_buf(&io, buf, bufsize);
582 io_load(struct io *io, const char *separators,
583 io_read_fn read_property, void *data)
585 char *name;
586 int state = OK;
588 while (state == OK && (name = io_get(io, '\n', TRUE))) {
589 char *value;
590 size_t namelen;
591 size_t valuelen;
593 name = chomp_string(name);
594 namelen = strcspn(name, separators);
596 if (name[namelen]) {
597 name[namelen] = 0;
598 value = chomp_string(name + namelen + 1);
599 valuelen = strlen(value);
601 } else {
602 value = "";
603 valuelen = 0;
606 state = read_property(name, namelen, value, valuelen, data);
609 if (state != ERR && io_error(io))
610 state = ERR;
611 io_done(io);
613 return state;
617 io_run_load(const char **argv, const char *separators,
618 io_read_fn read_property, void *data)
620 struct io io;
622 if (!io_run(&io, IO_RD, NULL, argv))
623 return ERR;
624 return io_load(&io, separators, read_property, data);