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.
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
, bool *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
);
41 return strcspn(arg
, " \t");
46 split_argv_string(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
, bool remove_quotes
)
48 while (*cmd
&& *argc
< SIZEOF_ARG
) {
50 int valuelen
= get_arg_valuelen(cmd
, "ed
);
51 bool advance
= cmd
[valuelen
] != 0;
52 int quote_offset
= !!(quoted
&& remove_quotes
);
54 cmd
[valuelen
- quote_offset
] = 0;
55 argv
[(*argc
)++] = chomp_string(cmd
+ quote_offset
);
56 cmd
= chomp_string(cmd
+ valuelen
+ advance
);
59 if (*argc
< SIZEOF_ARG
)
61 return *argc
< SIZEOF_ARG
;
65 argv_from_string_no_quotes(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
)
67 return split_argv_string(argv
, argc
, cmd
, TRUE
);
71 argv_from_string(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
)
73 return split_argv_string(argv
, argc
, cmd
, FALSE
);
77 argv_from_env(const char **argv
, const char *name
)
79 char *env
= argv
? getenv(name
) : NULL
;
84 return !env
|| argv_from_string(argv
, &argc
, env
);
88 argv_free(const char *argv
[])
94 for (argc
= 0; argv
[argc
]; argc
++)
95 free((void *) argv
[argc
]);
100 argv_size(const char **argv
)
104 while (argv
&& argv
[argc
])
110 DEFINE_ALLOCATOR(argv_realloc
, const char *, SIZEOF_ARG
)
113 argv_append(const char ***argv
, const char *arg
)
115 size_t argc
= argv_size(*argv
);
117 if (!*arg
&& argc
> 0)
120 if (!argv_realloc(argv
, argc
, 2))
123 (*argv
)[argc
++] = strdup(arg
);
124 (*argv
)[argc
] = NULL
;
129 argv_append_array(const char ***dst_argv
, const char *src_argv
[])
133 for (i
= 0; src_argv
&& src_argv
[i
]; i
++)
134 if (!argv_append(dst_argv
, src_argv
[i
]))
140 argv_copy(const char ***dst
, const char *src
[])
145 for (argc
= 0; src
[argc
]; argc
++)
146 if (!argv_append(dst
, src
[argc
]))
152 * Encoding conversion.
156 struct encoding
*next
;
161 static struct encoding
*encodings
;
164 encoding_open(const char *fromcode
)
166 struct encoding
*encoding
;
167 size_t len
= strlen(fromcode
);
172 for (encoding
= encodings
; encoding
; encoding
= encoding
->next
) {
173 if (!strcasecmp(encoding
->fromcode
, fromcode
))
177 encoding
= calloc(1, sizeof(*encoding
) + len
);
178 strncpy(encoding
->fromcode
, fromcode
, len
);
179 encoding
->cd
= iconv_open(ENCODING_UTF8
, fromcode
);
180 if (encoding
->cd
== ICONV_NONE
) {
185 encoding
->next
= encodings
;
186 encodings
= encoding
;
192 encoding_convert(struct encoding
*encoding
, char *line
)
194 static char out_buffer
[BUFSIZ
* 2];
195 ICONV_CONST
char *inbuf
= line
;
196 size_t inlen
= strlen(line
) + 1;
198 char *outbuf
= out_buffer
;
199 size_t outlen
= sizeof(out_buffer
);
201 size_t ret
= iconv(encoding
->cd
, &inbuf
, &inlen
, &outbuf
, &outlen
);
203 return (ret
!= (size_t) -1) ? out_buffer
: line
;
207 * Executing external commands.
211 io_init(struct io
*io
)
213 memset(io
, 0, sizeof(*io
));
218 io_open(struct io
*io
, const char *fmt
, ...)
220 char name
[SIZEOF_STR
] = "";
225 FORMAT_BUFFER(name
, sizeof(name
), fmt
, retval
, FALSE
);
227 io
->error
= ENAMETOOLONG
;
231 io
->pipe
= *name
? open(name
, O_RDONLY
) : dup(STDIN_FILENO
);
234 return io
->pipe
!= -1;
238 io_kill(struct io
*io
)
240 return io
->pid
== 0 || kill(io
->pid
, SIGKILL
) != -1;
244 io_done(struct io
*io
)
255 pid_t waiting
= waitpid(pid
, &status
, 0);
264 if (WEXITSTATUS(status
)) {
265 io
->status
= WEXITSTATUS(status
);
268 return waiting
== pid
&&
269 !WIFSIGNALED(status
) &&
277 open_trace(int devnull
, const char *argv
[])
279 static const char *trace_file
;
282 trace_file
= getenv("TIG_TRACE");
288 int fd
= open(trace_file
, O_RDWR
| O_CREAT
| O_APPEND
, 0666);
291 for (i
= 0; argv
[i
]; i
++) {
292 if (write(fd
, argv
[i
], strlen(argv
[i
])) == -1
293 || write(fd
, " ", 1) == -1)
296 if (argv
[i
] || write(fd
, "\n", 1) == -1) {
308 io_run(struct io
*io
, enum io_type type
, const char *dir
, const char *argv
[], ...)
310 int pipefds
[2] = { -1, -1 };
315 if (dir
&& !strcmp(dir
, argv
[0]))
316 return io_open(io
, "%s%s", dir
, argv
[1]);
318 if ((type
== IO_RD
|| type
== IO_WR
) && pipe(pipefds
) < 0) {
321 } else if (type
== IO_AP
) {
322 va_start(args
, argv
);
323 pipefds
[1] = va_arg(args
, int);
327 if ((io
->pid
= fork())) {
330 if (pipefds
[!(type
== IO_WR
)] != -1)
331 close(pipefds
[!(type
== IO_WR
)]);
333 io
->pipe
= pipefds
[!!(type
== IO_WR
)];
339 int devnull
= open("/dev/null", O_RDWR
);
340 int readfd
= type
== IO_WR
? pipefds
[0] : devnull
;
341 int writefd
= (type
== IO_RD
|| type
== IO_AP
)
342 ? pipefds
[1] : devnull
;
343 int errorfd
= open_trace(devnull
, argv
);
345 dup2(readfd
, STDIN_FILENO
);
346 dup2(writefd
, STDOUT_FILENO
);
347 dup2(errorfd
, STDERR_FILENO
);
349 if (devnull
!= errorfd
)
352 if (pipefds
[0] != -1)
354 if (pipefds
[1] != -1)
358 if (dir
&& *dir
&& chdir(dir
) == -1)
361 execvp(argv
[0], (char *const*) argv
);
365 if (pipefds
[!!(type
== IO_WR
)] != -1)
366 close(pipefds
[!!(type
== IO_WR
)]);
371 io_complete(enum io_type type
, const char **argv
, const char *dir
, int fd
)
375 return io_run(&io
, type
, dir
, argv
, fd
) && io_done(&io
);
379 io_run_bg(const char **argv
)
381 return io_complete(IO_BG
, argv
, NULL
, -1);
385 io_run_fg(const char **argv
, const char *dir
)
387 return io_complete(IO_FG
, argv
, dir
, -1);
391 io_run_append(const char **argv
, int fd
)
393 return io_complete(IO_AP
, argv
, NULL
, fd
);
397 io_eof(struct io
*io
)
403 io_error(struct io
*io
)
409 io_strerror(struct io
*io
)
411 return strerror(io
->error
);
415 io_can_read(struct io
*io
, bool can_block
)
417 struct timeval tv
= { 0, 500 };
421 FD_SET(io
->pipe
, &fds
);
423 return select(io
->pipe
+ 1, &fds
, NULL
, NULL
, can_block
? NULL
: &tv
) > 0;
427 io_read(struct io
*io
, void *buf
, size_t bufsize
)
430 ssize_t readsize
= read(io
->pipe
, buf
, bufsize
);
432 if (readsize
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
434 else if (readsize
== -1)
436 else if (readsize
== 0)
442 DEFINE_ALLOCATOR(io_realloc_buf
, char, BUFSIZ
)
445 io_get(struct io
*io
, int c
, bool can_read
)
451 if (io
->bufsize
> 0) {
452 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
454 char *line
= io
->bufpos
;
457 io
->bufpos
= eol
+ 1;
458 io
->bufsize
-= io
->bufpos
- line
;
465 io
->bufpos
[io
->bufsize
] = 0;
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
))
481 io
->bufalloc
+= BUFSIZ
;
484 io
->bufpos
= io
->buf
;
485 readsize
= io_read(io
, io
->buf
+ io
->bufsize
, io
->bufalloc
- io
->bufsize
);
488 io
->bufsize
+= readsize
;
493 io_write(struct io
*io
, const void *buf
, size_t bufsize
)
497 while (!io_error(io
) && written
< bufsize
) {
500 size
= write(io
->pipe
, buf
+ written
, bufsize
- written
);
501 if (size
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
509 return written
== bufsize
;
513 io_printf(struct io
*io
, const char *fmt
, ...)
515 char buf
[SIZEOF_STR
] = "";
518 FORMAT_BUFFER(buf
, sizeof(buf
), fmt
, retval
, FALSE
);
520 io
->error
= ENAMETOOLONG
;
524 return io_write(io
, buf
, retval
);
528 io_read_buf(struct io
*io
, char buf
[], size_t bufsize
)
530 char *result
= io_get(io
, '\n', TRUE
);
533 result
= chomp_string(result
);
534 string_ncopy_do(buf
, bufsize
, result
, strlen(result
));
537 return io_done(io
) && result
;
541 io_run_buf(const char **argv
, char buf
[], size_t bufsize
)
545 return io_run(&io
, IO_RD
, NULL
, argv
) && io_read_buf(&io
, buf
, bufsize
);
549 io_load(struct io
*io
, const char *separators
,
550 io_read_fn read_property
, void *data
)
555 while (state
== OK
&& (name
= io_get(io
, '\n', TRUE
))) {
560 name
= chomp_string(name
);
561 namelen
= strcspn(name
, separators
);
565 value
= chomp_string(name
+ namelen
+ 1);
566 valuelen
= strlen(value
);
573 state
= read_property(name
, namelen
, value
, valuelen
, data
);
576 if (state
!= ERR
&& io_error(io
))
584 io_run_load(const char **argv
, const char *separators
,
585 io_read_fn read_property
, void *data
)
589 if (!io_run(&io
, IO_RD
, NULL
, argv
))
591 return io_load(&io
, separators
, read_property
, data
);