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.
18 argv_to_string(const char *argv
[SIZEOF_ARG
], char *buf
, size_t buflen
, const char *sep
)
22 for (bufpos
= 0, argc
= 0; argv
[argc
]; argc
++)
23 if (!string_nformat(buf
, buflen
, &bufpos
, "%s%s",
24 argc
? sep
: "", argv
[argc
]))
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
);
39 return valuelen
> 0 ? valuelen
+ 2 : strlen(arg
);
43 return strcspn(arg
, " \t");
48 split_argv_string(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
, bool remove_quotes
)
50 while (*cmd
&& *argc
< SIZEOF_ARG
) {
52 int valuelen
= get_arg_valuelen(cmd
, "ed
);
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
)
63 return *argc
< SIZEOF_ARG
;
67 argv_from_string_no_quotes(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
)
69 return split_argv_string(argv
, argc
, cmd
, TRUE
);
73 argv_from_string(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
)
75 return split_argv_string(argv
, argc
, cmd
, FALSE
);
79 argv_from_env(const char **argv
, const char *name
)
81 char *env
= argv
? getenv(name
) : NULL
;
86 return !env
|| argv_from_string(argv
, &argc
, env
);
90 argv_free(const char *argv
[])
96 for (argc
= 0; argv
[argc
]; argc
++)
97 free((void *) argv
[argc
]);
102 argv_size(const char **argv
)
106 while (argv
&& argv
[argc
])
113 argv_contains(const char **argv
, const char *arg
)
117 for (i
= 0; argv
&& argv
[i
]; i
++)
118 if (!strcmp(argv
[i
], arg
))
123 DEFINE_ALLOCATOR(argv_realloc
, const char *, SIZEOF_ARG
)
126 argv_append(const char ***argv
, const char *arg
)
128 size_t argc
= argv_size(*argv
);
131 if (!*arg
&& argc
> 0)
134 if (!argv_realloc(argv
, argc
, 2))
139 (*argv
)[argc
++] = alloc
;
140 (*argv
)[argc
] = NULL
;
142 return alloc
!= NULL
;
146 argv_append_array(const char ***dst_argv
, const char *src_argv
[])
150 for (i
= 0; src_argv
&& src_argv
[i
]; i
++)
151 if (!argv_append(dst_argv
, src_argv
[i
]))
157 argv_remove_quotes(const char *argv
[])
161 for (argc
= 0; argv
[argc
]; argc
++) {
163 const char *arg
= argv
[argc
];
164 int arglen
= get_arg_valuelen(arg
, "ed
);
165 int unquotedlen
= arglen
- 1 - (arg
[arglen
- 1] == quoted
);
171 unquoted
= malloc(unquotedlen
+ 1);
174 strncpy(unquoted
, arg
+ 1, unquotedlen
);
175 unquoted
[unquotedlen
] = 0;
177 argv
[argc
] = unquoted
;
184 argv_copy(const char ***dst
, const char *src
[])
189 for (argc
= 0; src
[argc
]; argc
++)
190 if (!argv_append(dst
, src
[argc
]))
196 * Encoding conversion.
200 struct encoding
*next
;
205 static struct encoding
*encodings
;
208 encoding_open(const char *fromcode
)
210 struct encoding
*encoding
;
211 size_t len
= strlen(fromcode
);
216 for (encoding
= encodings
; encoding
; encoding
= encoding
->next
) {
217 if (!strcasecmp(encoding
->fromcode
, fromcode
))
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
) {
229 encoding
->next
= encodings
;
230 encodings
= encoding
;
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
;
251 encoding_convert(struct encoding
*encoding
, char *line
)
253 return encoding_convert_string(encoding
->cd
, line
);
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
);
263 return ret
== instr
? string
: ret
;
267 * Executing external commands.
271 io_init(struct io
*io
)
273 memset(io
, 0, sizeof(*io
));
278 io_open(struct io
*io
, const char *fmt
, ...)
280 char name
[SIZEOF_STR
] = "";
285 FORMAT_BUFFER(name
, sizeof(name
), fmt
, retval
, FALSE
);
287 io
->error
= ENAMETOOLONG
;
291 io
->pipe
= *name
? open(name
, O_RDONLY
) : dup(STDIN_FILENO
);
294 return io
->pipe
!= -1;
298 io_kill(struct io
*io
)
300 return io
->pid
== 0 || kill(io
->pid
, SIGKILL
) != -1;
304 io_done(struct io
*io
)
315 pid_t waiting
= waitpid(pid
, &status
, 0);
324 if (WEXITSTATUS(status
)) {
325 io
->status
= WEXITSTATUS(status
);
328 return waiting
== pid
&&
329 !WIFSIGNALED(status
) &&
337 open_trace(int devnull
, const char *argv
[])
339 static const char *trace_file
;
342 trace_file
= getenv("TIG_TRACE");
348 int fd
= open(trace_file
, O_RDWR
| O_CREAT
| O_APPEND
, 0666);
351 for (i
= 0; argv
[i
]; i
++) {
352 if (write(fd
, argv
[i
], strlen(argv
[i
])) == -1
353 || write(fd
, " ", 1) == -1)
356 if (argv
[i
] || write(fd
, "\n", 1) == -1) {
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 };
372 bool read_from_stdin
= type
== IO_RD_STDIN
;
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) {
385 } else if (type
== IO_AP
) {
386 va_start(args
, argv
);
387 pipefds
[1] = va_arg(args
, int);
391 if ((io
->pid
= fork())) {
394 if (pipefds
[!(type
== IO_WR
)] != -1)
395 close(pipefds
[!(type
== IO_WR
)]);
397 io
->pipe
= pipefds
[!!(type
== IO_WR
)];
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. */
411 readfd
= dup(STDIN_FILENO
);
413 dup2(readfd
, STDIN_FILENO
);
414 dup2(writefd
, STDOUT_FILENO
);
415 dup2(errorfd
, STDERR_FILENO
);
417 if (devnull
!= errorfd
)
420 if (pipefds
[0] != -1)
422 if (pipefds
[1] != -1)
426 if (dir
&& *dir
&& chdir(dir
) == -1)
432 for (i
= 0; env
[i
]; i
++)
437 execvp(argv
[0], (char *const*) argv
);
441 if (pipefds
[!!(type
== IO_WR
)] != -1)
442 close(pipefds
[!!(type
== IO_WR
)]);
447 io_complete(enum io_type type
, const char **argv
, const char *dir
, int fd
)
451 return io_run(&io
, type
, dir
, NULL
, argv
, fd
) && io_done(&io
);
455 io_run_bg(const char **argv
)
457 return io_complete(IO_BG
, argv
, NULL
, -1);
461 io_run_fg(const char **argv
, const char *dir
)
463 return io_complete(IO_FG
, argv
, dir
, -1);
467 io_run_append(const char **argv
, int fd
)
469 return io_complete(IO_AP
, argv
, NULL
, fd
);
473 io_eof(struct io
*io
)
479 io_error(struct io
*io
)
485 io_strerror(struct io
*io
)
487 return strerror(io
->error
);
491 io_can_read(struct io
*io
, bool can_block
)
493 struct timeval tv
= { 0, 500 };
497 FD_SET(io
->pipe
, &fds
);
499 return select(io
->pipe
+ 1, &fds
, NULL
, NULL
, can_block
? NULL
: &tv
) > 0;
503 io_read(struct io
*io
, void *buf
, size_t bufsize
)
506 ssize_t readsize
= read(io
->pipe
, buf
, bufsize
);
508 if (readsize
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
510 else if (readsize
== -1)
512 else if (readsize
== 0)
518 DEFINE_ALLOCATOR(io_realloc_buf
, char, BUFSIZ
)
521 io_get(struct io
*io
, int c
, bool can_read
)
527 if (io
->bufsize
> 0) {
528 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
530 char *line
= io
->bufpos
;
533 io
->bufpos
= eol
+ 1;
534 io
->bufsize
-= io
->bufpos
- line
;
541 io
->bufpos
[io
->bufsize
] = 0;
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
))
557 io
->bufalloc
+= BUFSIZ
;
560 io
->bufpos
= io
->buf
;
561 readsize
= io_read(io
, io
->buf
+ io
->bufsize
, io
->bufalloc
- io
->bufsize
);
564 io
->bufsize
+= readsize
;
569 io_write(struct io
*io
, const void *buf
, size_t bufsize
)
573 while (!io_error(io
) && written
< bufsize
) {
576 size
= write(io
->pipe
, buf
+ written
, bufsize
- written
);
577 if (size
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
585 return written
== bufsize
;
589 io_printf(struct io
*io
, const char *fmt
, ...)
591 char buf
[SIZEOF_STR
] = "";
594 FORMAT_BUFFER(buf
, sizeof(buf
), fmt
, retval
, FALSE
);
596 io
->error
= ENAMETOOLONG
;
600 return io_write(io
, buf
, retval
);
604 io_read_buf(struct io
*io
, char buf
[], size_t bufsize
)
606 char *result
= io_get(io
, '\n', TRUE
);
609 result
= chomp_string(result
);
610 string_ncopy_do(buf
, bufsize
, result
, strlen(result
));
613 return io_done(io
) && result
;
617 io_run_buf(const char **argv
, char buf
[], size_t bufsize
)
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
)
631 while (state
== OK
&& (name
= io_get(io
, '\n', TRUE
))) {
636 name
= chomp_string(name
);
637 namelen
= strcspn(name
, separators
);
641 value
= chomp_string(name
+ namelen
+ 1);
642 valuelen
= strlen(value
);
649 state
= read_property(name
, namelen
, value
, valuelen
, data
);
652 if (state
!= ERR
&& io_error(io
))
660 io_run_load(const char **argv
, const char *separators
,
661 io_read_fn read_property
, void *data
)
665 if (!io_run(&io
, IO_RD
, NULL
, NULL
, argv
))
667 return io_load(&io
, separators
, read_property
, data
);
670 /* vim: set ts=8 sw=8 noexpandtab: */