DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T p

⟦3bb20e739⟧ TextFile

    Length: 11525 (0x2d05)
    Types: TextFile
    Names: »parsesbr.c«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦e7f64e0c0⟧ »EurOpenD3/mail/vmh.tar.Z« 
        └─⟦dcb95597f⟧ 
            └─⟦this⟧ »parsesbr.c« 

TextFile

#ifndef lint
static char rcsid[] =
	"$Header: parsesbr.c,v 1.2 86/02/27 16:09:15 deboor Exp $";

static char notice[] =
	"This program is in the public domain and is available for unlimited \
distribution as long as this notice is enclosed.";
#endif lint

/*
 * $Source: /c/support/deboor/usr/src/old/vmh/RCS/parsesbr.c,v $
 * $Revision: 1.2 $ $Date: 86/02/27 16:09:15 $
 * $Author: deboor $
 *
 * Routines for parsing a 'pick' criteria string.
 *
 * FUNCTIONS:
 *	parseExpr	parses the (fractured) expression and leaves the
 *			expression tree rooted to expRoot;
 */

#include "vmh.h"
#include "pick.h"

static	NODE	*parseStack[MAXARGS];	/* temp stack for actual parsing */
static	int	parseTop;		/* top of this stack */

static	nodeT	opStack[MAXARGS]; /* stack for infix->postfix translation */
static	int	opTop;		  /* top of operator stack */
static	int	numHeaders;		/* the number of headers in headers */

#ifdef DEBUG
u_char	marks[50][20];
int	nodeNum;

printTree (root)
	NODE	*root;
{
	bzero (marks, sizeof(marks));
	nodeNum = 0;
	(void) markTree (root, 0);
	nodeNum = 0;
	printIt (root, 0);
	DeBuG ("\n");
}

markTree (root, level)
	NODE	*root;
	int	level;
{
	register int	lnum,
			rnum,
			ournum,
			i;
	
	if (root->n_left != NILNODE) {
		lnum = markTree (root->n_left, level + 1);
	} else
		lnum = nodeNum;

	ournum = nodeNum++;

	for (i = lnum; i <= ournum; i++)
		marks[i][level] = 1;

	if (root->n_right != NILNODE) {
		rnum = markTree (root->n_right, level + 1);
	} else
		rnum = nodeNum - 1;

	for (i = ournum; i <= rnum; i++)
		marks[i][level] = 1;
	
	return (ournum);
}

printIt (root, level)
	NODE	*root;
	int	level;
{
	register int	i;

	if (root->n_left != NILNODE) {
		printIt (root->n_left, level + 1);
	}
	
	for (i = 0; i <= level; i++) {
		DeBuG ("%6s", marks[nodeNum][i] ? "|" : " ");
	}
	DeBuG ("-");
	switch (root->n_which) {
		case not: DeBuG ("not"); break;
		case and: DeBuG ("and"); break;
		case or: DeBuG ("or"); break;
		case body: DeBuG ("search %s", root->n_key1); break;
		case header: DeBuG ("%s %s",root->n_key1, root->n_key2);break;
		case before: DeBuG ("before %d/%d/%d",root->n_month,root->n_day,root->n_year); break;
		case after: DeBuG ("after %d/%d/%d", root->n_month,
			root->n_day, root->n_year); break;
		default: DeBuG ("???"); break;
	}
	DeBuG (" (%sdone; value = %s)\n", root->n_done == true ? "" : "not ",
		root->n_value == TRUE ? "TRUE" : root->n_value == FALSE ?
		"FALSE" : "UNKNOWN");
	nodeNum++;
	if (root->n_right != NILNODE) {
		printIt (root->n_right, level + 1);
	}
}
#endif DEBUG
/*
 * NODE *
 * makeNode (which, left, right, arg1, arg2, arg3)
 *	create a new NODE and install 'which' in the n_which field, 'left'
 *	in the n_left field and 'right' in the n_right field. Then, depending
 *	on the value of 'which', use arg[123] in one of the following ways:
 *
 *		which		arg1		arg2		arg3
 *		----------------------------------------------------
 *		and,or,not	unused		unused		unused
 *		header		key1 (header)	key2 (in header) unused
 *		body		key1 (to find)	unused		unused
 *		after,before	month		day		year
 *
 *	makeNode returns a pointer to the new node with n_done and n_value
 *	initialized properly.
 */
/*VARARGS3*/
static NODE *
makeNode (which, left, right, arg1, arg2, arg3)
	nodeT	which;	/* what type of node this is to be */
	NODE	*left,	/* its left child */
		*right;	/* its right child */
	caddr_t	arg1,	/* key1 for patterns, month for dates */
		arg2,	/* key2 for patterns, day for dates */
		arg3;	/* nothing for patterns, year for dates */
{
	register NODE	*tNode;

	tNode = AllocST(NODE);	/* allocate the new structure */

	tNode->n_left = left;	/* install the non-unionized parameters */
	tNode->n_right = right;
	tNode->n_which = which;

	tNode->n_done = false;	/* initialize traversal values */
	tNode->n_value = UNKNOWN;

	switch (which) {	/* deal with the union */
	case and:	/* operators have no further parameters */
	case or:
	case not:
		/* void */
		break;
	case body:	/* search patterns have but one key whose offsets */
			/* need to be determined */
		tNode->n_key1 = (char *) arg1;
		setoffsets (tNode->n_key1, tNode->n_key1offs);
		break;
	case header:	/* headers need to have the two keys */
			/* installed and their offsets determined */
		tNode->n_key1 = (char *) arg1;
		tNode->n_key2 = (char *) arg2;
		setoffsets (tNode->n_key1, tNode->n_key1offs);
		setoffsets (tNode->n_key2, tNode->n_key2offs);
		break;
	case after:	/* dates need the date slots filled in */
	case before:
		tNode->n_month = (int) arg1;
		tNode->n_day = (int) arg2;
		tNode->n_year = (int) arg3;
		break;
	default:	/* anything else is a screw up */
		punt ("internal error! (bad which in makeNode)");
		/*NOTREACHED*/
	}
	return tNode;
} /*makeNode*/

/*
 * days of the week (unused)
 */

static	struct	swit	days[] = {
	"sunday",	0,
	"monday",	0,
	"tuesday",	0,
	"wednesday",	0,
	"thursday",	0,
	"friday",	0,
	"saturday",	0,
	(char *) NULL,	0,
};

/*
 * doOp (opType)
 *	combine the operator opType with the 1 or 2 items on the top
 *	of the parseStack to form a subtree, then put the new node on
 *	the stack.
 */
static
doOp (opType)
	nodeT	opType;
{
	switch (opType) {
	case not:
		parseStack[parseTop-1] = makeNode (not, parseStack[parseTop-1],
						NILNODE);
		break;
	case and:
	case or:
		if (parseTop < 2) {
			errormsg ("too many operators", 1);
			return (0);
		}
		parseStack[parseTop-2] = makeNode(opType,parseStack[parseTop-1],
						parseStack[parseTop-2]);
		parseTop--;
		break;
	default:
		punt ("unknown opType received in doOp");
		/*NOTREACHED*/
	}
	return (1);
} /* doOp */

/*
 * DATE *
 * getDate (dstring)
 *	parse the date given by the string in dstring according to the
 *	following format:
 *		<day>.<month>,<year>
 *	the period and comma may be any non-digit and any item not present
 *	defaults to the current date.
 *	If there is an error in the string NULL is returned. The numbers are
 *	stored in static structure, so they must be copied if they are to be
 *	saved.
 */
static DATE *
getDate (dstring)
	char	*dstring;
{
	register char		*cp;
	register int		tNum;
	static	struct	tm	*timeNow = (struct tm *) NULL;
	time_t			cur,
				time();
	static	DATE		dateGotten;

	if (timeNow == (struct tm *) NULL) {
		cur = time ((time_t *) 0);
		timeNow = localtime (&cur);
	}

	dateGotten.day = timeNow->tm_mday;
	dateGotten.month = timeNow->tm_mon + 1;
	dateGotten.year = timeNow->tm_year;

	for (cp = dstring; *cp && !isdigit (*cp); cp++)
		;

	if (!*cp) {	/* no numbers. must be dow */
		/* now what??? */
		errormsg ("days of week not implemented (yet).", 1);
		return ((DATE *) NULL);
	} else {
		/*
		 * first is day
		 */
		for (tNum = 0; *cp && isdigit (*cp); cp++)
			tNum = tNum * 10 + *cp - '0';
		if (! tNum || tNum > 31) {
			errormsg ("day out of range", 1);
			return ((DATE *) NULL);
		}
		dateGotten.day = tNum;
		while (*cp && !isdigit (*cp))
			cp++;
		
		if (!*cp)
			return (&dateGotten);
		
		/*
		 * then comes the month
		 */
		for (tNum = 0; *cp && isdigit (*cp); cp++)
			tNum = tNum * 10 + *cp - '0';
		if (!tNum || tNum > 12) {
			errormsg ("month out of range", 1);
			return ((DATE *) NULL);
		}
		dateGotten.month = tNum;
		while (*cp && !isdigit (*cp))
			cp++;
		
		if (!*cp)
			return (&dateGotten);

		/*
		 * then the year
		 */
		for (tNum = 0; *cp && isdigit (*cp); cp++)
			tNum = tNum * 10 + *cp - '0';
		if (tNum > 1900)
			tNum -= 1900;

		if (tNum < 70) {
			errormsg ("time began in 1970", 1);
			return ((DATE *) NULL);
		}
		dateGotten.year = tNum;
		return (&dateGotten);
	}
} /*getDate*/


/*
 * possible keywords in command
 */
static	struct	swit	keywords[] = {
	"and",		0,
#define ANDKEY	0
	"or",		0,
#define ORKEY	1
	"not",		0,
#define NOTKEY	2
	"from",		0,
#define FROMKEY	3
	"to",		0,
#define TOKEY	4
	"cc",		0,
#define CCKEY	5
	"subject",	0,
#define SUBJKEY	6
	"after",	0,
#define AFTKEY	7
	"before",	0,
#define BEFKEY	8
	"search",	0,
#define SRCHKEY	9
	"sequence",	0,
#define SEQKEY	10
	"do",		0,
#define DOKEY	11
	"zero",		0,
#define ZEROKEY	12
	"nozero",	0,
#define NZROKEY	13
	(char *) NULL,	0,
#define NKEYS	14
};


parseExpr (ac, av)
	int	ac;
	char	**av;
{
	Reg2	char	*cp;
	Reg1	int	idx;
	char		err[60];
	DATE		*dt;

	parseTop = opTop = numHeaders = 0;
	dateGiven = searchBody = false;

	expRoot = NILNODE;

	for (idx = 0; idx < ac; idx++) {
		cp = av[idx];
		if (*cp == '(') {
			opStack[opTop++] = leftP;
			if (!*++cp)
				continue;
		} else if (*cp == ')') {
			while (opStack[--opTop] != leftP && opTop >= 0)
				if (doOp (opStack[opTop]) == 0)
					return (0);
			continue;
		}
		if (*cp == '-')
			cp++;
		switch (smatch (cp, keywords)) {
		case AMBIGSW:
			(void) snprintf (err, sizeof(err),
				"key %s ambiguous", cp);
			errormsg (err,1);
			return (0);
		case SEQKEY:
			if (++idx >= ac) {
				errormsg ("sequence needs argument", 1);
				return (0);
			}
			seqName = av[idx];
			break;
		case ZEROKEY:
			zeroSeq = true;
			break;
		case NZROKEY:
			zeroSeq = false;
			break;
		case ANDKEY:
			while (opTop-- && (opStack[opTop] == and ||
				opStack[opTop] == not))
					if (doOp (opStack[opTop]) == 0)
						return (0);
			opStack[++opTop] = and;
			opTop++;
			break;
		case ORKEY:
			/*
			 * only or, and, not and leftP can be on the operator
			 * stack and we pop all but left parentheses when
			 * processing an or
			 */
			while (opTop-- && opStack[opTop] != leftP)
					if (doOp (opStack[opTop]) == 0)
						return (0);
			opStack[++opTop] = or;
			opTop++;
			break;
		case NOTKEY:
			while (opTop-- && opStack[opTop] == not)
				if (doOp (opStack[opTop]) == 0)
					return (0);
			opStack[++opTop] = not;
			opTop++;
			break;
		case FROMKEY:
		case TOKEY:
		case CCKEY:
		case SUBJKEY:
		case UNKWNSW:	/* assume unknown is a header to search */
			if (++idx >= ac) {
				(void) snprintf (err, sizeof(err),
					"%s needs pattern", cp);
				errormsg (err, 1);
				return (0);
			}
			parseStack[parseTop++] = makeNode (header, NILNODE,
							NILNODE,
							cp,
							av[idx]);
			headers[numHeaders++] = av[idx-1];
			break;
		case DOKEY:
			if (++idx >= ac) {
				errormsg ("do needs a command string", 1);
				return (0);
			}
			Cmd = av[idx];
			break;
		case SRCHKEY:
			searchBody = true;
			if (++idx >= ac) {
				errormsg ("search needs a pattern", 1);
				return (0);
			}
			parseStack[parseTop++] = makeNode (body, NILNODE,
							NILNODE,
							av[idx]);
			break;
		case AFTKEY:
			if (++idx >= ac) {
				errormsg ("after needs a date", 1);
				return (0);
			}
			if ((dt = getDate (av[idx])) == (DATE *) NULL)
				return (0);
			parseStack[parseTop++] = makeNode (after, NILNODE,
							NILNODE,
							dt->month,
							dt->day,
							dt->year);
			dateGiven = true;
			break;
		case BEFKEY:
			if (++idx >= ac) {
				errormsg ("before needs a date", 1);
				return (0);
			}
			if ((dt = getDate (av[idx])) == (DATE *) NULL)
				return (0);
			parseStack[parseTop++] = makeNode (before, NILNODE,
							NILNODE,
							dt->month,
							dt->day,
							dt->year);
			dateGiven = true;
			break;
		default:
			punt ("smatch returned weird value in parseExpr!");
		}
	}

	while (opTop--)	/* flush operator stack */
		if (opStack[opTop] == leftP) {
			errormsg ("unmatched left parenthesis", 1);
			return (0);
		} else
			if (doOp (opStack[opTop]) == 0)
				return (0);

	if (parseTop != 1) {
		errormsg ("too few operators", 1);
		return (0);
	}
	if ((expRoot = parseStack[0]) == NILNODE)
		return (0);
	headers[numHeaders] = (char *) NULL;
#ifdef DEBUG
	printTree (expRoot);
#endif DEBUG
	return (1);
} /* parseExpr */