#include <std.h>
#include <stdio.h>
#include <ios1.h>
#include <qdos.h>
#include <ctype.h>

extern char _DPNAME[], _PROG_NAME[];

extern struct UFB _ufbs[];
extern char *_SP;
extern char _INAME[], _ONAME[], _ENAME[];
extern long _CONCHAN; /* Channel to be used for conio */

#define ERR 1 /* Set if stdout and stderr redirected to same place */

/********************************************************
 * Routine to copy internals of channel structure, and 	*
 * set DUP option.										*
 ********************************************************/

static void dupop( from, to)
register struct UFB *from, *to;
{
	*to = *from;
	to->ufbflg = ( from->ufbflg |= UFB_DP);
}

static void cpio_chan( from, to, inmode)
register struct UFB *from, *to;
register int inmode;
{
	*to = *from;
	/* Set new channel as open, write, and DUP'ed, - also preserve no close flag */
	to->ufbflg = (UFB_OP | UFB_WA | UFB_DP) | inmode | (from->ufbflg & UFB_NC);
	from->ufbflg |= UFB_DP; /* stdin now DUP'ed */
}

/************************************************
 * Routine to open all the necessary channels   *
 * before starting the users C program.         *
 ************************************************/

void _main( cl )
char *cl;   /* Command line */
{
	extern int _fmode;
	int inmode = (_fmode & O_RAW) ? UFB_NT : 0; /* Default open mode */
	/* opmode is used for open calls */
	register int nc;
	register int opmode = (_fmode & O_RAW)|(O_CREAT | O_WRONLY);
	register int ormode = (_fmode & O_RAW);	
	int oflag = 0;
	register WORD i;
	register struct UFB *uptri = &_ufbs[0], *uptro = &_ufbs[1];
	register struct UFB *uptre = &_ufbs[2];
	register FILE *fp;
	register int fdi = -1, fdo = -1, fde = -1, ic;
	int argc;
	char **argv;
	
	/* Copy the program name if not default */
	if( *_PROG_NAME ) /* Copy the program name into space for it */
		cstr_to_ql( _DPNAME, _PROG_NAME);

    /* Try and connect the channels passed on the stack (if any )
        to real level 2 channels (eg. stdin, stdout) 
		nc is a bitmap of channels opened */
    nc = _op_pchans( _SP );

    /* Set up the default directories before any file i/o (MUST BE DONE
		BEFORE PARSE ARGS */
    setup_dirs( cl );

	/* Separate out command line arguements */
    argc = _parse_args( cl, &argv );


    if (*_INAME) /* Input name asked for */
        fdi = open( _INAME, O_RDONLY | ormode );
    else if( nc & 1 ) /* No input name - channel passed */
        fdi = 0; /*  Standard in already opened by op_pchans */
    else /* Open a standard console channel in */
        fdi = open( "CON_", O_RDONLY | ormode );

	/* See if stdin is a con channel */
	ic = iscon( uptri->ufbfh, 0);

    /* Now try and open / set up the standard output channel */
    if(*_ONAME) /* Output name asked for */
		{
		if(*_ONAME == '>') 
			{/* Open for appending */
			opmode |= O_APPEND;
			strcpy( _ONAME, &_ONAME[1]); /* Ensure filename starts at _NAME[0] */
			}
		else /* Always overwrite file (no appending) */
			opmode |= O_TRUNC;

		if(*_ONAME == '&')
			{ /* Redirect stderr as well */
			oflag = ERR;
			strcpy( _ONAME, &_ONAME[1]);
			}

		fdo = open( _ONAME, opmode);
		if( oflag & ERR)
			{ /* Duplicate stdout into stderr */
			dupop( uptro, uptre); /* Copy UFB struct & add DUP flag */
			fde = 2; /* stderr opened */
			}
		}
    else if (!(nc & 2)) /* no stdout channel passed */
        {
		if( ic )
			{/* stdin is a screen channel, copy it for stdout */
			cpio_chan( uptri, uptro, inmode);
			fdo = 1;
			}
		else /* stdin is not a screen channel, open one for stdout */
			fdo = open( "CON_", O_WRONLY | ormode );
        }
    else
        fdo = 2; /* Standard out already opened */

	/* Now see if stderr was redirected on it's own */
	if( *_ENAME )
		{
		if( *_ENAME == '>' ) /* Append stderr */
			fde = open( &_ENAME[1], O_CREAT|O_WRONLY|O_APPEND|ormode);
		else
			fde = open( _ENAME, O_CREAT|O_WRONLY|O_TRUNC|ormode );
		}
    else if( (!(nc & 4)) && fde == -1)
        { /* Now try and open the standard error channel */
		if( iscon( uptro->ufbfh, 0))
			{/* Standard out is a CON_ device, use it for stderr */
			dupop( uptro, uptre);
			fde = 2;
			}
		else if( ic ) /* stdin is a CON_ device, use it for stderr */
			{
			cpio_chan( uptri, uptre, inmode);
			fde = 2;
			}
        else fde = open( "CON_", O_WRONLY | ormode);
        }
    else
        fde = 2; /* stdout already opened */

	/* Fail if any of the above failed */
	if( fdi == -1 || fdo == -1 || fde == -1)
		_exit(-1);
	nc |= 7; /* We know 0 - 2 are open */

	/* Go through the channels - ensuring level 2 i/o is opened for them,
		and the buffering and type are correct */

	for( i = 0; nc; i++, nc >>= 1)
		{
		if(nc & 1) /* Do this for all channels open*/
			{
			fp = &_iob[i]; /* Get level 2 handle */
			uptro = &_ufbs[i];
			if( ic = iscon( uptro->ufbfh, 0))
				{
				uptro->ufbtyp = D_CON; /* Set correct type */
				if( i != 2) /* Every channel except stderr is line buff if its CON_ */
					fp->_flag |= _IOLBF;
				}

			/* Try and get a CON_ channel for conio routines */
			if((_CONCHAN == -1) && ic)
				_CONCHAN = uptro->ufbfh;

			/* Special arrangement for stderr */
			if( (i == 2) && ic )
				{ /* stdout CON_ is not buffered */
				fp->_flag |= _IONBF;
				fp->_base = &fp->_cbuff;
				}

			if( i > 2)
				{ /* FILE 's below 2 are already defined, others we must set up */
				fp->_flag |= (ic ? _IOLBF : _IOFBF) | _IORW;
				fp->_file = i;
				}
			}
		}

	/* Initialise the semaphore package */
	initsems();

    /* Now call the user's program */
  	exit( main( argc, argv));
}

