/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred."
 *
 */
/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*
 * Copyright  (c) 1985 AT&T
 *	All Rights Reserved
 */

#ident	"$Header: fm_mn_par.c 1.2 89/10/10 $@(#)vm.oh:src/oh/fm_mn_par.c	1.9"

#include	<stdio.h>
#include	<string.h>
#include	"wish.h"
#include	"token.h"
#include	"actrec.h"
#include	"fm_mn_par.h"
#include	"var_arrays.h"
#include	"terror.h"
#include	"eval.h"
#include	"vtdefs.h"
#include	"moremacros.h"

/*
** Frees one attribute.  This involves freeing the "def" if set,
** and the "cur" as an array if the flags say so, or as a string
** if set.
*/
void
freeattr(attr)
register struct attribute *attr;
{
	if (attr->flags & FREEIT) {
		if (attr->def)
			free(attr->def);
		if (attr->cur) {
			if (((attr->flags & RETS) == RET_LIST) || ((attr->flags & RETS) == RET_ARGS))
				listfree(attr->cur);
			else
				free(attr->cur);
		}
		free(attr);
	}
}

/*
** If the "single" array is NULL then this structure does
** not contain any data to be freed
*/
void
freeitup(fm_mn)
register struct fm_mn *fm_mn;
{
	register int i, j;
	int	lcv, lcv2;

	if (fm_mn->single.attrs == NULL)
		return;
	lcv = array_len(fm_mn->single.attrs);
	for (i = 0; i < lcv; i++)
		freeattr(fm_mn->single.attrs[i]);
	array_destroy(fm_mn->single.attrs);
	fm_mn->single.attrs = NULL;
	if (!fm_mn->multi)
		return;
	lcv = array_len(fm_mn->multi);
	for (j = 0; j < lcv; j++)
		if (fm_mn->multi[j].attrs) {
			lcv2 = array_len(fm_mn->multi[j].attrs);
			for (i = 0; i < lcv2; i++)
				freeattr(fm_mn->multi[j].attrs[i]);
			array_destroy(fm_mn->multi[j].attrs);
		}
	array_destroy(fm_mn->multi);
	fm_mn->multi = NULL;
}

/*
** Fills an array with the information from another (in this case, 
** the array of defaults.
*/
void
filldef(fld, defaults, no)
struct fld *fld;
struct attribute *defaults;
int no;
{
	int i;
	struct attribute *p;

	fld->attrs = (struct attribute **) array_create(sizeof(struct attribute *), no);
	for (i = 0; i < no; i++) {
		if (defaults[i].flags & MAKE_COPY) {
			p = new(struct attribute);
			*p = defaults[i];
			p->flags |= FREEIT;
		}
		else
			p = defaults + i;
		fld->attrs = (struct attribute **) array_append(fld->attrs, &p);
	}
}

/*
** Boosts a the sequence number for the whole object.  This will
** force every variable field to be evaluated.
*/
upseqno(fm_mn)
struct fm_mn *fm_mn;
{
	fm_mn->seqno++;
}

/*
** This parses an object.  The "flags" say whether info_or_file is 
** the information itself or the file of where the information sits.
** Sdfl, sdflsize, mdfl and mdflsize describe the default arrays and
** single and multi are the addresses of pointers to store the
** information in.
*/
parser(flags, info_or_file, sdfl, sdflsize, single, mdfl, mdflsize, multi)
int flags;
char *info_or_file;
struct attribute *sdfl;
int sdflsize;
struct fld *single;
struct attribute *mdfl;
int mdflsize;
struct fld **multi;
{
	int i;
	register char *val, *kwd;
	char mybuf[BUFSIZ];
	int more;
	IOSTRUCT *in, *out;
	struct fld *multiptr, ptr;
	FILE *fp;

	if (flags & INLINE) 
		in = io_open(EV_USE_STRING|EV_READONLY, info_or_file);
	else {
		if ((fp = fopen(info_or_file, "r")) == NULL) {
			warn(NOPEN, info_or_file);
			if (single)
				single->attrs = NULL;
			return;
		}
		setbuf(fp, mybuf);
		in = io_open(EV_USE_FP, fp);
	}
	out = io_open(EV_USE_STRING, NULL);
	while (more = eval(in, out, EV_GROUP)) {
		kwd = io_ret_string(out);
		if (val = strchr(kwd, '='))
			*val++ = '\0';
		else
			val = nil;
		for (i = 0; i < sdflsize; i++)
			if (strCcmp(kwd, sdfl[i].testring) == 0)
				break;
		if (i == sdflsize) {
			if (strCcmp(kwd, mdfl[0].testring) == 0)
				break;
		}
		else {
			struct attribute *hold;

			hold = new(struct attribute);
			memcpy(hold, single->attrs[i], sizeof(struct attribute));
			hold->flags |= FREEIT;
			hold->cur = NULL;
			hold->seqno = 0;
			set_def(single->attrs[i] = hold, strsave(val));
		}
		io_seek(out, 0);
	}

	multiptr = (struct fld *) array_create(sizeof(struct fld), 1024);
	for ( ; more; more = eval(in, out, EV_GROUP)) {
		if (!kwd) {
			kwd = io_ret_string(out);
			if (val = strchr(kwd, '='))
				*val++ = '\0';
			else
				val = nil;
		}
		for (i = 0; i < mdflsize; i++)
			if (strCcmp(kwd, mdfl[i].testring) == 0)
				break;
		if (i == 0) {		/* if its the first multi-descriptor */
			filldef(&ptr, mdfl, mdflsize);
			multiptr = (struct fld *) array_append(multiptr, &ptr);
		}
		if (i != mdflsize) {	/* if its the one we're looking for */
			struct attribute *hold;

			hold = new(struct attribute);
			memcpy(hold, ptr.attrs[i], sizeof(struct attribute));
			hold->flags |= FREEIT;
			hold->cur = NULL;
			hold->seqno = 0;
			/* don't comment out until you're SURE 
			if (mdfl[i].flags & MAKE_COPY)
				free(ptr.attrs[i]);
			*/
			set_def(ptr.attrs[i] = hold, strsave(val));
		}
		io_seek(out, 0);
		kwd = NULL;
	}
	multiptr = (struct fld *) array_shrink(multiptr);
	*multi = multiptr;
	io_close(out);
	io_close(in);
}

/*
** This puts the args into an altenv ($ARG1, $ARG2 and $ARG3)
*/
void
setupenv(flags, args, altenv)
int flags;
register char **args;
register char ***altenv;
{
	char buf[BUFSIZ];
	char argbuf[6];
	char *envbuf;
	register int i;

	strcpy(argbuf, "ARG1=");
	for (i = flags & INLINE ? 2 : 1; args[i]; i++, (argbuf[3])++) {
		int dofree, maxamt, amt;

		dofree = 0;
		maxamt = BUFSIZ - sizeof(argbuf) - 2;
		if ((amt = strlen(args[i])) > maxamt) { 
			/*
			 * Value is greater than 1K so malloc 
			 * enough space to hold it. 
			 */
			maxamt = amt + sizeof(argbuf) + 2;
			if ((envbuf = (char *) malloc(maxamt)) == NULL)
				fatal(NOMEM, nil); 
			dofree++;
		}
		else {
			/*
			 * ... otherwise, use static 1K buffer
			 */
			envbuf = buf;
			dofree = 0;
		}
		strcpy(envbuf, argbuf);
		strncat(envbuf, args[i], maxamt);
		putaltenv(altenv, envbuf);
		if (dofree)	/* if buffer was malloc'd, free it */
			free(envbuf);
	}
	argbuf[4] = '\0';
	while(delAltenv(argbuf) == SUCCESS)
		(argbuf[3])++;
	copyAltenv(*altenv);
}

/*
** This will setup the lifetime and positioning for an object.
*/
void
life_and_pos(a, life, begrow, begcol, prow, pcol, ptype)
register struct actrec *a;
register char *life;
register char *begrow;
register char *begcol;
int *prow;
int *pcol;
int *ptype;
{
	*prow = VT_UNDEFINED;
	*pcol = VT_UNDEFINED;
	*ptype = 0;
	if (strCcmp(begrow, "current") == 0)
		*ptype = VT_COVERCUR;
	else if (strCcmp(begrow, "center") == 0)
		*ptype = VT_CENTER;
	else if (strCcmp(begrow, "distinct") == 0)
		*ptype = VT_NOCOVERCUR;
	else {
		if (!(*prow = atoi(begrow)))
			*prow = VT_UNDEFINED;
	}
	if (*prow != VT_UNDEFINED) {
		if (!(*pcol = atoi(begcol)))
			*pcol = VT_UNDEFINED;
	}
	if (life) {
		if (strCcmp(life, "shortterm") == 0)
			a->lifetime = AR_SHORTERM;
		else if (strCcmp(life, "permanent") == 0)
			a->lifetime = AR_PERMANENT;
		else if (strCcmp(life, "immortal") == 0)
			a->lifetime = AR_IMMORTAL;
		else
			a->lifetime = AR_LONGTERM;
	}
}
