/* pipeline.h - create a process pipeline that can be used for reading or
 * writing.  These pipeline objects don't go through the shell, so they
 * avoid many of the obscure problems associated with system() and popen().
 *
 * Read pipelines are pipelines where a program reads output written by the
 * pipeline, and write pipelines are where the program writes data to the
 * pipeline.  The type of pipeline is specified in the set of option flags
 * passed to pipelineOpen().  The file at the other end of the pipeline is
 * specified in the otherEndFile argument of pipelineOpen(), as shown here:
 *
 * pipelineRead:
 *
 *   otherEndFile --> cmd[0] --> ... --> cmd[n] --> pipelineLf() etc.
 *
 * pipelineWrite:
 *
 *   pipeLineFile() --> cmd[0] --> ... --> cmd[n] --> otherEndFile
 *
 * Specify otherEndFile as "/dev/null" for no input or no output (or to
 * discard output).  If otherEndFile is NULL, then either stdin or stdout are
 * inherited from the current process.
 * 
 * I/O to the pipeline is done by using the result of pipelineFd(),
 * pipelineFile(), or pipelineLineFile().
 *
 * An example that reads a compressed file, sorting it numerically by the 
 * first column:
 *    
 *    static char *cmd1[] = {"gzip", "-dc", NULL};
 *    static char *cmd2[] = {"sort", "-k", "1,1n", NULL};
 *    static char **cmds[] = {cmd1, cmd2, NULL};
 *    
 *    struct pipeline *pl = pipelineOpen(cmds, pipelineRead, inFilePath, stderrFd);
 *    struct lineFile *lf = pipelineLineFile(pl);
 *    char *line;
 *    
 *    while (lineFileNext(lf, &line, NULL))
 *        {
 *        ...
 *        }
 *    pipelineWait(pl);
 *    pipelineFree(&pl);
 *
 * A similar example that generates data and writes a compressed file, sorting
 * it numerically by the first column:
 *    
 *    
 *    static char *cmd1[] = {"sort", "-k", "1,1n", NULL};
 *    static char *cmd2[] = {"gzip", "-c3", NULL};
 *    static char **cmds[] = {cmd1, cmd2, NULL};
 *    
 *    struct pipeline *pl = pipelineOpen(cmds, pipelineWrite, outFilePath, stderrFd);
 *    char *line;
 *    
 *    while ((line = makeNextRow()) != NULL)
 *        fprintf(fh, "%s\n", line);
 *    
 *    pipelineWait(pl);
 *    pipelineFree(&pl);
 *
 * To append to an output file, use pipelineWrite|pipelineAppend:
 *    
 *    struct pipeline *pl = pipelineOpen(cmds, pipelineWrite|pipelineAppend, outFilePath, stderrFd);
 */
#ifndef PIPELINE_H
#define PIPELINE_H
#include <stdio.h>
struct linefile;
struct pipeline;

enum pipelineOpts
/* pipeline options bitset */
    {
    pipelineRead       = 0x01, /* read from pipeline */
    pipelineWrite      = 0x02, /* write to pipeline */
    pipelineNoAbort    = 0x04, /* don't abort if a process exits non-zero,
                                * wait will return exit code instead.
                                * Still aborts if process signals. */
    pipelineAppend     = 0x10, /* Append to output file (used only with pipelineWrite) */
    /* these are internal options */
    pipelineMemInput   = 0x08  /* pipeline takes input from memory */
    };

struct pipeline *pipelineOpenFd(char ***cmds, unsigned opts,
                                int otherEndFd, int stderrFd);
/* Create a pipeline from an array of commands.  Each command is an array of
 * arguments.  Shell expansion is not done on the arguments.  If pipelineRead
 * is specified, the output of the pipeline is readable from the pipeline
 * object.  If pipelineWrite is specified, the input of the pipeline is
 * writable from the pipeline object. */

struct pipeline *pipelineOpen(char ***cmds, unsigned opts,
                              char *otherEndFile, char *stderrFile);
/* Create a pipeline from an array of commands.  Each command is an array of
 * arguments.  Shell expansion is not done on the arguments.  If pipelineRead
 * is specified, the output of the pipeline is readable from the pipeline
 * object.  If pipelineWrite is specified, the input of the pipeline is
 * writable from the pipeline object.  If stderrFile is NULL, stderr is inherited,
 * otherwise it is redirected to this file.
 */

void pipelineDumpCmds(char ***cmds);
/* Dump out pipeline-formatted commands to stdout for debugging. */

struct pipeline *pipelineOpenMem(char ***cmds, unsigned opts,
                                 void *otherEndBuf, size_t otherEndBufSize,
                                 int stderrFd);
/* Create a pipeline from an array of commands, with the pipeline input/output
 * in a memory buffer.  See pipeline.h for full documentation.  Currently only
 * input to a read pipeline is supported  */

struct pipeline *pipelineOpenFd1(char **cmd, unsigned opts,
                                 int otherEndFd, int stderrFd);
/* like pipelineOpenFd(), only takes a single command */

struct pipeline *pipelineOpen1(char **cmd, unsigned opts,
                               char *otherEndFile, char *stderrFile);
/* like pipelineOpen(), only takes a single command */

struct pipeline *pipelineOpenMem1(char **cmd, unsigned opts,
                                  void *otherEndBuf, size_t otherEndBufSize,
                                  int stderrFd);
/* like pipelineOpenMem(), only takes a single command */

char *pipelineDesc(struct pipeline *pl);
/* Get the desciption of a pipeline for use in error messages */

int pipelineFd(struct pipeline *pl);
/* Get the file descriptor for a pipeline */

FILE *pipelineFile(struct pipeline *pl);
/* Get a FILE object wrapped around the pipeline.  Do not close the FILE, is
 * owned by the pipeline object.  A FILE is created on first call to this
 * function.  Subsequent calls return the same FILE.*/

struct lineFile *pipelineLineFile(struct pipeline *pl);
/* Get a lineFile object wrapped around the pipeline.  Do not close the
 * lineFile, is owned by the pipeline object.  A lineFile is created on first
 * call to this function.  Subsequent calls return the same object.*/

int pipelineWait(struct pipeline *pl);
/* Wait for processes in a pipeline to complete; normally aborts if any
 * process exists non-zero.  If pipelineNoAbort was specified, return the exit
 * code of the first process exit non-zero, or zero if none failed. */

void pipelineFree(struct pipeline **plPtr);
/* free a pipeline object */

#endif
/*
 * Local Variables:
 * c-file-style: "jkent-c"
 * End:
 */
