/*
    This file is part of SUPPL - the supplemental library for DOS
    Copyright (C) 1996-2000 Steffen Kaiser

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $RCSfile: CFG_OFIL.C $
   $Locker: ska $	$Name:  $	$State: Exp $


ob(ject): cfg_ostkRdFile
su(bsystem): cmdline
ty(pe): L
sy(nopsis): 
sh(ort description): "read argument" function for files
he(ader files): 
lo(ng description): Implements the "read argument" function for files,
	suiteable for the member of the output stack named \tok{C_rdArg}.
pr(erequistes): 
va(lue): NULL: if empty \item else: pointer to static buffer containing
	the next argument
re(lated to): cfg_ostkInitFile
se(condary subsystems): 
xr(ef): 
im(port): 
fi(le): cfg_ofil.c
in(itialized by): 
wa(rning): 
bu(gs): 

ob(ject): cfg_ostkSqFile
su(bsystem): cmdline
ty(pe): L
sy(nopsis): 
sh(ort description): "sequentially read argument" function for files
he(ader files): 
lo(ng description): Implements the "sequentially read argument" function for files,
	suiteable for the member of the output stack named \tok{C_rdArg}.
pr(erequistes): 
va(lue): NULL: if empty \item else: pointer to static buffer containing
	the next argument
re(lated to): cfg_ostkInitFile
se(condary subsystems): 
xr(ef): 
im(port): 
fi(le): cfg_ofil.c
in(itialized by): 
wa(rning): 
bu(gs): 

ob(ject): cfg_ostkClFile
su(bsystem): cmdline
ty(pe): L
sy(nopsis): 
sh(ort description): "close output stack item" function for files
he(ader files): 
lo(ng description): Implements the "close output stack item" function for files,
	suiteable for the member of the output stack named \tok{C_clArg}.
pr(erequistes): 
va(lue): none
re(lated to): cfg_ostkInitFile
se(condary subsystems): 
xr(ef): 
im(port): 
fi(le): cfg_ofil.c
in(itialized by): 
wa(rning): 
bu(gs): 

ob(ject): cfg_ostkInitFile
su(bsystem): cmdline
ty(pe): L
sy(nopsis): 
sh(ort description): Initialize an output stack item associated to a file
he(ader files): 
lo(ng description): Associates an already created output stack item
	with the file implementation. The members of the output stack item
	serve the following purpose:
	\item\tok{FLAG opt_readmode}:	\tok{!= 0}, if the last access was to read
	\item\tok{FILE *opt_rsp}:		 duplicated response file; valid if buildarglst
								is enabled.\par
								If a response file is encountered, the
								values normally put into the lst are
								buffered into this file. This ensures
								that the response file is opened & read
								only once (pipe), but also offers to
								hold as many entries a response file can
								have (and overflow the memory).  A
								placeholder is added to the lst array
								that indicates how many lines are used
								by this response file, in case more than
								one response file is used. Because the
								lst array is always scanned from the
								beginning, one need not save the
								position within this buffer file.\par
								The \tok{_rspread} flag indicates that the file is
								in read-mode currently, thus before appending
								a new entry, the file position must be
								saved into \tok{_rpos} and seeked to the end of
								the file.\par
								Each entry within the file is a Pascal
								string with an (unsigned) length indicator.
	\item\tok{fpos_t opt_wpos}:		position of the beginning of the last non-option
								entry within the \tok{rsp} file, for the insOpt()
								function; valid if \tok{rsp != NULL}
	\item\tok{fpos_t opt_rpos}:		position of the next read access; valid
								if \tok{_rspread == 0}.
pr(erequistes): 
va(lue): none
re(lated to): 
se(condary subsystems): 
xr(ef): 
im(port): 
fi(le): cfg_ofil.c
in(itialized by): 
wa(rning): 
bu(gs): 

*/

#include "initsupl.loc"

#ifndef _MICROC_
#include <string.h>
#endif
#include <portable.h>
#include "dynstr.h"
#include "supplio.h"
#include "cfg.loc"

#include "suppldbg.h"

#ifdef RCS_Version
static char const rcsid[] = 
	"$Id: CFG_OFIL.C 1.8 2001/02/27 01:28:03 ska Exp ska $";
#endif

void cfg_ostkWrFile(int mode, struct Cfg_Getopt * const optstru
	, struct Cfg_oStackGetopt * const ostk
	, char * const buf
	, size_t len)
{	struct Cfg_ArgFileList *p;
	FILE *f;

	DBG_ENTER("cfg_ostkWrFile", Suppl_cmdline)

	assert(optstru);
	assert(ostk);

	if(mode && !O(cnt))
		mode = 0;		/* first entry */

	if((p = O(putArg)) == 0) {		/* create the parameters */
		O(putArg) = p = Ecalloc(sizeof(struct Cfg_ArgFileList));
		f = p->cfg_a_f = Etmpfile();
		EEgetpos(p->cfg_a_f, p->cfg_a_rpos);
		EEgetpos(p->cfg_a_f, p->cfg_a_fpos);
	}
	else {					/* make sure the file is in write mode */
		assert(p->cfg_a_f);
		f = p->cfg_a_f;
		if(p->cfg_a_rmode) {
			EEgetpos(f, p->cfg_a_rpos);
			Eseeke(f);
			Fsetmode(f, FF_WR);
			p->cfg_a_rmode = 0;
		}
	}

	if(mode && O(cnt)) {	/* insert before */
		Fsetmode(f, FF_RD);
		EEsetpos(f, p->cfg_a_wpos);
		cfg_rsprd(optstru, f);
		EEsetpos(f, p->cfg_a_wpos);
		Esetmode(f, FF_WR);
	}
	else mode = 0;

	EEgetpos(f, p->cfg_a_wpos);		/* preserve as "previous" */
	cfg_rspwr(optstru, f, len, buf);

	if(mode) {			/* was inserted before */
		EEgetpos(f, p->cfg_a_wpos);		/* preserve as "previous" */
		cfg_rspwr(optstru, f, C(_hlen), C(_hbuf));
	}

	++O(cnt);

	DBG_EXIT
}
char * cfg_ostkRdFile(struct Cfg_Getopt * const optstru
	, struct Cfg_oStackGetopt * const ostk
	, int idx)
{	struct Cfg_ArgFileList *p;
	FILE *f;

	DBG_ENTER("cfg_ostkRdFile", Suppl_cmdline)

	assert(optstru);
	assert(ostk);

	if(idx > O(cnt) || (p = O(putArg)) == 0)
		DBG_RETURN_S( 0)

	assert(p->cfg_a_f);
	f = p->cfg_a_f;

	if(!p->cfg_a_rmode) {			/* bring the file into read mode */
		Fsetmode(f, FF_RD);
		p->cfg_a_rmode = 1;
	}
	else EEgetpos(f, p->cfg_a_rpos);	/* save the correct read position */

	if(idx >= O(idx)) {		/* re-use the known position */
		EEsetpos(f, p->cfg_a_rpos);
		idx -= O(idx);
	}
	else {					/* search from the start of the file */
		EEsetpos(f, p->cfg_a_fpos);	/* first non-removed entry */
	}
	do cfg_rsprd(optstru, f);
	while(idx--);
	EEsetpos(f, p->cfg_a_rpos);	/* file in read mode --> goto next read pos */
	DBG_RETURN_S( C(_hbuf))
}
char * cfg_ostkSqFile(struct Cfg_Getopt * const optstru
	, struct Cfg_oStackGetopt * const ostk)
{	struct Cfg_ArgFileList *p;
	FILE *f;

	DBG_ENTER("cfg_ostkSqFile", Suppl_cmdline)

	assert(optstru);
	assert(ostk);
	
	if(O(idx) >= O(cnt) || (p = O(putArg)) == 0)
		DBG_RETURN_S( 0)

	assert(p->cfg_a_f);
	f = p->cfg_a_f;

	if(!p->cfg_a_rmode) {			/* bring the file into read mode */
		Fsetmode(f, FF_RD);
		EEsetpos(f, p->cfg_a_rpos);
		p->cfg_a_rmode = 1;
	}

	cfg_rsprd(optstru, f);

	if(C(_removeAfterRead)) {	/* Don't physically delete, but make sure
								the direct read skips these entries */
		--O(cnt);
		EEgetpos(f, p->cfg_a_fpos);
	}
	else ++O(idx);

	DBG_RETURN_S( C(_hbuf))
}
void cfg_ostkClFile(struct Cfg_Getopt * const optstru
	, struct Cfg_oStackGetopt * const ostk)
{	struct Cfg_ArgFileList *p;

	DBG_ENTER("cfg_ostkClFile", Suppl_cmdline)

	assert(optstru);
	assert(ostk);
	
	if((p = O(putArg)) != 0) {
		Fxclose(p->cfg_a_f);
		free(p);
	}

	DBG_EXIT
	/** Warning: opstru never used **/
}
void cfg_ostkInitFile(struct Cfg_oStackGetopt *ostk)
{	DBG_ENTER("cfg_ostkInitFile", Suppl_cmdline)

	assert(ostk);

	/* the file is opened when it is used first */
	O(wrArg) = aF(cfg_ostkWrFile);
	O(rdArg) = aF(cfg_ostkRdFile);
	O(sqArg) = aF(cfg_ostkSqFile);
	O(clArg) = aF(cfg_ostkClFile);
	O(large) = 1;		/* unlimited number of arguments can be cached */

	DBG_EXIT
}
