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
])
112 DEFINE_ALLOCATOR(argv_realloc
, const char *, SIZEOF_ARG
)
115 argv_append(const char ***argv
, const char *arg
)
117 size_t argc
= argv_size(*argv
);
120 if (!*arg
&& argc
> 0)
123 if (!argv_realloc(argv
, argc
, 2))
128 (*argv
)[argc
++] = alloc
;
129 (*argv
)[argc
] = NULL
;
131 return alloc
!= NULL
;
135 argv_append_array(const char ***dst_argv
, const char *src_argv
[])
139 for (i
= 0; src_argv
&& src_argv
[i
]; i
++)
140 if (!argv_append(dst_argv
, src_argv
[i
]))
146 argv_remove_quotes(const char *argv
[])
150 for (argc
= 0; argv
[argc
]; argc
++) {
152 const char *arg
= argv
[argc
];
153 int arglen
= get_arg_valuelen(arg
, "ed
);
154 int unquotedlen
= arglen
- 1 - (arg
[arglen
- 1] == quoted
);
160 unquoted
= malloc(unquotedlen
+ 1);
163 strncpy(unquoted
, arg
+ 1, unquotedlen
);
164 unquoted
[unquotedlen
] = 0;
166 argv
[argc
] = unquoted
;
173 argv_copy(const char ***dst
, const char *src
[])
178 for (argc
= 0; src
[argc
]; argc
++)
179 if (!argv_append(dst
, src
[argc
]))
185 * Encoding conversion.
189 struct encoding
*next
;
194 static struct encoding
*encodings
;
197 encoding_open(const char *fromcode
)
199 struct encoding
*encoding
;
200 size_t len
= strlen(fromcode
);
205 for (encoding
= encodings
; encoding
; encoding
= encoding
->next
) {
206 if (!strcasecmp(encoding
->fromcode
, fromcode
))
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
) {
218 encoding
->next
= encodings
;
219 encodings
= encoding
;
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.
244 io_init(struct io
*io
)
246 memset(io
, 0, sizeof(*io
));
251 io_open(struct io
*io
, const char *fmt
, ...)
253 char name
[SIZEOF_STR
] = "";
258 FORMAT_BUFFER(name
, sizeof(name
), fmt
, retval
, FALSE
);
260 io
->error
= ENAMETOOLONG
;
264 io
->pipe
= *name
? open(name
, O_RDONLY
) : dup(STDIN_FILENO
);
267 return io
->pipe
!= -1;
271 io_kill(struct io
*io
)
273 return io
->pid
== 0 || kill(io
->pid
, SIGKILL
) != -1;
277 io_done(struct io
*io
)
288 pid_t waiting
= waitpid(pid
, &status
, 0);
297 if (WEXITSTATUS(status
)) {
298 io
->status
= WEXITSTATUS(status
);
301 return waiting
== pid
&&
302 !WIFSIGNALED(status
) &&
310 open_trace(int devnull
, const char *argv
[])
312 static const char *trace_file
;
315 trace_file
= getenv("TIG_TRACE");
321 int fd
= open(trace_file
, O_RDWR
| O_CREAT
| O_APPEND
, 0666);
324 for (i
= 0; argv
[i
]; i
++) {
325 if (write(fd
, argv
[i
], strlen(argv
[i
])) == -1
326 || write(fd
, " ", 1) == -1)
329 if (argv
[i
] || write(fd
, "\n", 1) == -1) {
341 io_run(struct io
*io
, enum io_type type
, const char *dir
, char * const env
[], const char *argv
[], ...)
343 int pipefds
[2] = { -1, -1 };
345 bool read_from_stdin
= type
== IO_RD_STDIN
;
352 if (dir
&& !strcmp(dir
, argv
[0]))
353 return io_open(io
, "%s%s", dir
, argv
[1]);
355 if ((type
== IO_RD
|| type
== IO_WR
) && pipe(pipefds
) < 0) {
358 } else if (type
== IO_AP
) {
359 va_start(args
, argv
);
360 pipefds
[1] = va_arg(args
, int);
364 if ((io
->pid
= fork())) {
367 if (pipefds
[!(type
== IO_WR
)] != -1)
368 close(pipefds
[!(type
== IO_WR
)]);
370 io
->pipe
= pipefds
[!!(type
== IO_WR
)];
376 int devnull
= open("/dev/null", O_RDWR
);
377 int readfd
= type
== IO_WR
? pipefds
[0] : devnull
;
378 int writefd
= (type
== IO_RD
|| type
== IO_AP
)
379 ? pipefds
[1] : devnull
;
380 int errorfd
= open_trace(devnull
, argv
);
382 /* Inject stdin given on the command line. */
384 readfd
= dup(STDIN_FILENO
);
386 dup2(readfd
, STDIN_FILENO
);
387 dup2(writefd
, STDOUT_FILENO
);
388 dup2(errorfd
, STDERR_FILENO
);
390 if (devnull
!= errorfd
)
393 if (pipefds
[0] != -1)
395 if (pipefds
[1] != -1)
399 if (dir
&& *dir
&& chdir(dir
) == -1)
405 for (i
= 0; env
[i
]; i
++)
410 execvp(argv
[0], (char *const*) argv
);
414 if (pipefds
[!!(type
== IO_WR
)] != -1)
415 close(pipefds
[!!(type
== IO_WR
)]);
420 io_complete(enum io_type type
, const char **argv
, const char *dir
, int fd
)
424 return io_run(&io
, type
, dir
, NULL
, argv
, fd
) && io_done(&io
);
428 io_run_bg(const char **argv
)
430 return io_complete(IO_BG
, argv
, NULL
, -1);
434 io_run_fg(const char **argv
, const char *dir
)
436 return io_complete(IO_FG
, argv
, dir
, -1);
440 io_run_append(const char **argv
, int fd
)
442 return io_complete(IO_AP
, argv
, NULL
, fd
);
446 io_eof(struct io
*io
)
452 io_error(struct io
*io
)
458 io_strerror(struct io
*io
)
460 return strerror(io
->error
);
464 io_can_read(struct io
*io
, bool can_block
)
466 struct timeval tv
= { 0, 500 };
470 FD_SET(io
->pipe
, &fds
);
472 return select(io
->pipe
+ 1, &fds
, NULL
, NULL
, can_block
? NULL
: &tv
) > 0;
476 io_read(struct io
*io
, void *buf
, size_t bufsize
)
479 ssize_t readsize
= read(io
->pipe
, buf
, bufsize
);
481 if (readsize
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
483 else if (readsize
== -1)
485 else if (readsize
== 0)
491 DEFINE_ALLOCATOR(io_realloc_buf
, char, BUFSIZ
)
494 io_get(struct io
*io
, int c
, bool can_read
)
500 if (io
->bufsize
> 0) {
501 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
503 char *line
= io
->bufpos
;
506 io
->bufpos
= eol
+ 1;
507 io
->bufsize
-= io
->bufpos
- line
;
514 io
->bufpos
[io
->bufsize
] = 0;
524 if (io
->bufsize
> 0 && io
->bufpos
> io
->buf
)
525 memmove(io
->buf
, io
->bufpos
, io
->bufsize
);
527 if (io
->bufalloc
== io
->bufsize
) {
528 if (!io_realloc_buf(&io
->buf
, io
->bufalloc
, BUFSIZ
))
530 io
->bufalloc
+= BUFSIZ
;
533 io
->bufpos
= io
->buf
;
534 readsize
= io_read(io
, io
->buf
+ io
->bufsize
, io
->bufalloc
- io
->bufsize
);
537 io
->bufsize
+= readsize
;
542 io_write(struct io
*io
, const void *buf
, size_t bufsize
)
546 while (!io_error(io
) && written
< bufsize
) {
549 size
= write(io
->pipe
, buf
+ written
, bufsize
- written
);
550 if (size
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
558 return written
== bufsize
;
562 io_printf(struct io
*io
, const char *fmt
, ...)
564 char buf
[SIZEOF_STR
] = "";
567 FORMAT_BUFFER(buf
, sizeof(buf
), fmt
, retval
, FALSE
);
569 io
->error
= ENAMETOOLONG
;
573 return io_write(io
, buf
, retval
);
577 io_read_buf(struct io
*io
, char buf
[], size_t bufsize
)
579 char *result
= io_get(io
, '\n', TRUE
);
582 result
= chomp_string(result
);
583 string_ncopy_do(buf
, bufsize
, result
, strlen(result
));
586 return io_done(io
) && result
;
590 io_run_buf(const char **argv
, char buf
[], size_t bufsize
)
594 return io_run(&io
, IO_RD
, NULL
, NULL
, argv
) && io_read_buf(&io
, buf
, bufsize
);
598 io_load(struct io
*io
, const char *separators
,
599 io_read_fn read_property
, void *data
)
604 while (state
== OK
&& (name
= io_get(io
, '\n', TRUE
))) {
609 name
= chomp_string(name
);
610 namelen
= strcspn(name
, separators
);
614 value
= chomp_string(name
+ namelen
+ 1);
615 valuelen
= strlen(value
);
622 state
= read_property(name
, namelen
, value
, valuelen
, data
);
625 if (state
!= ERR
&& io_error(io
))
633 io_run_load(const char **argv
, const char *separators
,
634 io_read_fn read_property
, void *data
)
638 if (!io_run(&io
, IO_RD
, NULL
, NULL
, argv
))
640 return io_load(&io
, separators
, read_property
, data
);
643 /* vim: set ts=8 sw=8 noexpandtab: */