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
, char *line
, size_t linelen
)
68 static char out_buffer
[BUFSIZ
* 2];
69 ICONV_CONST
char *inbuf
= line
;
70 size_t inlen
= linelen
+ 1;
72 char *outbuf
= out_buffer
;
73 size_t outlen
= sizeof(out_buffer
);
75 size_t ret
= iconv(iconv_cd
, &inbuf
, &inlen
, &outbuf
, &outlen
);
77 return (ret
!= (size_t) -1) ? out_buffer
: line
;
81 encoding_convert(struct encoding
*encoding
, char *line
)
83 return encoding_convert_string(encoding
->cd
, line
, strlen(line
));
87 encoding_iconv(iconv_t iconv_cd
, const char *string
, size_t length
)
89 char *instr
= strndup(string
, length
);
90 const char *ret
= instr
? encoding_convert_string(iconv_cd
, instr
, length
) : string
;
93 return ret
== instr
? string
: ret
;
97 get_path_encoding(const char *path
, struct encoding
*default_encoding
)
99 const char *check_attr_argv
[] = {
100 "git", "check-attr", "encoding", "--", path
, NULL
102 char buf
[SIZEOF_STR
];
105 /* <path>: encoding: <encoding> */
107 if (!*path
|| !io_run_buf(check_attr_argv
, buf
, sizeof(buf
))
108 || !(encoding
= strstr(buf
, ENCODING_SEP
)))
109 return default_encoding
;
111 encoding
+= STRING_SIZE(ENCODING_SEP
);
112 if (!strcmp(encoding
, ENCODING_UTF8
)
113 || !strcmp(encoding
, "unspecified")
114 || !strcmp(encoding
, "set")) {
115 const char *file_argv
[] = {
116 "file", "-I", "--", path
, NULL
119 if (!*path
|| !io_run_buf(file_argv
, buf
, sizeof(buf
))
120 || !(encoding
= strstr(buf
, CHARSET_SEP
)))
121 return default_encoding
;
123 encoding
+= STRING_SIZE(CHARSET_SEP
);
126 return encoding_open(encoding
);
130 * Executing external commands.
134 io_init(struct io
*io
)
136 memset(io
, 0, sizeof(*io
));
141 io_open(struct io
*io
, const char *fmt
, ...)
143 char name
[SIZEOF_STR
] = "";
148 FORMAT_BUFFER(name
, sizeof(name
), fmt
, retval
, FALSE
);
150 io
->error
= ENAMETOOLONG
;
154 io
->pipe
= *name
? open(name
, O_RDONLY
) : dup(STDIN_FILENO
);
157 return io
->pipe
!= -1;
161 io_kill(struct io
*io
)
163 return io
->pid
== 0 || kill(io
->pid
, SIGKILL
) != -1;
167 io_done(struct io
*io
)
178 pid_t waiting
= waitpid(pid
, &status
, 0);
187 if (WEXITSTATUS(status
)) {
188 io
->status
= WEXITSTATUS(status
);
191 return waiting
== pid
&&
192 !WIFSIGNALED(status
) &&
200 open_trace(int devnull
, const char *argv
[])
202 static const char *trace_file
;
205 trace_file
= getenv("TIG_TRACE");
211 int fd
= open(trace_file
, O_RDWR
| O_CREAT
| O_APPEND
, 0666);
214 for (i
= 0; argv
[i
]; i
++) {
215 if (write(fd
, argv
[i
], strlen(argv
[i
])) == -1
216 || write(fd
, " ", 1) == -1)
219 if (argv
[i
] || write(fd
, "\n", 1) == -1) {
231 io_trace(const char *fmt
, ...)
233 static FILE *trace_out
; /* Intensionally leaked. */
238 const char *trace_file
= getenv("TIG_TRACE");
241 trace_out
= fopen(trace_file
, "a");
247 retval
= vfprintf(trace_out
, fmt
, args
);
255 io_exec(struct io
*io
, enum io_type type
, const char *dir
, char * const env
[], const char *argv
[], int custom
)
257 int pipefds
[2] = { -1, -1 };
258 bool read_from_stdin
= type
== IO_RD
&& (custom
& IO_RD_FORWARD_STDIN
);
259 bool read_with_stderr
= type
== IO_RD
&& (custom
& IO_RD_WITH_STDERR
);
263 if (dir
&& !strcmp(dir
, argv
[0]))
264 return io_open(io
, "%s%s", dir
, argv
[1]);
266 if ((type
== IO_RD
|| type
== IO_WR
) && pipe(pipefds
) < 0) {
269 } else if (type
== IO_AP
) {
273 if ((io
->pid
= fork())) {
276 if (pipefds
[!(type
== IO_WR
)] != -1)
277 close(pipefds
[!(type
== IO_WR
)]);
279 io
->pipe
= pipefds
[!!(type
== IO_WR
)];
285 int devnull
= open("/dev/null", O_RDWR
);
286 int readfd
= type
== IO_WR
? pipefds
[0] : devnull
;
287 int writefd
= (type
== IO_RD
|| type
== IO_AP
)
288 ? pipefds
[1] : devnull
;
289 int errorfd
= open_trace(devnull
, argv
);
291 /* Inject stdin given on the command line. */
293 readfd
= dup(STDIN_FILENO
);
295 dup2(readfd
, STDIN_FILENO
);
296 dup2(writefd
, STDOUT_FILENO
);
297 if (read_with_stderr
)
298 dup2(writefd
, STDERR_FILENO
);
300 dup2(errorfd
, STDERR_FILENO
);
302 if (devnull
!= errorfd
)
305 if (pipefds
[0] != -1)
307 if (pipefds
[1] != -1)
311 if (dir
&& *dir
&& chdir(dir
) == -1)
317 for (i
= 0; env
[i
]; i
++)
322 execvp(argv
[0], (char *const*) argv
);
326 if (pipefds
[!!(type
== IO_WR
)] != -1)
327 close(pipefds
[!!(type
== IO_WR
)]);
332 io_run(struct io
*io
, enum io_type type
, const char *dir
, char * const env
[], const char *argv
[])
334 return io_exec(io
, type
, dir
, env
, argv
, 0);
338 io_complete(enum io_type type
, const char **argv
, const char *dir
, int fd
)
342 return io_exec(&io
, type
, dir
, NULL
, argv
, fd
) && io_done(&io
);
346 io_run_bg(const char **argv
)
348 return io_complete(IO_BG
, argv
, NULL
, -1);
352 io_run_fg(const char **argv
, const char *dir
)
354 return io_complete(IO_FG
, argv
, dir
, -1);
358 io_run_append(const char **argv
, int fd
)
360 return io_complete(IO_AP
, argv
, NULL
, fd
);
364 io_eof(struct io
*io
)
370 io_error(struct io
*io
)
376 io_strerror(struct io
*io
)
378 return strerror(io
->error
);
382 io_can_read(struct io
*io
, bool can_block
)
384 struct timeval tv
= { 0, 500 };
388 FD_SET(io
->pipe
, &fds
);
390 return select(io
->pipe
+ 1, &fds
, NULL
, NULL
, can_block
? NULL
: &tv
) > 0;
394 io_read(struct io
*io
, void *buf
, size_t bufsize
)
397 ssize_t readsize
= read(io
->pipe
, buf
, bufsize
);
399 if (readsize
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
401 else if (readsize
== -1)
403 else if (readsize
== 0)
410 io_memchr(struct io
*io
, char *data
, int c
)
414 if (data
< io
->buf
|| io
->bufpos
<= data
)
417 pos
= memchr(data
, c
, io
->bufpos
- data
- 1);
418 return pos
? pos
+ 1 : NULL
;
421 DEFINE_ALLOCATOR(io_realloc_buf
, char, BUFSIZ
)
424 io_get(struct io
*io
, int c
, bool can_read
)
430 if (io
->bufsize
> 0) {
431 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
433 while (io
->span
&& io
->bufpos
< eol
&& eol
[-1] == '\\') {
434 eol
[-1] = eol
[0] = ' ';
435 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
438 char *line
= io
->bufpos
;
441 io
->bufpos
= eol
+ 1;
442 io
->bufsize
-= io
->bufpos
- line
;
449 char *line
= io
->bufpos
;
451 io
->bufpos
[io
->bufsize
] = 0;
452 io
->bufpos
+= io
->bufsize
;
462 if (io
->bufsize
> 0 && io
->bufpos
> io
->buf
)
463 memmove(io
->buf
, io
->bufpos
, io
->bufsize
);
465 if (io
->bufalloc
== io
->bufsize
) {
466 if (!io_realloc_buf(&io
->buf
, io
->bufalloc
, BUFSIZ
))
468 io
->bufalloc
+= BUFSIZ
;
471 io
->bufpos
= io
->buf
;
472 readsize
= io_read(io
, io
->buf
+ io
->bufsize
, io
->bufalloc
- io
->bufsize
);
475 io
->bufsize
+= readsize
;
480 io_write(struct io
*io
, const void *buf
, size_t bufsize
)
484 while (!io_error(io
) && written
< bufsize
) {
487 size
= write(io
->pipe
, buf
+ written
, bufsize
- written
);
488 if (size
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
496 return written
== bufsize
;
500 io_printf(struct io
*io
, const char *fmt
, ...)
502 char buf
[SIZEOF_STR
] = "";
505 FORMAT_BUFFER(buf
, sizeof(buf
), fmt
, retval
, FALSE
);
507 io
->error
= ENAMETOOLONG
;
511 return io_write(io
, buf
, retval
);
515 io_read_buf(struct io
*io
, char buf
[], size_t bufsize
)
517 char *result
= io_get(io
, '\n', TRUE
);
520 result
= chomp_string(result
);
521 string_ncopy_do(buf
, bufsize
, result
, strlen(result
));
524 return io_done(io
) && result
;
528 io_run_buf(const char **argv
, char buf
[], size_t bufsize
)
532 return io_run(&io
, IO_RD
, NULL
, NULL
, argv
) && io_read_buf(&io
, buf
, bufsize
);
536 io_from_string(struct io
*io
, const char *str
)
538 size_t len
= strlen(str
);
542 if (!io_realloc_buf(&io
->buf
, io
->bufalloc
, len
))
545 io
->bufsize
= io
->bufalloc
= len
;
546 io
->bufpos
= io
->buf
;
548 strncpy(io
->buf
, str
, len
);
554 io_load(struct io
*io
, const char *separators
,
555 io_read_fn read_property
, void *data
)
560 while (state
== OK
&& (name
= io_get(io
, '\n', TRUE
))) {
565 name
= chomp_string(name
);
566 namelen
= strcspn(name
, separators
);
570 value
= chomp_string(name
+ namelen
+ 1);
571 valuelen
= strlen(value
);
578 state
= read_property(name
, namelen
, value
, valuelen
, data
);
581 if (state
!= ERR
&& io_error(io
))
589 io_run_load(const char **argv
, const char *separators
,
590 io_read_fn read_property
, void *data
)
594 if (!io_run(&io
, IO_RD
, NULL
, NULL
, argv
))
596 return io_load(&io
, separators
, read_property
, data
);
602 static const char *tmp
;
608 tmp
= getenv("TMPDIR");
610 tmp
= getenv("TEMP");
619 /* vim: set ts=8 sw=8 noexpandtab: */