diff options
Diffstat (limited to 'gnulib/lib/pipe-filter.h')
m--------- | gnulib | 0 | ||||
-rw-r--r-- | gnulib/lib/pipe-filter.h | 237 |
2 files changed, 237 insertions, 0 deletions
diff --git a/gnulib b/gnulib deleted file mode 160000 -Subproject 443bc5ffcf7429e557f4a371b0661abe98ddbc1 diff --git a/gnulib/lib/pipe-filter.h b/gnulib/lib/pipe-filter.h new file mode 100644 index 0000000..546d5ca --- /dev/null +++ b/gnulib/lib/pipe-filter.h @@ -0,0 +1,237 @@ +/* Filtering of data through a subprocess. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + Written by Bruno Haible <haible@clisp.cons.org>, 2009, + and Paolo Bonzini <bonzini@gnu.org>, 2009. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _PIPE_FILTER_H +#define _PIPE_FILTER_H + +#include <stdbool.h> +#include <stddef.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Piping data through a subprocess in the naïve way - write data to the + subprocess and read from the subprocess when you expect it to have + produced results - is subject to two kinds of deadlocks: + 1) If you write more than PIPE_MAX bytes or, more generally, if you write + more bytes than the subprocess can handle at once, the subprocess + may write its data and wait on you to read it, but you are currently + busy writing. + 2) When you don't know ahead of time how many bytes the subprocess + will produce, the usual technique of calling read (fd, buf, BUFSIZ) + with a fixed BUFSIZ will, on Linux 2.2.17 and on BSD systems, cause + the read() call to block until *all* of the buffer has been filled. + But the subprocess cannot produce more data until you gave it more + input. But you are currently busy reading from it. + + This header file declares four set of functions that pipes data through + the subprocess, without risking these deadlocks. + + The side that writes data to the subprocess can be seen as a "generator", + that is, as a subroutine that produces and writes a piece of data here and + there, see <http://en.wikipedia.org/wiki/Generator_(computer_science)>. + But often, it can be written in the form of an "iterator", that is, as a + function that, each time it is invoked, produces and writes one more piece + of data. + + Similarly, the side that reads data from the subprocess can be seen as + a "generator", that is, as a subroutine that consumes a piece of data here + and there. Often, it can be written in the form of an "iterator", that + is, as a function that, each time it is invoked, consumes one more piece + of data. + + This header file declares four set of functions: + + | writer | reader | + ----------------+------------+------------+ + pipe_filter_ii | iterator | iterator | + pipe_filter_ig | iterator | generator | + pipe_filter_gi | generator | iterator | + pipe_filter_gg | generator | generator | + ----------------+------------+------------+ + + The last one uses threads in order to implement two generators running at + the same time. (For the relation between generators, coroutines, and + threads, see <http://en.wikipedia.org/wiki/Generator_(computer_science)> + and <http://en.wikipedia.org/wiki/Coroutine>.) It is therefore only + portable to platforms with kernel-based POSIX threads. */ + +/* These two functions together describe the side that writes data to the + subprocess when it has the form of an iterator. + - prepare_write (&num_bytes, p) must either return a pointer to data that + is ready to be written and set num_bytes to the number of bytes ready to + be written, or return NULL when no more bytes are to be written. + - done_write (data_written, num_bytes_written) is called after + num_bytes_written bytes were written. It is guaranteed that + num_bytes_written > 0. + Here p is always the private_data argument passed to the main function. */ +typedef const void * (*prepare_write_fn) (size_t *num_bytes_p, + void *private_data); +typedef void (*done_write_fn) (void *data_written, size_t num_bytes_written, + void *private_data); + +/* These two functions together describe the side that reads data from the + subprocess when it has the form of an iterator. + - prepare_read (&num_bytes, p) must return a pointer to a buffer for data + that can be read and set num_bytes to the size of that buffer + (must be > 0). + - done_read (data_read, num_bytes_read, p) is called after num_bytes_read + bytes were read into the buffer. + Here p is always the private_data argument passed to the main function. */ +typedef void * (*prepare_read_fn) (size_t *num_bytes_p, + void *private_data); +typedef void (*done_read_fn) (void *data_read, size_t num_bytes_read, + void *private_data); + + +/* ============================ pipe_filter_ii ============================ */ + +/* Create a subprocess and pipe some data through it. + Arguments: + - progname is the program name used in error messages. + - prog_path is the file name of the program to invoke. + - prog_argv is a NULL terminated argument list, starting with prog_path as + first element. + - If null_stderr is true, the subprocess' stderr will be redirected to + /dev/null, and the usual error message to stderr will be omitted. + This is suitable when the subprocess does not fulfill an important task. + - If exit_on_error is true, any error will cause the main process to exit + with an error status. + If the subprocess does not terminate correctly, exit if exit_on_error is + true, otherwise return 127. + Callback arguments are as described above. + + Data is alternatingly written to the subprocess, through the functions + prepare_write and done_write, and read from the subprocess, through the + functions prepare_read and done_read. + + Note that the prepare_write/done_write functions and the + prepare_read/done_read functions may be called in different threads than + the current thread (depending on the platform). But they will not be + called after the pipe_filter_ii_execute function has returned. + + Return 0 upon success, or (only if exit_on_error is false): + - -1 with errno set upon failure, + - the positive exit code of the subprocess if that failed. */ +extern int + pipe_filter_ii_execute (const char *progname, + const char *prog_path, const char **prog_argv, + bool null_stderr, bool exit_on_error, + prepare_write_fn prepare_write, + done_write_fn done_write, + prepare_read_fn prepare_read, + done_read_fn done_read, + void *private_data); + + +/* ============================ pipe_filter_ig ============================ */ + +struct pipe_filter_ig; + + +/* ============================ pipe_filter_gi ============================ */ + +struct pipe_filter_gi; + +/* Create a subprocess and pipe some data through it. + Arguments: + - progname is the program name used in error messages. + - prog_path is the file name of the program to invoke. + - prog_argv is a NULL terminated argument list, starting with + prog_path as first element. + - If null_stderr is true, the subprocess' stderr will be redirected + to /dev/null, and the usual error message to stderr will be + omitted. This is suitable when the subprocess does not fulfill an + important task. + - If exit_on_error is true, any error will cause the main process to + exit with an error status. + If the subprocess does not start correctly, exit if exit_on_error is + true, otherwise return NULL and set errno. + + The caller will write to the subprocess through pipe_filter_gi_write + and finally call pipe_filter_gi_write. During such calls, the + prepare_read and done_read function may be called to process any data + that the subprocess has written. + + Note that the prepare_read/done_read functions may be called in a + different thread than the current thread (depending on the platform). + But they will not be called after the pipe_filter_gi_close function has + returned. + + Return the freshly created 'struct pipe_filter_gi'. */ +extern struct pipe_filter_gi * + pipe_filter_gi_create (const char *progname, + const char *prog_path, const char **prog_argv, + bool null_stderr, bool exit_on_error, + prepare_read_fn prepare_read, + done_read_fn done_read, + void *private_data); + +/* Write size bytes starting at buf into the pipe and in the meanwhile + possibly call the prepare_read and done_read functions specified to + pipe_filter_gi_create. + + Note that the prepare_read/done_read functions may be called in a + different thread than the current thread (depending on the platform). + However, they will always be called before pipe_filter_gi_write has + returned, or otherwise not sooner than the next call to + pipe_filter_gi_write or pipe_filter_gi_close. + + Return only after all the entire buffer has been written to the pipe or + the subprocess has exited. + + Return 0 upon success, or (only if exit_on_error is false): + - -1 with errno set upon failure, + - the positive exit code of the subprocess if that failed. */ +extern int + pipe_filter_gi_write (struct pipe_filter_gi *filter, + const void *buf, size_t size); + +/* Finish reading the output via the prepare_read/done_read functions + specified to pipe_filter_gi_create. + + Note that the prepare_read/done_read functions may be called in a + different thread than the current thread (depending on the platform). + However, they will always be called before pipe_filter_gi_close has + returned. + + The write side of the pipe is closed as soon as pipe_filter_gi_close + starts, while the read side will be closed just before it finishes. + + Return 0 upon success, or (only if exit_on_error is false): + - -1 with errno set upon failure, + - the positive exit code of the subprocess if that failed. */ +extern int + pipe_filter_gi_close (struct pipe_filter_gi *filter); + + +/* ============================ pipe_filter_gg ============================ */ + + +/* ======================================================================== */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _PIPE_FILTER_H */ |