//-----------------------------------------------------------------------------
// Copyright © 2003 - Philip Howard - All rights reserved
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//-----------------------------------------------------------------------------
// package	libh/io
// homepage	http://libh.slashusr.org/
//-----------------------------------------------------------------------------
// author	Philip Howard
// email	libh at ipal dot org
// homepage	http://phil.ipal.org/
//-----------------------------------------------------------------------------
// This file is best viewed using a fixed spaced font such as Courier
// and in a display at least 120 columns wide.
//-----------------------------------------------------------------------------

#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

// #include <libh/map.h>

#include "io_lib.h"

#ifndef DEV_NULL
#define DEV_NULL	"/dev/null"
#endif

extern char **environ;


__FMACRO_BEGIN__
//-----------------------------------------------------------------------------
// macro	fopen_proc_arg
//
// purpose	Create a pipe to a child process to read from its stdout (and
//		optionally stderr) or to write to its stdin, with the child
//		process running the given command and arguments.
//
// arguments	1 (const char *) option string
//		2 (const char *) file name to execute
//		3-N (const char *) program arguments as function arguments
//
// returns	(FILE *) NULL : error
//		(FILE *) file pointer to pipe.
//
// options	"r" open to read from stdout (and stderr if not inherited)
//		"w" open to write to stdin
//		"i" inherit stdin from parent
//		"o" inherit stdout from parent
//		"e" inherit stderr from parent
//
// warning	Do not use pclose() on the stream returned by this function.
//		It works differently than popen() and is not compatible with
//		pclose().
//-----------------------------------------------------------------------------
#define fopen_proc_arg(o,f,a...) ((fopen_proc_arg)((o),(f),a,(const char*)(NULL)))

__FMACRO_END__

__PROTO_BEGIN__
//-----------------------------------------------------------------------------
// function	fopen_proc_arg
//
// purpose	Create a pipe to a child process to read from its stdout (and
//		optionally stderr) or to write to its stdin, with the child
//		process running the given command and arguments.
//
// arguments	1 (const char *) option string
//		2 (const char *) file name to execute
//		3-N (const char *) program arguments as function arguments
//		N+1 (const char *) NULL to indicate end of arguments
//
// returns	(FILE *) NULL : error
//		(FILE *) file pointer to pipe.
//
// options	"r" open to read from stdout (and stderr if not inherited)
//		"w" open to write to stdin
//		"i" inherit stdin from parent
//		"o" inherit stdout from parent
//		"e" inherit stderr from parent
//
// warning	Do not use pclose() on the stream returned by this function.
//		It works differently than popen() and is not compatible with
//		pclose().
//-----------------------------------------------------------------------------
FILE *
(fopen_proc_arg) (
    const char *		arg_options
    ,
    const char *		arg_exec_name
    ,
    ...
    )
__PROTO_END__
{
    char * *		args_array	;
    char * *		args_ptr	;
    va_list		var_args	;
    int			args_count	;

    //-----------------
    // Check arguments.
    //-----------------
    if ( ! arg_exec_name || ! * arg_exec_name ) return NULL;

    //---------------------
    // Count the arguments.
    //---------------------
    args_count = 1;
    va_start( var_args, arg_exec_name );
    while ( va_arg( var_args, char * ) ) ++ args_count;
    va_end( var_args );

    //----------------------------------------------
    // Allocate a temporary array for the arguments.
    //----------------------------------------------
    args_array = alloca( sizeof (char *) * args_count );
    if ( ! args_array ) return NULL;

    //--------------------
    // Populate the array.
    //--------------------
    args_ptr = args_array;
    va_start( var_args, arg_exec_name );
    while ( ( * args_ptr = va_arg( var_args, char * ) ) ) ++ args_ptr;
    va_end( var_args );

    //-------------------------------------------
    // Let fopen_proc() do all the hard work.
    //-------------------------------------------
    return fopen_proc( arg_options, arg_exec_name, args_array );
}

