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 get_arg_valuelen(const char *arg
, bool *quoted
)
20 if (*arg
== '"' || *arg
== '\'') {
21 const char *end
= *arg
== '"' ? "\"" : "'";
22 int valuelen
= strcspn(arg
+ 1, end
);
26 return valuelen
> 0 ? valuelen
+ 2 : strlen(arg
);
28 return strcspn(arg
, " \t");
33 split_argv_string(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
, bool remove_quotes
)
35 while (*cmd
&& *argc
< SIZEOF_ARG
) {
37 int valuelen
= get_arg_valuelen(cmd
, "ed
);
38 bool advance
= cmd
[valuelen
] != 0;
39 int quote_offset
= !!(quoted
&& remove_quotes
);
41 cmd
[valuelen
- quote_offset
] = 0;
42 argv
[(*argc
)++] = chomp_string(cmd
+ quote_offset
);
43 cmd
= chomp_string(cmd
+ valuelen
+ advance
);
46 if (*argc
< SIZEOF_ARG
)
48 return *argc
< SIZEOF_ARG
;
52 argv_from_string_no_quotes(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
)
54 return split_argv_string(argv
, argc
, cmd
, TRUE
);
58 argv_from_string(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
)
60 return split_argv_string(argv
, argc
, cmd
, FALSE
);
64 argv_from_env(const char **argv
, const char *name
)
66 char *env
= argv
? getenv(name
) : NULL
;
71 return !env
|| argv_from_string(argv
, &argc
, env
);
75 argv_free(const char *argv
[])
81 for (argc
= 0; argv
[argc
]; argc
++)
82 free((void *) argv
[argc
]);
87 argv_size(const char **argv
)
91 while (argv
&& argv
[argc
])
97 DEFINE_ALLOCATOR(argv_realloc
, const char *, SIZEOF_ARG
)
100 argv_append(const char ***argv
, const char *arg
)
102 size_t argc
= argv_size(*argv
);
104 if (!*arg
&& argc
> 0)
107 if (!argv_realloc(argv
, argc
, 2))
110 (*argv
)[argc
++] = strdup(arg
);
111 (*argv
)[argc
] = NULL
;
116 argv_append_array(const char ***dst_argv
, const char *src_argv
[])
120 for (i
= 0; src_argv
&& src_argv
[i
]; i
++)
121 if (!argv_append(dst_argv
, src_argv
[i
]))
127 argv_copy(const char ***dst
, const char *src
[])
132 for (argc
= 0; src
[argc
]; argc
++)
133 if (!argv_append(dst
, src
[argc
]))
139 * Encoding conversion.
143 struct encoding
*next
;
148 static struct encoding
*encodings
;
151 encoding_open(const char *fromcode
)
153 struct encoding
*encoding
;
154 size_t len
= strlen(fromcode
);
159 for (encoding
= encodings
; encoding
; encoding
= encoding
->next
) {
160 if (!strcasecmp(encoding
->fromcode
, fromcode
))
164 encoding
= calloc(1, sizeof(*encoding
) + len
);
165 strncpy(encoding
->fromcode
, fromcode
, len
);
166 encoding
->cd
= iconv_open(ENCODING_UTF8
, fromcode
);
167 if (encoding
->cd
== ICONV_NONE
) {
172 encoding
->next
= encodings
;
173 encodings
= encoding
;
179 encoding_convert(struct encoding
*encoding
, char *line
)
181 static char out_buffer
[BUFSIZ
* 2];
182 ICONV_CONST
char *inbuf
= line
;
183 size_t inlen
= strlen(line
) + 1;
185 char *outbuf
= out_buffer
;
186 size_t outlen
= sizeof(out_buffer
);
188 size_t ret
= iconv(encoding
->cd
, &inbuf
, &inlen
, &outbuf
, &outlen
);
190 return (ret
!= (size_t) -1) ? out_buffer
: line
;
194 * Executing external commands.
198 io_init(struct io
*io
)
200 memset(io
, 0, sizeof(*io
));
205 io_open(struct io
*io
, const char *fmt
, ...)
207 char name
[SIZEOF_STR
] = "";
212 FORMAT_BUFFER(name
, sizeof(name
), fmt
, retval
, FALSE
);
214 io
->error
= ENAMETOOLONG
;
218 io
->pipe
= *name
? open(name
, O_RDONLY
) : dup(STDIN_FILENO
);
221 return io
->pipe
!= -1;
225 io_kill(struct io
*io
)
227 return io
->pid
== 0 || kill(io
->pid
, SIGKILL
) != -1;
231 io_done(struct io
*io
)
242 pid_t waiting
= waitpid(pid
, &status
, 0);
251 if (WEXITSTATUS(status
)) {
252 io
->status
= WEXITSTATUS(status
);
255 return waiting
== pid
&&
256 !WIFSIGNALED(status
) &&
264 io_run(struct io
*io
, enum io_type type
, const char *dir
, const char *argv
[], ...)
266 int pipefds
[2] = { -1, -1 };
271 if (dir
&& !strcmp(dir
, argv
[0]))
272 return io_open(io
, "%s%s", dir
, argv
[1]);
274 if ((type
== IO_RD
|| type
== IO_WR
) && pipe(pipefds
) < 0) {
277 } else if (type
== IO_AP
) {
278 va_start(args
, argv
);
279 pipefds
[1] = va_arg(args
, int);
283 if ((io
->pid
= fork())) {
286 if (pipefds
[!(type
== IO_WR
)] != -1)
287 close(pipefds
[!(type
== IO_WR
)]);
289 io
->pipe
= pipefds
[!!(type
== IO_WR
)];
295 int devnull
= open("/dev/null", O_RDWR
);
296 int readfd
= type
== IO_WR
? pipefds
[0] : devnull
;
297 int writefd
= (type
== IO_RD
|| type
== IO_AP
)
298 ? pipefds
[1] : devnull
;
300 dup2(readfd
, STDIN_FILENO
);
301 dup2(writefd
, STDOUT_FILENO
);
302 dup2(devnull
, STDERR_FILENO
);
305 if (pipefds
[0] != -1)
307 if (pipefds
[1] != -1)
311 if (dir
&& *dir
&& chdir(dir
) == -1)
314 execvp(argv
[0], (char *const*) argv
);
318 if (pipefds
[!!(type
== IO_WR
)] != -1)
319 close(pipefds
[!!(type
== IO_WR
)]);
324 io_complete(enum io_type type
, const char **argv
, const char *dir
, int fd
)
328 return io_run(&io
, type
, dir
, argv
, fd
) && io_done(&io
);
332 io_run_bg(const char **argv
)
334 return io_complete(IO_BG
, argv
, NULL
, -1);
338 io_run_fg(const char **argv
, const char *dir
)
340 return io_complete(IO_FG
, argv
, dir
, -1);
344 io_run_append(const char **argv
, int fd
)
346 return io_complete(IO_AP
, argv
, NULL
, fd
);
350 io_eof(struct io
*io
)
356 io_error(struct io
*io
)
362 io_strerror(struct io
*io
)
364 return strerror(io
->error
);
368 io_can_read(struct io
*io
, bool can_block
)
370 struct timeval tv
= { 0, 500 };
374 FD_SET(io
->pipe
, &fds
);
376 return select(io
->pipe
+ 1, &fds
, NULL
, NULL
, can_block
? NULL
: &tv
) > 0;
380 io_read(struct io
*io
, void *buf
, size_t bufsize
)
383 ssize_t readsize
= read(io
->pipe
, buf
, bufsize
);
385 if (readsize
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
387 else if (readsize
== -1)
389 else if (readsize
== 0)
395 DEFINE_ALLOCATOR(io_realloc_buf
, char, BUFSIZ
)
398 io_get(struct io
*io
, int c
, bool can_read
)
404 if (io
->bufsize
> 0) {
405 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
407 char *line
= io
->bufpos
;
410 io
->bufpos
= eol
+ 1;
411 io
->bufsize
-= io
->bufpos
- line
;
418 io
->bufpos
[io
->bufsize
] = 0;
428 if (io
->bufsize
> 0 && io
->bufpos
> io
->buf
)
429 memmove(io
->buf
, io
->bufpos
, io
->bufsize
);
431 if (io
->bufalloc
== io
->bufsize
) {
432 if (!io_realloc_buf(&io
->buf
, io
->bufalloc
, BUFSIZ
))
434 io
->bufalloc
+= BUFSIZ
;
437 io
->bufpos
= io
->buf
;
438 readsize
= io_read(io
, io
->buf
+ io
->bufsize
, io
->bufalloc
- io
->bufsize
);
441 io
->bufsize
+= readsize
;
446 io_write(struct io
*io
, const void *buf
, size_t bufsize
)
450 while (!io_error(io
) && written
< bufsize
) {
453 size
= write(io
->pipe
, buf
+ written
, bufsize
- written
);
454 if (size
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
462 return written
== bufsize
;
466 io_printf(struct io
*io
, const char *fmt
, ...)
468 char buf
[SIZEOF_STR
] = "";
471 FORMAT_BUFFER(buf
, sizeof(buf
), fmt
, retval
, FALSE
);
473 io
->error
= ENAMETOOLONG
;
477 return io_write(io
, buf
, retval
);
481 io_read_buf(struct io
*io
, char buf
[], size_t bufsize
)
483 char *result
= io_get(io
, '\n', TRUE
);
486 result
= chomp_string(result
);
487 string_ncopy_do(buf
, bufsize
, result
, strlen(result
));
490 return io_done(io
) && result
;
494 io_run_buf(const char **argv
, char buf
[], size_t bufsize
)
498 return io_run(&io
, IO_RD
, NULL
, argv
) && io_read_buf(&io
, buf
, bufsize
);
502 io_load(struct io
*io
, const char *separators
,
503 io_read_fn read_property
, void *data
)
508 while (state
== OK
&& (name
= io_get(io
, '\n', TRUE
))) {
513 name
= chomp_string(name
);
514 namelen
= strcspn(name
, separators
);
518 value
= chomp_string(name
+ namelen
+ 1);
519 valuelen
= strlen(value
);
526 state
= read_property(name
, namelen
, value
, valuelen
, data
);
529 if (state
!= ERR
&& io_error(io
))
537 io_run_load(const char **argv
, const char *separators
,
538 io_read_fn read_property
, void *data
)
542 if (!io_run(&io
, IO_RD
, NULL
, argv
))
544 return io_load(&io
, separators
, read_property
, data
);