1 /* Copyright (c) 2006-2014 Jonas Fonseca <jonas.fonseca@gmail.com>
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.
19 * Encoding conversion.
22 #define ENCODING_SEP ": encoding: "
23 #define ENCODING_ARG "--encoding=" ENCODING_UTF8
25 #define CHARSET_SEP "; charset="
28 struct encoding
*next
;
33 char encoding_arg
[] = ENCODING_ARG
;
34 struct encoding
*default_encoding
;
35 static struct encoding
*encodings
;
38 encoding_open(const char *fromcode
)
40 struct encoding
*encoding
;
41 size_t len
= strlen(fromcode
);
46 for (encoding
= encodings
; encoding
; encoding
= encoding
->next
) {
47 if (!strcasecmp(encoding
->fromcode
, fromcode
))
51 encoding
= calloc(1, sizeof(*encoding
) + len
);
52 strncpy(encoding
->fromcode
, fromcode
, len
);
53 encoding
->cd
= iconv_open(ENCODING_UTF8
, fromcode
);
54 if (encoding
->cd
== ICONV_NONE
) {
59 encoding
->next
= encodings
;
66 encoding_convert_string(iconv_t iconv_cd
, struct buffer
*buf
)
68 static char out_buffer
[BUFSIZ
* 2];
69 ICONV_CONST
char *inbuf
= buf
->data
;
70 size_t inlen
= buf
->size
+ 1;
72 char *outbuf
= out_buffer
;
73 size_t outlen
= sizeof(out_buffer
);
75 size_t ret
= iconv(iconv_cd
, &inbuf
, &inlen
, &outbuf
, &outlen
);
76 if (ret
!= (size_t) -1) {
77 buf
->data
= out_buffer
;
78 buf
->size
= sizeof(out_buffer
) - outlen
;
81 return (ret
!= (size_t) -1);
85 encoding_convert(struct encoding
*encoding
, struct buffer
*buf
)
87 return encoding_convert_string(encoding
->cd
, buf
);
91 encoding_iconv(iconv_t iconv_cd
, const char *string
, size_t length
)
93 char *instr
= strndup(string
, length
);
94 struct buffer buf
= { instr
, length
};
95 const char *ret
= buf
.data
&& encoding_convert_string(iconv_cd
, &buf
) ? buf
.data
: string
;
98 return ret
== instr
? string
: ret
;
102 get_path_encoding(const char *path
, struct encoding
*default_encoding
)
104 const char *check_attr_argv
[] = {
105 "git", "check-attr", "encoding", "--", path
, NULL
107 char buf
[SIZEOF_STR
];
110 /* <path>: encoding: <encoding> */
112 if (!*path
|| !io_run_buf(check_attr_argv
, buf
, sizeof(buf
))
113 || !(encoding
= strstr(buf
, ENCODING_SEP
)))
114 return default_encoding
;
116 encoding
+= STRING_SIZE(ENCODING_SEP
);
117 if (!strcmp(encoding
, ENCODING_UTF8
)
118 || !strcmp(encoding
, "unspecified")
119 || !strcmp(encoding
, "set")) {
120 const char *file_argv
[] = {
121 "file", "-I", "--", path
, NULL
124 if (!*path
|| !io_run_buf(file_argv
, buf
, sizeof(buf
))
125 || !(encoding
= strstr(buf
, CHARSET_SEP
)))
126 return default_encoding
;
128 encoding
+= STRING_SIZE(CHARSET_SEP
);
131 return encoding_open(encoding
);
135 * Executing external commands.
139 io_init(struct io
*io
)
141 memset(io
, 0, sizeof(*io
));
146 io_open(struct io
*io
, const char *fmt
, ...)
148 char name
[SIZEOF_STR
] = "";
153 FORMAT_BUFFER(name
, sizeof(name
), fmt
, retval
, FALSE
);
155 io
->error
= ENAMETOOLONG
;
159 io
->pipe
= *name
? open(name
, O_RDONLY
) : dup(STDIN_FILENO
);
162 return io
->pipe
!= -1;
166 io_kill(struct io
*io
)
168 return io
->pid
== 0 || kill(io
->pid
, SIGKILL
) != -1;
172 io_done(struct io
*io
)
183 pid_t waiting
= waitpid(pid
, &status
, 0);
192 if (WEXITSTATUS(status
)) {
193 io
->status
= WEXITSTATUS(status
);
196 return waiting
== pid
&&
197 !WIFSIGNALED(status
) &&
205 open_trace(int devnull
, const char *argv
[])
207 static const char *trace_file
;
210 trace_file
= getenv("TIG_TRACE");
216 int fd
= open(trace_file
, O_RDWR
| O_CREAT
| O_APPEND
, 0666);
219 for (i
= 0; argv
[i
]; i
++) {
220 if (write(fd
, argv
[i
], strlen(argv
[i
])) == -1
221 || write(fd
, " ", 1) == -1)
224 if (argv
[i
] || write(fd
, "\n", 1) == -1) {
236 io_trace(const char *fmt
, ...)
238 static FILE *trace_out
; /* Intensionally leaked. */
243 const char *trace_file
= getenv("TIG_TRACE");
246 trace_out
= fopen(trace_file
, "a");
252 retval
= vfprintf(trace_out
, fmt
, args
);
260 io_exec(struct io
*io
, enum io_type type
, const char *dir
, char * const env
[], const char *argv
[], int custom
)
262 int pipefds
[2] = { -1, -1 };
263 bool read_from_stdin
= type
== IO_RD
&& (custom
& IO_RD_FORWARD_STDIN
);
264 bool read_with_stderr
= type
== IO_RD
&& (custom
& IO_RD_WITH_STDERR
);
268 if (dir
&& !strcmp(dir
, argv
[0]))
269 return io_open(io
, "%s%s", dir
, argv
[1]);
271 if ((type
== IO_RD
|| type
== IO_WR
) && pipe(pipefds
) < 0) {
274 } else if (type
== IO_AP
) {
278 if ((io
->pid
= fork())) {
281 if (pipefds
[!(type
== IO_WR
)] != -1)
282 close(pipefds
[!(type
== IO_WR
)]);
284 io
->pipe
= pipefds
[!!(type
== IO_WR
)];
290 int devnull
= open("/dev/null", O_RDWR
);
291 int readfd
= type
== IO_WR
? pipefds
[0] : devnull
;
292 int writefd
= (type
== IO_RD
|| type
== IO_AP
)
293 ? pipefds
[1] : devnull
;
294 int errorfd
= open_trace(devnull
, argv
);
296 /* Inject stdin given on the command line. */
298 readfd
= dup(STDIN_FILENO
);
300 dup2(readfd
, STDIN_FILENO
);
301 dup2(writefd
, STDOUT_FILENO
);
302 if (read_with_stderr
)
303 dup2(writefd
, STDERR_FILENO
);
305 dup2(errorfd
, STDERR_FILENO
);
307 if (devnull
!= errorfd
)
310 if (pipefds
[0] != -1)
312 if (pipefds
[1] != -1)
316 if (dir
&& *dir
&& chdir(dir
) == -1)
322 for (i
= 0; env
[i
]; i
++)
327 execvp(argv
[0], (char *const*) argv
);
331 if (pipefds
[!!(type
== IO_WR
)] != -1)
332 close(pipefds
[!!(type
== IO_WR
)]);
337 io_run(struct io
*io
, enum io_type type
, const char *dir
, char * const env
[], const char *argv
[])
339 return io_exec(io
, type
, dir
, env
, argv
, 0);
343 io_complete(enum io_type type
, const char **argv
, const char *dir
, int fd
)
347 return io_exec(&io
, type
, dir
, NULL
, argv
, fd
) && io_done(&io
);
351 io_run_bg(const char **argv
)
353 return io_complete(IO_BG
, argv
, NULL
, -1);
357 io_run_fg(const char **argv
, const char *dir
)
359 return io_complete(IO_FG
, argv
, dir
, -1);
363 io_run_append(const char **argv
, int fd
)
365 return io_complete(IO_AP
, argv
, NULL
, fd
);
369 io_eof(struct io
*io
)
375 io_error(struct io
*io
)
381 io_strerror(struct io
*io
)
383 return strerror(io
->error
);
387 io_can_read(struct io
*io
, bool can_block
)
389 struct timeval tv
= { 0, 500 };
393 FD_SET(io
->pipe
, &fds
);
395 return select(io
->pipe
+ 1, &fds
, NULL
, NULL
, can_block
? NULL
: &tv
) > 0;
399 io_read(struct io
*io
, void *buf
, size_t bufsize
)
402 ssize_t readsize
= read(io
->pipe
, buf
, bufsize
);
404 if (readsize
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
406 else if (readsize
== -1)
408 else if (readsize
== 0)
415 io_memchr(struct buffer
*buf
, char *data
, int c
)
419 if (!buf
|| data
< buf
->data
|| buf
->data
+ buf
->size
<= data
)
422 pos
= memchr(data
, c
, buf
->size
- (data
- buf
->data
));
423 return pos
? pos
+ 1 : NULL
;
426 DEFINE_ALLOCATOR(io_realloc_buf
, char, BUFSIZ
)
429 io_get_line(struct io
*io
, struct buffer
*buf
, int c
, size_t *lineno
, bool can_read
)
435 if (io
->bufsize
> 0) {
436 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
438 while (io
->span
&& io
->bufpos
< eol
&& eol
[-1] == '\\') {
441 eol
[-1] = eol
[0] = ' ';
442 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
445 buf
->data
= io
->bufpos
;
446 buf
->size
= eol
- buf
->data
;
449 io
->bufpos
= eol
+ 1;
450 io
->bufsize
-= io
->bufpos
- buf
->data
;
459 buf
->data
= io
->bufpos
;
460 buf
->size
= io
->bufsize
;
462 io
->bufpos
[io
->bufsize
] = 0;
463 io
->bufpos
+= io
->bufsize
;
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_get(struct io
*io
, struct buffer
*buf
, int c
, bool can_read
)
495 return io_get_line(io
, buf
, c
, NULL
, can_read
);
499 io_write(struct io
*io
, const void *buf
, size_t bufsize
)
503 while (!io_error(io
) && written
< bufsize
) {
506 size
= write(io
->pipe
, buf
+ written
, bufsize
- written
);
507 if (size
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
515 return written
== bufsize
;
519 io_printf(struct io
*io
, const char *fmt
, ...)
521 char buf
[SIZEOF_STR
] = "";
524 FORMAT_BUFFER(buf
, sizeof(buf
), fmt
, retval
, FALSE
);
526 io
->error
= ENAMETOOLONG
;
530 return io_write(io
, buf
, retval
);
534 io_read_buf(struct io
*io
, char buf
[], size_t bufsize
)
536 struct buffer result
= {};
538 if (io_get(io
, &result
, '\n', TRUE
)) {
539 result
.data
= chomp_string(result
.data
);
540 string_ncopy_do(buf
, bufsize
, result
.data
, strlen(result
.data
));
543 return io_done(io
) && result
.data
;
547 io_run_buf(const char **argv
, char buf
[], size_t bufsize
)
551 return io_run(&io
, IO_RD
, NULL
, NULL
, argv
) && io_read_buf(&io
, buf
, bufsize
);
555 io_from_string(struct io
*io
, const char *str
)
557 size_t len
= strlen(str
);
561 if (!io_realloc_buf(&io
->buf
, io
->bufalloc
, len
))
564 io
->bufsize
= io
->bufalloc
= len
;
565 io
->bufpos
= io
->buf
;
567 strncpy(io
->buf
, str
, len
);
573 io_load_file(struct io
*io
, const char *separators
,
574 size_t *lineno
, io_read_fn read_property
, void *data
)
579 while (state
== OK
&& io_get_line(io
, &buf
, '\n', lineno
, TRUE
)) {
585 name
= chomp_string(buf
.data
);
586 namelen
= strcspn(name
, separators
);
590 value
= chomp_string(name
+ namelen
+ 1);
591 valuelen
= strlen(value
);
598 state
= read_property(name
, namelen
, value
, valuelen
, data
);
601 if (state
!= ERR
&& io_error(io
))
609 io_load_span(struct io
*io
, const char *separators
, size_t *lineno
,
610 io_read_fn read_property
, void *data
)
613 return io_load_file(io
, separators
, lineno
, read_property
, data
);
617 io_load(struct io
*io
, const char *separators
,
618 io_read_fn read_property
, void *data
)
620 return io_load_file(io
, separators
, NULL
, read_property
, data
);
624 io_run_load(const char **argv
, const char *separators
,
625 io_read_fn read_property
, void *data
)
629 if (!io_run(&io
, IO_RD
, NULL
, NULL
, argv
))
631 return io_load(&io
, separators
, read_property
, data
);
637 static const char *tmp
;
643 tmp
= getenv("TMPDIR");
645 tmp
= getenv("TEMP");
654 /* vim: set ts=8 sw=8 noexpandtab: */