[comp.sources.unix] v17i088: Ease2.0, a language for sendmail.cf files, Part02/03

rsalz@uunet.uu.net (Rich Salz) (02/09/89)

Submitted-by: Arnold D. Robbins <arnold@EMORYU1.ARPA>
Posting-number: Volume 17, Issue 88
Archive-name: ease2/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 3)."
# Contents:  src/emitcf.c src/lexan.l src/parser.y src/strops.c
# Wrapped by rsalz@papaya.bbn.com on Wed Feb  8 16:55:43 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/emitcf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/emitcf.c'\"
else
echo shar: Extracting \"'src/emitcf.c'\" \(7475 characters\)
sed "s/^X//" >'src/emitcf.c' <<'END_OF_FILE'
X/*	$Header: emitcf.c,v 2.0 88/06/15 14:40:47 root Exp $	*/
X
X/*
X * $Log:	emitcf.c,v $
X * Revision 2.0  88/06/15  14:40:47  root
X * Baseline release for net posting. ADR.
X * 
X */
X
X/*
X *	emitcf.c  -- This file contains routines associated with the writing
X *		     and formatting of a translated sendmail configuration file.
X *
X *	author	  -- James S. Schoner, Purdue University Computing Center,
X *			  	       West Lafayette, Indiana  47907
X *
X *  	date	  -- July 9, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X */
X
X#include <stdio.h>
X#include "symtab.h"
X#include "fixstrings.h"
X
X#define REGLINE 60	/* length of output lines which may be continued */
X#define MAXLINE 256	/* liberal maximum line length			 */
X
Xextern short Rformat;			/* read-format flag for a class  */
Xextern char *MacScan ();
Xextern char  MakeMac ();
Xextern void  PrintError (),
X	     FatalError (),
X	     PrintWarning (),
X	     ErrorReport ();
X
Xvoid  PrintDef ();
X
Xstatic char ClassCH;			/* printable class macro char    */
X
X/*
X *	EmitDef () -- Emit a definition line (Ease block definition) in cf 
X *		      format.
X *
X */
Xvoid
XEmitDef (blockdef, targ, defstr1, defstr2)
Xregister enum bdefs blockdef;	/* type of definition   	 */
Xregister struct he *targ;	/* target to be defined 	 */
Xchar *defstr1, *defstr2;	/* one or two definition strings */
X{
X	/*
X	 *  This routine is about as pretty as a translated ease file...
X	 *  Each type of line (Ease block) is handled case by case below.
X	 *
X	 */
X	switch (blockdef) {
X		case def_macro:		printf ("D%c", MakeMac (targ, ID_MACRO));
X					PrintDef (def_macro, MacScan (defstr1));
X					if (ISMACRO(targ->idd))
X						PrintWarning ("Redefining macro %s.\n", targ->psb);
X					targ->idd |= ID_MACRO;  /* signal definition */
X					break;
X
X		case def_class:		if (Rformat)	/* read format */
X						printf ("F");
X					else
X						printf ("C");
X					printf ("%c", ClassCH = MakeMac (targ, ID_CLASS));
X					if (Rformat) {	/* read format */
X						printf ("%s\n", defstr1);
X						Rformat = FALSE;
X					} else
X						PrintDef (def_class, defstr1);
X					if (ISCLASS(targ->idd))
X						PrintWarning ("Redefining class %s.\n", targ->psb);
X					targ->idd |= ID_CLASS;  /* signal definition */
X					break;
X
X		case def_option:	if (defstr1 == NULL)
X						FatalError ("No option passed in EmitDef()", (char *)NULL);
X					printf ("O%c", *defstr1);
X					PrintDef (def_option, defstr2);
X					break;
X
X		case def_prec:		printf ("P%s=%d\n", targ->psb, targ->idval.prec);
X					break;
X
X		case def_trusted:	printf ("T");
X					PrintDef (def_trusted, defstr1);
X					break;
X
X		case def_header:	printf ("H");
X					if (defstr1 != NULL)
X						printf ("?%s?", defstr1);
X					PrintDef (def_header, defstr2);
X					break;
X
X		case def_mailer:	if (ISMAILER(targ->idtype)) {
X						if (ISMAILER(targ->idd))
X							PrintWarning ("Redefining mailer %s.\n", targ->psb);
X					} else if (ISTYPED(targ->idtype)) {
X						PrintError ("Redeclaration of identifier as mailer:", targ->psb);
X						return;
X					}
X					targ->idd |= ID_MAILER;  /* signal definition */
X					printf ("M%s, ", targ->psb);
X					PrintDef (def_mailer, defstr1);
X					break;
X
X		case def_ruleset:	printf ("R");
X					PrintDef (def_ruleset, defstr1);
X					break;
X
X		default:		FatalError ("Bad case in EmitDef ()", (char *) NULL);
X	}
X}
X
X
X/*
X *  	PrintContinued () -- Print a line definition (buf) by splitting it over
X *			     more than one line.  The two definition types 
X *			     accepted for this method of continuation are class
X *			     and trusted user lists, indicated in the argument 
X *			     btype 
X *
X */
Xvoid
XPrintContinued (btype, buf)
Xenum bdefs     btype;	/* block (line) type for definition */
Xregister char *buf;	/* buffer containing the definition */
X{
X	register char *tmp;	/* breakpoint search pointer   */
X	register char  tc;	/* temporary swap byte         */
X	int  buflen;		/* length of definition buffer */	
X
X	buflen = strlen (buf);
X	tmp = buf + REGLINE;
X	while ((*--tmp != ' ') && (tmp != buf))	 /* look for suitable break */
X		/* null */ ;
X	if (tmp == buf) {
X		for (tmp = buf + REGLINE; (*tmp != ' ') && (tmp - buf != buflen); tmp++)
X			/* null */ ;
X		if ((tmp - buf) >= MAXLINE)
X			PrintWarning ("Member name may be too long.\n", (char *) NULL);
X	}
X	tc = *tmp;		/* swap break char with null char */
X	*tmp = '\0';
X	printf ("%s\n", buf);
X	if ((*tmp = tc) == '\0')
X		return;
X	else
X		tmp++;
X	if (btype == def_class)		/* start next line   */
X		printf ("C%c", ClassCH);
X	else
X		printf ("T");
X	if (strlen (tmp) < REGLINE)	/* continue the line */
X		printf ("%s\n", tmp);
X	else
X		PrintContinued (btype, tmp);
X}
X
X
X/*
X *	PrintDef () -- Handles special cases (like line continuation) when 
X *		       printing definitions.
X *
X */
Xvoid
XPrintDef (btype, dstr)
Xregister enum bdefs btype;	/* block type (output line type) */
Xregister char *dstr;		/* definition string		 */
X{
X	register char *tmp;
X
X	if (dstr == (char *)NULL)
X		dstr = "";
X
X	for (tmp = dstr; *tmp != '\0'; tmp++) 	/* search for line continuations */
X		if ((*tmp == '\\') && (*++tmp == '\n'))
X			if (btype != def_header) {
X				ErrorReport ("Non-header string contains line continuation\n");
X				return;
X			} else
X				break;
X
X	/*
X	 *  Perform case by case handling of definition printing.
X	 *
X	 */
X	switch (btype) {
X		case def_header :  if (*tmp-- == '\n') {
X					*tmp = '\0';
X					if (tmp - dstr >= MAXLINE)
X						PrintWarning ("Header may be too long.\n", 
X							      (char *) NULL);
X					printf ("%s\n\t", dstr);
X					tmp += 2;
X				        PrintDef (def_header, tmp);
X				   } else {
X					if (strlen (dstr) >= MAXLINE)
X						PrintWarning ("Header may be too long.\n", 
X							      (char *) NULL);
X					printf ("%s\n", dstr);
X				   }
X				   break;
X
X		case def_mailer :  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Mailer definition may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_ruleset:  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Rewriting rule may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_option :  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Option assignment may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_macro  :  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Macro assignment may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_prec   :  if (strlen (dstr) >= MAXLINE)
X					PrintWarning ("Precedence relation may be too long.\n", 
X						      (char *) NULL);
X				   printf ("%s\n", dstr);
X				   break;
X
X		case def_trusted:
X		case def_class  :  if (strlen (dstr) < REGLINE)
X					printf ("%s\n", dstr);
X				   else		/* use line continuation feature */
X				   	PrintContinued (btype, dstr);
X				   break;
X
X		default         :  FatalError ("Invalid case in PrintDef ()", (char *) NULL);
X	}
X}
X
X
X/*
X *	StartRuleset () -- Prints a ruleset heading for the ruleset identifier
X *		           contained in the argument rsid.
X *
X */
Xvoid
XStartRuleset (rsid)
Xregister struct he *rsid;	/* ruleset identifier */
X{
X	if (!ISRULESET(rsid->idtype))
X		if (ISTYPED(rsid->idtype))
X			PrintError ("Identifier not of ruleset type:", rsid->psb);
X		else
X			PrintError ("Ruleset identifier not bound to a number:", rsid->psb);
X	else {
X		if (ISRULESET(rsid->idd))
X			PrintWarning ("Redefining ruleset %s.\n", rsid->psb);
X		rsid->idd |= ID_RULESET;
X		printf ("S%s\n", rsid->idval.rsn);
X	}
X}
END_OF_FILE
if test 7475 -ne `wc -c <'src/emitcf.c'`; then
    echo shar: \"'src/emitcf.c'\" unpacked with wrong size!
fi
chmod +x 'src/emitcf.c'
# end of 'src/emitcf.c'
fi
if test -f 'src/lexan.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/lexan.l'\"
else
echo shar: Extracting \"'src/lexan.l'\" \(6834 characters\)
sed "s/^X//" >'src/lexan.l' <<'END_OF_FILE'
X%{
X/*	$Header: lexan.l,v 2.0 88/06/15 15:11:30 root Exp $ */
X
X/*
X * $Log:	lexan.l,v $
X * Revision 2.0  88/06/15  15:11:30  root
X * Baseline release for net posting. ADR.
X * 
X */
X
X/*
X *	lexan.l -- Lexical Analyzer for EASE.
X *
X *		   Contains code for lex(1) which generates a lexical
X *		   analyzer (lex.yy.c) for Ease, a high-level specification 
X *		   format for sendmail configuration files.
X *
X *	author -- James S. Schoner, Purdue University Computing Center,
X *				    West Lafayette, Indiana  47907
X *
X *	date   -- July 1, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X */
X
X#include "fixstrings.h"
X#include "symtab.h"
X#include "lexdefs.h"
X
X#define  LEXnewline '\n'
X#define	 LEXeof	    '\0'
X#define  MaxFN	    200			/* maximum file name length */
X
Xextern struct he *LookupSymbol ();
Xextern void	  ErrorReport ();
X
Xint  Lcount;				/* line counter		    */
Xchar FNbuf[MaxFN];			/* file name buffer	    */
Xshort RMatch  = FALSE;			/* ruleset match flag  	    */
X
X#undef input
X# define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):Getc(yyin,yyout))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
X
Xchar
XGetc (yyin, yyout)
X	FILE *yyin, *yyout;
X{
X	static char linbuf[BUFSIZ], *pc = linbuf;
X	char c;
X
X	/* initialize buffer: first call only */
X	if (*pc == '\0' && pc == linbuf) {
X		if (fgets(linbuf, BUFSIZ, yyin)==NULL)
X			return EOF;
X		fprintf(yyout, "# %s", linbuf);  /* echo input as comment */
X	}
X	c = *pc++;
X	if (c == '\n') {
X		pc = linbuf;
X		if (fgets(linbuf, BUFSIZ, yyin) == NULL)
X			*pc = EOF;
X		else
X			/* echo input as comment */
X			fprintf(yyout, "# %s", linbuf);
X	}
X	return c;
X}
X
X/*
X * Table of keywords. NOTE: This is in sorted order, and
X * must stay that way if anything else is added to it.
X */
Xstatic struct resword {
X	char	*r_text;
X	int	r_tokval;
X} reswords[] = {
X	{ "Argv",		MARGV },
X	{ "Eol",		MEOL },
X	{ "Flags",		MFLAGS },
X	{ "Maxsize",		MMAXSIZE },
X	{ "Path",		MPATH },
X	{ "Recipient",		MRECIPIENT },
X	{ "Sender",		MSENDER },
X	{ "bind",		BIND },
X	{ "canon",		CANON },
X	{ "class",		CLASS },
X	{ "concat",		CONCAT },
X	{ "d_background",	DOPTB },
X	{ "d_interactive",	DOPTI },
X	{ "d_queue",		DOPTQ },
X	{ "define",		DEFINE },
X	{ "f_addrw",		CCFLAG },
X	{ "f_arpa",		AAFLAG },
X	{ "f_date",		DDFLAG },
X	{ "f_dot",		XXFLAG },
X	{ "f_escape",		EEFLAG },
X	{ "f_expensive",	EFLAG },
X	{ "f_ffrom",		FFLAG },
X	{ "f_from",		FFFLAG },
X	{ "f_full",		XFLAG },
X	{ "f_llimit",		LLFLAG },
X	{ "f_locm",		LFLAG },
X	{ "f_mesg",		MMFLAG },
X	{ "f_mult",		MFLAG },
X	{ "f_noreset",		SSFLAG },
X	{ "f_noufrom",		NFLAG },
X	{ "f_retsmtp",		PFLAG },
X	{ "f_return",		PPFLAG },
X	{ "f_rfrom",		RFLAG },
X	{ "f_rport",		RRFLAG },
X	{ "f_smtp",		IIFLAG },
X	{ "f_strip",		SFLAG },
X	{ "f_ufrom",		UUFLAG },
X	{ "f_upperh",		HFLAG },
X	{ "f_upperu",		UFLAG },
X	{ "field",		FIELD },
X	{ "for",		FOR },
X	{ "h_exit",		EOPTE },
X	{ "h_mail",		EOPTM },
X	{ "h_mailz",		EOPTZ },
X	{ "h_print",		EOPTP },
X	{ "h_write",		EOPTW },
X	{ "header",		HEADER },
X	{ "host",		HOST },
X	{ "hostnum",		HOSTNUM },
X	{ "if",			IF },
X	{ "ifset",		IFSET },
X	{ "in",			IN },
X	{ "macro",		MACRO },
X	{ "mailer",		MAILER },
X	{ "map",		MAP },
X	{ "match",		MATCH },
X	{ "next",		NEXT },
X	{ "o_alias",		AAOPT },
X	{ "o_bsub",		BBOPT },
X	{ "o_checkpoint",	CCOPT },
X	{ "o_delivery",		DOPT },
X	{ "o_dmuid",		UOPT },
X	{ "o_dnet",		NNOPT },
X	{ "o_ewait",		AOPT },
X	{ "o_flog",		SSOPT },
X	{ "o_fsmtp",		HHOPT },
X	{ "o_gid",		GOPT },
X	{ "o_handling",		EOPT },
X	{ "o_hformat",		OOPT },
X	{ "o_loadnc",		XXOPT },
X	{ "o_loadq",		XOPT },
X	{ "o_newproc",		YYOPT },
X	{ "o_pmaster",		PPOPT },
X	{ "o_prifactor",	ZOPT },
X	{ "o_qdir",		QQOPT },
X	{ "o_qfactor",		QOPT },
X	{ "o_qtimeout",		TTOPT },
X	{ "o_qwait",		COPT },
X	{ "o_rebuild",		DDOPT },
X	{ "o_recipfactor",	YOPT },
X	{ "o_rsend",		MOPT },
X	{ "o_safe",		SOPT },
X	{ "o_skipd",		IOPT },
X	{ "o_slog",		LLOPT },
X	{ "o_timezone",		TOPT },
X	{ "o_tmode",		FFOPT },
X	{ "o_tread",		ROPT },
X	{ "o_usave",		FOPT },
X	{ "o_validate",		NOPT },
X	{ "o_verbose",		VOPT },
X	{ "o_waitfactor",	ZZOPT },
X	{ "o_wizpass",		WWOPT },
X	{ "options",		OPTIONS },
X	{ "precedence",		PRECEDENCE },
X	{ "readclass",		READCLASS },
X	{ "resolve",		RESOLVE },
X	{ "retry",		RETRY },
X	{ "return",		RETURN },
X	{ "ruleset",		RULESET },
X	{ "trusted",		TRUSTED },
X	{ "user",		USER },
X	{ "while",		IF },
X};
X%}
X
X%%
X	int INch;			/* any input character */
X
X[ \t\f]+			; 	/* discard whitepsace  */
X[\n]				Lcount++;
X^\#[ \t]*[0-9]+[ \t]*\".*\"[ \t]*[\n]	{
X			        sscanf (yytext, "%*c%d%s", &Lcount, FNbuf);
X			        }
X[A-Za-z][A-Za-z0-9_-]*		{
X				register int l, h, m, r, c;
X
X				l = 0;
X				h = (sizeof (reswords) / sizeof(reswords[0])) - 1;
X				while (l <= h) {
X					m = (h + l) / 2;
X					c = yytext[0] - reswords[m].r_text[0];
X					r = c ? c : strcmp (yytext, reswords[m].r_text);
X					if (r < 0)
X						h = m - 1;
X					else if (r > 0)
X						l = m + 1;
X					else
X						return reswords[m].r_tokval;
X				}
X
X				/* not a keyword */
X
X				/* store identifiers in symbol table */
X				yylval.phe = LookupSymbol (yytext);
X				return (IDENT);
X				}
X["]((\\\n)|(\\\")|[^"\n])*	{
X				if ((INch = input()) == LEXnewline) {
X					ErrorReport ("End of line in string.\n");
X					unput (INch);
X				}
X				fixquotes ();
X				yylval.psb = (char *) malloc (strlen (yytext) + 1);
X				strcpy (yylval.psb, yytext + 1);
X				return (SCONST);
X				}
X[0][0-7]*			{
X				sscanf (yytext, "%o", &yylval.ival);  /* octal constant */
X				return (ICONST);
X				}
X[-]?[1-9][0-9]*			{
X				yylval.ival = atoi (yytext);
X				return (ICONST);
X				}
X"="				return (ASGN);
X","				return (COMMA);
X"{"				return (LBRACE);
X"}"				return (RBRACE);
X"("				return (LPAREN);
X")"				return (RPAREN);
X";"				return (SEMI);
X"$"				return (DOLLAR);
X":"				return (COLON);
X"*"				return (STAR);
X"/*"				{
X				/* eat C comments */
X				INch = input ();
X				while ((INch != '*') || 
X				      ((INch = input ()) != '/')) {
X					if (INch == LEXnewline)
X						Lcount++;
X					else
X						if (INch == LEXeof) {
X							ErrorReport ("End of file in comment.\n");
X							break;
X						}
X					if (INch != '*')
X						INch = input ();
X				}
X				}
X[\\]?.				{
X				if (RMatch) {	/* in rulesets, return literal character */
X					yylval.ival = (yytext[0] == '\\') ? yytext[1] : yytext[0];
X					return (SEPCHAR);
X				} else {
X					ErrorReport ("Illegal delimiter character");
X					printf (": (octal code) \\%03o\n", *yytext);
X				}
X				}
X%%
X
X/*
X * fixquotes --- inside a "quoted string", turn `\"' into just `"'
X *
X * this is most useful inside the Argv strings for mailers,
X * particularly when debugging.
X */
X
Xfixquotes ()
X{
X	register char *cp1, *cp2;
X
X	cp1 = cp2 = yytext;
X	while (*cp2) {
X		/*
X		 * if we really wanted to get fancy,
X		 * at this point we'd handle C escapes,
X		 * but I don't think it's necessary.
X		 */
X		if (*cp2 == '\\' && cp2[1] == '"')
X			cp2++;
X		*cp1++ = *cp2++;
X	}
X	*cp1++ = *cp2++;	/* final '\0' */
X}
END_OF_FILE
if test 6834 -ne `wc -c <'src/lexan.l'`; then
    echo shar: \"'src/lexan.l'\" unpacked with wrong size!
fi
chmod +x 'src/lexan.l'
# end of 'src/lexan.l'
fi
if test -f 'src/parser.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/parser.y'\"
else
echo shar: Extracting \"'src/parser.y'\" \(15988 characters\)
sed "s/^X//" >'src/parser.y' <<'END_OF_FILE'
X%{
X/*	$Header: parser.y,v 2.0 88/06/15 14:42:46 root Exp $	*/
X
X/*
X * $Log:	parser.y,v $
X * Revision 2.0  88/06/15  14:42:46  root
X * Baseline release for net posting. ADR.
X * 
X */
X
X/*
X *	parser.y -- EASE parser.
X *
X *		    Contains code for yacc(1) which produces a parser (y.tab.c)
X *		    for Ease, a specification format for sendmail configuration
X *		    files.
X *
X *	author   -- James S. Schoner, Purdue University Computing Center,
X *		    		      West Lafayette, Indiana  47907
X *
X *	date     -- July 2, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X */
X
X#include "fixstrings.h"
X#include <stdio.h>
X#include "symtab.h"
X
Xextern void	   BindID ();
Xextern void	   EmitDef ();
Xextern char	  *ListAppend ();
Xextern char 	  *MakeCond ();
Xextern char	  *MakeRStr ();
Xextern char       *ConvOpt ();
Xextern char	  *ConvFlg ();
Xextern char	  *MacScan ();
Xextern char	  *ConvMat ();
Xextern void	   StartRuleset ();
Xextern char	  *MakePosTok ();
Xextern char	  *GetField ();
Xextern char	  *Bracket ();
Xextern char	  *MakeRSCall ();
Xextern char	  *CheckMailer ();
Xextern char	  *CheckRS ();
Xextern char	  *MakeField ();
Xextern char	   MakeMac ();
Xextern void	   AssignType ();
Xextern void	   RemoveSymbol ();
Xextern void	   yyerror ();
X
Xextern short RMatch;		/* ruleset match flag 		      */
X
Xchar *Cbuf = " ";		/* character buffer   		      */
Xchar *Mbuf = "$ ";		/* macro buffer	      		      */
Xchar *Tsb;			/* pointer to temporary string buffer */
Xchar *Flaglist;			/* pointer to header flag list	      */
X
X%}
X
X%union {			/* value stack element type    */
X	int	  ival;		/* integer token 	       */
X	char	  *psb;		/* string token		       */
X	struct he *phe;		/* pointer to hash entry       */
X	enum opts optval;	/* sendmail options	       */
X	enum flgs flgval;	/* mailer flags		       */
X	enum mats mpval;	/* mailer attribute parameters */
X}
X
X%start config
X
X%token 	<phe>	IDENT
X%token  <psb>	SCONST
X%token  <ival>	ICONST SEPCHAR
X%token BIND CANON CLASS CONCAT FOR HEADER HOST HOSTNUM IF IFSET IN
X%token MACRO MAILER MAP MARGV MATCH MEOL MFLAGS MMAXSIZE MPATH
X%token MRECIPIENT MSENDER NEXT OPTIONS PRECEDENCE READCLASS RESOLVE
X%token RETRY RETURN RULESET TRUSTED USER
X
X%token ASGN COLON COMMA DEFINE DOLLAR FIELD LBRACE LPAREN RBRACE
X%token RPAREN SEMI STAR
X
X%token AAOPT AOPT BBOPT CCOPT COPT DDOPT DOPT DOPTB DOPTI DOPTQ EOPT
X%token EOPTE EOPTM EOPTP EOPTW EOPTZ FFOPT FOPT GOPT HHOPT IOPT LLOPT
X%token MOPT NNOPT NOPT OOPT PPOPT QOPT QQOPT ROPT SOPT SSOPT TOPT TTOPT
X%token UOPT VOPT WWOPT XOPT XXOPT YOPT YYOPT ZOPT ZZOPT
X
X%token AAFLAG CCFLAG DDFLAG EEFLAG EFLAG FFFLAG FFLAG HFLAG IIFLAG LFLAG
X%token LLFLAG MFLAG MMFLAG NFLAG PFLAG PPFLAG RFLAG RRFLAG SFLAG SSFLAG
X%token UFLAG UUFLAG XFLAG XXFLAG
X
X%type	<psb>		mval strval ifcon conval ifres elseres nameset namelist
X%type	<psb>		doptid eoptid idlist fcond dlist mflags route mdefs
X%type	<psb>		matchaddr matchtok action actionstmt mailerspec mtdef
X%type	<psb>		rwaddr rwtok ftype reftok rword cantok resolution
X%type	<psb>		userspec hword hostid dheader
X%type	<psb>		catstring canval canvaltok
X%type	<ival>		anychar
X%type	<phe>		cdef
X%type	<optval>	optid
X%type	<flgval>	flagid
X%type	<mpval>		mvar
X
X%left COMMA
X%left LPAREN RPAREN
X%nonassoc SCONST
X
X%%
Xconfig		:	/* empty */
X		|	config blockdef
X		|	error blockdef
X		;
X
Xblockdef	:	BIND bindings
X		|	MACRO macdefs
X		|	CLASS classdefs
X		|	OPTIONS optdefs
X		|	PRECEDENCE precdefs
X		|	TRUSTED tlist
X		|	HEADER hdefs
X		|	MAILER mlist
X		|	RULESET rdef
X		|	FIELD fdefs
X		;
X
Xbindings	:	/* empty */
X		|	bindings IDENT ASGN RULESET ICONST SEMI {
X				BindID ($2, $5, ID_RULESET);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xmacdefs		:	/* empty */
X		|	macdefs IDENT ASGN mval SEMI {
X				EmitDef (def_macro, $2, $4, (char *) NULL);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xmval		:	strval				%prec COMMA {
X				$$ = $1;
X			}
X		|	CONCAT LPAREN conval RPAREN {
X				$$ = $3;
X			}
X		;
X
Xstrval		:	SCONST {
X				$$ = $1;
X			}
X		|	strval SCONST {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		;
X
Xconval		:	strval COMMA ifcon {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($1);
X				free ($3);
X			}
X		|	ifcon COMMA strval {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($1);
X				free ($3);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xifcon		:	IFSET LPAREN IDENT COMMA ifres RPAREN {
X				$$ = MakeCond ($3, $5);
X			}
X		;
X
Xifres		:	mval elseres {
X				if ($2 != NULL) {
X					$$ = ListAppend ($1, $2, "$|");
X					free ($1);
X					free ($2);
X				} else
X					$$ = $1;
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xelseres		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	COMMA mval {
X				$$ = $2;
X			}
X		;
X
Xclassdefs	:	/* empty */ 
X		|	classdefs IDENT ASGN nameset {
X				EmitDef (def_class, $2, $4, (char *) NULL);
X			}
X		|	error
X		;
X
Xnameset		:	LBRACE namelist RBRACE SEMI {
X				$$ = $2;
X			}
X		|	LBRACE RBRACE SEMI {
X				$$ = NULL;
X			}
X		|	LBRACE error RBRACE SEMI {
X				$$ = NULL;
X			}
X		|	READCLASS LPAREN strval RPAREN SEMI {
X				$$ = MakeRStr ($3, (char *) NULL);
X			}
X		|	READCLASS LPAREN strval COMMA strval RPAREN SEMI {
X				$$ = MakeRStr ($3, $5);
X			}
X		|	READCLASS LPAREN error RPAREN SEMI {
X				$$ = NULL;
X			}
X		|	error SEMI {
X				$$ = NULL;
X				yyerrok;
X			}
X		;
X
Xnamelist	:	IDENT {
X				$$ = ListAppend ($1->psb, (char *) NULL, (char *) NULL);
X				RemoveSymbol ($1);
X			}
X		|	strval {
X				$$ = $1;
X			}
X		|	namelist COMMA IDENT {
X				$$ = ListAppend ($1, $3->psb, " ");
X				free ($1);
X				RemoveSymbol ($3);
X			}
X		|	namelist COMMA strval {
X				$$ = ListAppend ($1, $3, " ");
X				free ($1);
X				free ($3);
X			}
X		;
X
Xoptdefs		:	/* empty */
X		|	optdefs optid ASGN strval SEMI {
X				EmitDef (def_option, (struct he *) NULL, ConvOpt ($2), $4);
X			}
X		|	optdefs DOPT ASGN doptid SEMI {
X				EmitDef (def_option, (struct he *) NULL, ConvOpt (opt_d), $4);
X			}
X		|	optdefs EOPT ASGN eoptid SEMI {
X				EmitDef (def_option, (struct he *) NULL, ConvOpt (opt_e), $4);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xoptid		:	AAOPT {
X				$$ = opt_A;
X			}
X		|	AOPT {
X				$$ = opt_a;
X			}
X		|	BBOPT {
X				$$ = opt_B;
X			}
X		|	CCOPT {
X				$$ = opt_C;
X			}
X		|	COPT {
X				$$ = opt_c;
X			}
X		|	DDOPT {
X				$$ = opt_D;
X			}
X		|	FFOPT {
X				$$ = opt_F;
X			}
X		|	FOPT {
X				$$ = opt_f;
X			}
X		|	GOPT {
X				$$ = opt_g;
X			}
X		|	HHOPT {
X				$$ = opt_H;
X			}
X		|	IOPT {
X				$$ = opt_i;
X			}
X		|	LLOPT {
X				$$ = opt_L;
X			}
X		|	MOPT {
X				$$ = opt_m;
X			}
X		|	NNOPT {
X				$$ = opt_N;
X			}
X		|	NOPT {
X				$$ = opt_n;
X			}
X		|	PPOPT {
X				$$ = opt_P;
X			}
X		|	OOPT {
X				$$ = opt_o;
X			}
X		|	QQOPT {
X				$$ = opt_Q;
X			}
X		|	QOPT {
X				$$ = opt_q;
X			}
X		|	ROPT {
X				$$ = opt_r;
X			}
X		|	SSOPT {
X				$$ = opt_S;
X			}
X		|	SOPT {
X				$$ = opt_s;
X			}
X		|	TTOPT {
X				$$ = opt_T;
X			}
X		|	TOPT {
X				$$ = opt_t;
X			}
X		|	UOPT {
X				$$ = opt_u;
X			}
X		|	VOPT {
X				$$ = opt_v;
X			}
X		|	WWOPT {
X				$$ = opt_W;
X			}
X		|	XOPT {
X				$$ = opt_x;
X			}
X		|	XXOPT {
X				$$ = opt_X;
X			}
X		|	YOPT {
X				$$ = opt_y;
X			}
X		|	YYOPT {
X				$$ = opt_Y;
X			}
X		|	ZOPT {
X				$$ = opt_z;
X			}
X		|	ZZOPT {
X				$$ = opt_Z;
X			}
X		;
X
Xdoptid		:	DOPTI {
X				$$ = ConvOpt (d_opt_i);
X			}
X		|	DOPTB {
X				$$ = ConvOpt (d_opt_b);
X			}
X		|	DOPTQ {
X				$$ = ConvOpt (d_opt_q);
X			}
X		;
X
Xeoptid		:	EOPTP {
X				$$ = ConvOpt (e_opt_p);
X			}
X		|	EOPTE {
X				$$ = ConvOpt (e_opt_e);
X			}
X		|	EOPTM {
X				$$ = ConvOpt (e_opt_m);
X			}
X		|	EOPTW {
X				$$ = ConvOpt (e_opt_w);
X			}
X		|	EOPTZ {
X				$$ = ConvOpt (e_opt_z);
X			}
X		;
X
Xprecdefs	:	/* empty */
X		|	precdefs IDENT ASGN ICONST SEMI {
X				BindID ($2, $4, ID_PREC);
X				EmitDef (def_prec, $2, (char *) NULL, (char *) NULL);
X			}
X		;
X
Xtlist		:	/* empty */
X		|	tlist LBRACE IDENT idlist RBRACE SEMI {
X				EmitDef (def_trusted, (struct he *) NULL, 
X					 ListAppend ($3->psb, $4, " "), (char *) NULL);
X				free ($4);
X				RemoveSymbol ($3);
X			}
X		|	tlist LBRACE RBRACE SEMI
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xhdefs		:	/* empty */
X		|	hdefs FOR fcond dheader SEMI {
X				EmitDef (def_header, (struct he *) NULL, $3, $4);
X			}
X		|	hdefs FOR fcond LBRACE { Flaglist = $3; } 
X				dheaders RBRACE SEMI
X		|	hdefs DEFINE dlist SEMI {
X				EmitDef (def_header, (struct he *) NULL, (char *) NULL, $3);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xfcond		:	LPAREN RPAREN {
X				$$ = NULL;
X			}
X		|	LPAREN mflags RPAREN {
X				$$ = $2;
X			}
X		|	LPAREN error RPAREN {
X				$$ = NULL;
X			}
X		;
X
Xmflags		:	flagid {
X				$$ = ListAppend (ConvFlg ($1), (char *) NULL, (char *) NULL);
X			}
X		|	mflags COMMA flagid {
X				$$ = ListAppend ($1, ConvFlg($3), (char *) NULL);
X				free ($1);
X			}
X		;
X
Xflagid		:	FFLAG {
X				$$ = flg_f;
X			}
X		|	RFLAG {
X				$$ = flg_r;
X			}
X		|	SSFLAG {
X				$$ = flg_S;
X			}
X		|	NFLAG {
X				$$ = flg_n;
X			}
X		|	LFLAG {
X				$$ = flg_l;
X			}
X		|	SFLAG {
X				$$ = flg_s;
X			}
X		|	MFLAG {
X				$$ = flg_m;
X			}
X		|	FFFLAG {
X				$$ = flg_F;
X			}
X		|	DDFLAG {
X				$$ = flg_D;
X			}
X		|	MMFLAG {
X				$$ = flg_M;
X			}
X		|	XFLAG {
X				$$ = flg_x;
X			}
X		|	PPFLAG {
X				$$ = flg_P;
X			}
X		|	UFLAG {
X				$$ = flg_u;
X			}
X		|	HFLAG {
X				$$ = flg_h;
X			}
X		|	AAFLAG {
X				$$ = flg_A;
X			}
X		|	UUFLAG {
X				$$ = flg_U;
X			}
X		|	EFLAG {
X				$$ = flg_e;
X			}
X		|	XXFLAG {
X				$$ = flg_X;
X			}
X		|	LLFLAG {
X				$$ = flg_L;
X			}
X		|	PFLAG {
X				$$ = flg_p;
X			}
X		|	IIFLAG {
X				$$ = flg_I;
X			}
X		|	CCFLAG {
X				$$ = flg_C;
X			}
X		|	EEFLAG {
X				$$ = flg_E;
X			}
X		|	RRFLAG {
X				$$ = flg_R;
X			}
X		;
X
Xdheader		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	DEFINE dlist {
X				$$ = $2;
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xdheaders	:	/* empty */
X		|	dheaders DEFINE dlist SEMI {
X				EmitDef (def_header, (struct he *) NULL, Flaglist, $3);
X			}
X		|	error
X		;
X
Xdlist		:	LPAREN strval COMMA catstring RPAREN {
X				$$ = ListAppend ($2, MacScan ($4), " ");
X				free ($2);
X				free ($4);
X			}
X		|	LPAREN error RPAREN {
X				$$ = NULL;
X			}
X		;
X
Xcatstring	:	SCONST {
X				$$ = $1;
X			}
X		|	ifcon {
X				$$ = $1;
X			}
X		|	CONCAT LPAREN conval RPAREN {
X				$$ = $3;
X			}
X		|	catstring SCONST {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		|	catstring ifcon {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($2);
X			}
X		;
X
Xmlist		:	/* empty */
X		|	mlist IDENT LBRACE mdefs RBRACE SEMI {
X				EmitDef (def_mailer, $2, $4, (char *) NULL);
X			}
X		|	mlist IDENT LBRACE RBRACE SEMI {
X				EmitDef (def_mailer, $2, (char *) NULL, (char *) NULL);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xmdefs		:	mtdef {
X				$$ = $1;
X			}
X		|	mdefs COMMA mtdef {
X				$$ = ListAppend ($1, $3, ", ");
X				free ($1);
X				free ($3);
X			}
X		;	
X
Xmtdef		:	mvar ASGN mval {
X				$$ = ListAppend (ConvMat ($1), MacScan ($3), "=");
X				free ($3);
X			}
X		|	MFLAGS ASGN LBRACE mflags RBRACE {
X				$$ = ListAppend (ConvMat (mat_flags), $4, "=");
X			}
X		|	MSENDER ASGN IDENT {
X				$$ = ListAppend (ConvMat (mat_sender), CheckRS ($3), "=");
X			}
X		|	MRECIPIENT ASGN IDENT {
X				$$ = ListAppend (ConvMat (mat_recipient), CheckRS ($3), "=");
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xmvar		:	MPATH {
X				$$ = mat_path;
X			}
X		|	MARGV {
X				$$ = mat_argv;
X			}
X		|	MEOL {
X				$$ = mat_eol;
X			}
X		|	MMAXSIZE {
X				$$ = mat_maxsize;
X			}
X		;
X
Xrdef		:	/* empty */
X		|	rdef IDENT { StartRuleset ($2); } rulelist
X		;
X
Xrulelist	:	LBRACE ruledefs RBRACE {
X				RMatch = FALSE;
X			}
X		|	error {
X				RMatch = FALSE;
X			}
X		;
X
Xruledefs	:	/* empty */ {
X				RMatch = TRUE;
X			}
X		|	ruledefs IF LPAREN matchaddr RPAREN actionstmt {
X				EmitDef (def_ruleset, (struct he *) NULL, 
X					 ListAppend ($4, $6, "\t"), (char *) NULL);
X			free ($4);
X			free ($6);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xmatchaddr	:	/* empty */ {
X				$$ = NULL;
X			}
X		|	matchaddr matchtok {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xmatchtok	:	IDENT {
X				$$ = GetField ($1);
X			}
X		|	anychar {
X				*Cbuf = $1;
X				$$ = ListAppend (Cbuf, (char *) NULL, (char *) NULL);
X			}
X		|	mval {
X				$$ = MacScan ($1);
X			}
X		|	DOLLAR IDENT {
X				Mbuf[1] = MakeMac ($2, ID_MACRO);
X				$$ = ListAppend (Mbuf, (char *) NULL, (char *) NULL);
X			}
X		;
X
Xactionstmt	:	action LPAREN rwaddr RPAREN SEMI {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($3);
X			}
X		|	RESOLVE LPAREN resolution RPAREN SEMI {
X				$$ = $3;
X			}
X		|	error SEMI {
X				$$ = NULL;
X				yyerrok;
X			}
X		;
X
Xaction		:	RETRY {
X				$$ = NULL;
X			}
X		|	NEXT {
X				$$ = "$:";
X			}
X		|	RETURN {
X				$$ = "$@";
X			}
X		;
X
Xrwaddr		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	rwaddr rwtok {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		|	rwaddr IDENT LPAREN rwaddr RPAREN {
X				$$ = ListAppend ($1, (Tsb = MakeRSCall ($2, $4)), (char *) NULL);
X				free ($1);
X				free ($4);
X				free (Tsb);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xrwtok		:	anychar {
X				*Cbuf = $1;
X				$$ = ListAppend (Cbuf, (char *) NULL, (char *) NULL);
X			}
X		|	mval {
X				$$ = MacScan ($1);
X			}
X		|	cantok {
X				$$ = $1;
X			}
X		|	reftok {
X				$$ = $1;
X			}
X		;
X
Xcantok		:	CANON LPAREN canval RPAREN {
X				$$ = Bracket ($3, TRUE);
X				free ($3);
X			}
X
Xcanval		:	canvaltok {
X				$$ = $1;
X			}
X		|	canval canvaltok {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X				free ($2);
X			}
X		;
X
Xcanvaltok	:	IDENT {
X				$$ = ListAppend ($1->psb, (char *) NULL, (char *) NULL);
X				RemoveSymbol ($1);
X			}
X		|	SCONST {
X				$$ = ListAppend (MacScan ($1), (char *) NULL, (char *) NULL);
X				free ($1);
X			}
X		|	reftok {
X				$$ = $1;
X			}
X		|	SEPCHAR {
X				*Cbuf = $1;
X				$$ = ListAppend (Cbuf, (char *) NULL, (char *) NULL);
X			}
X		|	HOSTNUM LPAREN reftok RPAREN {
X				$$ = Bracket ($3, FALSE);
X				free ($3);
X			}
X		;
X
Xreftok		:	DOLLAR IDENT {
X				Mbuf[1] = MakeMac ($2, ID_MACRO);
X				$$ = ListAppend (Mbuf, (char *) NULL, (char *) NULL);
X			}
X		|	DOLLAR ICONST {
X				$$ = ListAppend (MakePosTok ($2), (char *) NULL, (char *) NULL);
X			}
X		;
X
Xanychar		:	SEPCHAR {
X				$$ = $1;
X			}
X		|	COLON {
X				$$ = ':';
X			}
X		|	STAR {
X				$$ = '*';
X			}
X		|	SEMI {
X				$$ = ';';
X			}
X		|	LBRACE {
X				$$ = '{';
X			}
X		|	RBRACE {
X				$$ = '}';
X			}
X		|	COMMA {
X				$$ = ',';
X			}
X		|	ASGN {
X				$$ = '=';
X			}
X		;
X
Xresolution	:	mailerspec COMMA route {
X				$$ = ListAppend ($1, $3, (char *) NULL);
X				free ($1);
X				free ($3);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xmailerspec	:	MAILER LPAREN rword RPAREN {
X				$$ = ListAppend ("$#", $3, (char *) NULL);
X			}
X		;
X
Xroute		:	HOST LPAREN hword RPAREN COMMA userspec {
X				$$ = ListAppend (Tsb = ListAppend ("$@", $3, (char *) NULL),
X						 $6, (char *) NULL);
X				free (Tsb);
X				free ($6);
X			}
X		|	userspec {
X				$$ = $1;
X			}
X		;
X
Xhword		:	hostid {
X				$$ = $1;
X			}
X		|	HOSTNUM LPAREN reftok RPAREN {
X				$$ = Bracket ($3, FALSE);
X				free ($3);
X			}
X		;
X
Xhostid		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	hostid IDENT {
X				$$ = ListAppend ($1, $2->psb, (char *) NULL);
X				RemoveSymbol ($2);
X				free ($1);
X			}
X		|	hostid rwtok {
X				$$ = ListAppend ($1, $2, (char *) NULL);
X				free ($1);
X			}
X		;
X
Xuserspec	:	USER LPAREN rwaddr RPAREN {
X				$$ = ListAppend ("$:", $3, (char *) NULL);
X				free ($3);
X			}
X		;
X
Xrword		:	IDENT {
X				$$ = CheckMailer ($1);
X			}
X		|	reftok {
X				$$ = $1;
X			}
X		;
X
Xfdefs		:	/* empty */
X		|	fdefs IDENT idlist COLON ftype SEMI {
X				AssignType (ListAppend ($2->psb, $3, " "), $5);
X				free ($3);
X			}
X		|	error SEMI {
X				yyerrok;
X			}
X		;
X
Xidlist		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	idlist COMMA IDENT {
X				$$ = ListAppend ($1, $3->psb, " ");
X				free ($1);
X			}
X		;
X
Xftype		:	MATCH LPAREN ICONST RPAREN cdef {
X				$$ = ListAppend (MakeField ($3, $5, FALSE, FALSE), 
X				    		 (char *) NULL, (char *) NULL);
X			}
X		|	MATCH LPAREN ICONST RPAREN MAP IDENT {
X				$$ = ListAppend (MakeField ($3, $6, FALSE, TRUE), 
X				    		 (char *) NULL, (char *) NULL);
X			}
X		|	MATCH HOST {
X				$$ = ListAppend ("$%y", 
X				    		 (char *) NULL, (char *) NULL);
X			}
X		|	MATCH LPAREN ICONST STAR RPAREN {
X				$$ = ListAppend (MakeField ($3, (struct he *) NULL, TRUE, FALSE), 
X						 (char *) NULL, (char *) NULL);
X			}
X		|	error {
X				$$ = NULL;
X			}
X		;
X
Xcdef		:	/* empty */ {
X				$$ = NULL;
X			}
X		|	IN IDENT {
X				$$ = $2;
X			}
X		;
END_OF_FILE
if test 15988 -ne `wc -c <'src/parser.y'`; then
    echo shar: \"'src/parser.y'\" unpacked with wrong size!
fi
chmod +x 'src/parser.y'
# end of 'src/parser.y'
fi
if test -f 'src/strops.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/strops.c'\"
else
echo shar: Extracting \"'src/strops.c'\" \(12669 characters\)
sed "s/^X//" >'src/strops.c' <<'END_OF_FILE'
X/*	$Header: strops.c,v 2.0 88/06/15 14:42:55 root Exp $	*/
X
X/*
X * $Log:	strops.c,v $
X * Revision 2.0  88/06/15  14:42:55  root
X * Baseline release for net posting. ADR.
X * 
X */
X
X/*
X *	strops.c   -- Contains string operation routines used for constructing
X *		      definitions in cf format.
X *
X *	author	   -- James S. Schoner, Purdue University Computing Center,
X *				        West Lafayette, Indiana  47907
X *
X *	date	   -- July 9, 1985
X *
X *	Copyright (c) 1985 by Purdue Research Foundation
X *
X *	All rights reserved.
X *
X */
X
X#include "fixstrings.h"
X#include <stdio.h>
X#include <strings.h>
X#include "symtab.h"
X
X#define MAXTOKPOS   99		/* maximum number of token positions */
X#define MAXNAME	    1024	/* maximum length of an identifier   */
X
Xextern struct he *LookupSymbol ();
Xextern char       MakeMac ();
Xextern void	  FatalError (),
X		  PrintError (),
X		  ErrorReport ();
X
Xshort  Rformat = FALSE;			/* class read format flag	  */
Xstatic char   *Ptok   = "$  ";		/* positional token structure     */
Xstatic char   *Cfield = "$= ";		/* class reference structure	  */
Xstatic char   *Ofield = "$-";		/* one token match structure	  */
Xstatic char   *Zfield = "$*";		/* zero or more tokens structure  */
Xstatic char   *Pfield = "$+";		/* one or more tokens structure	  */
X
X/*
X *  FLUKE jps 25-apr-86
X *
X *  Add the three new $%x, $%y, and $!x match operators that Sun introduced
X *  with release 3.0.
X *
X *  BUG (probably) - Sun has assigned a predefined meaning to the $y macro;
X *  I imagine we will need to teach ease to avoid this letter.
X */
Xstatic char   *Hfield = "$%y";		/*    match in /etc/hosts */
Xstatic char   *Mfield = "$% ";		/*    match in specified YP map */
Xstatic char   *Nfield = "$! ";		/* no match in specified YP map */
X
Xstatic char   *Mtest  = "$? ";		/* conditional macro test string  */
X
X
X/*
X *	ConvOpt () -- Convert an Ease option identifier (optid) by returning a
X *		      string representation of the cf format.  
X *
X */
Xchar *
XConvOpt (optid) 
Xregister enum opts optid;
X{
X	switch (optid) {
X		case opt_A  :	return ("A");
X		case opt_a  :	return ("a");
X		case opt_B  :	return ("B");
X		case d_opt_b:	return ("b");
X		case opt_C  :	return ("C");
X		case opt_c  :	return ("c");
X		case opt_D  :	return ("D");
X		case opt_d  :	return ("d");
X		case opt_e  :
X		case e_opt_e:	return ("e");
X		case opt_F  :	return ("F");
X		case opt_f  :	return ("f");
X		case opt_g  :	return ("g");
X		case opt_H  :	return ("H");
X		case opt_i  :
X		case d_opt_i:	return ("i");
X		case opt_L  :	return ("L");
X		case opt_m  :
X		case e_opt_m:	return ("m");
X		case opt_N  :	return ("N");
X		case opt_n  :	return ("n");
X		case opt_o  :	return ("o");
X		case opt_P  :	return ("P");
X		case e_opt_p:	return ("p");
X		case opt_Q  :	return ("Q");
X		case opt_q  :	return ("q");
X		case d_opt_q:	return ("q");
X		case opt_r  :	return ("r");
X		case opt_S  :	return ("S");
X		case opt_s  :	return ("s");
X		case opt_T  :	return ("T");
X		case opt_t  :	return ("t");
X		case opt_u  :	return ("u");
X		case opt_v  :	return ("v");
X		case opt_W  :	return ("W");
X		case e_opt_w:	return ("w");
X		case opt_x  :	return ("x");
X		case opt_X  :	return ("X");
X		case opt_y  :	return ("y");
X		case opt_Y  :	return ("Y");
X		case opt_z  :	return ("z");
X		case opt_Z  :	return ("Z");
X		case e_opt_z:	return ("z");
X		default     :	FatalError ("Bad case in ConvOpt ()", (char *) NULL);
X	}
X	/*NOTREACHED*/
X}
X
X
X/*
X *	ConvFlg () -- Convert an Ease mailer flag identifier (flgid) by 
X *		      string representation of the cf format.  
X *
X */
Xchar *
XConvFlg (flgid)
Xregister enum flgs flgid;	/* flag identifier */
X{
X	switch (flgid) {
X		case flg_f:	return ("f");
X		case flg_r:	return ("r");
X		case flg_S:	return ("S");
X		case flg_n:	return ("n");
X		case flg_l:	return ("l");
X		case flg_s:	return ("s");
X		case flg_m:	return ("m");
X		case flg_F:	return ("F");
X		case flg_D:	return ("D");
X		case flg_M:	return ("M");
X		case flg_x:	return ("x");
X		case flg_P:	return ("P");
X		case flg_u:	return ("u");
X		case flg_h:	return ("h");
X		case flg_A:	return ("A");
X		case flg_U:	return ("U");
X		case flg_e:	return ("e");
X		case flg_X:	return ("X");
X		case flg_L:	return ("L");
X		case flg_p:	return ("p");
X		case flg_I:	return ("I");
X		case flg_C:	return ("C");
X		case flg_E:	return ("E");
X		case flg_R:	return ("R");
X		default   :	FatalError ("Bad case in ConvFlg ()", (char *) NULL);
X	}
X	/*NOTREACHED*/
X}
X
X
X/*
X *	ConvMat () -- Convert an Ease mailer attribute (mat) by returning a
X *		      string representation of the cf format.  
X *
X */
Xchar *
XConvMat (mat)
Xregister enum mats mat;		/* mailer attribute flag */
X{
X	switch (mat) {
X		case mat_path		: return ("P");
X		case mat_flags		: return ("F");
X		case mat_sender		: return ("S");
X		case mat_recipient	: return ("R");
X		case mat_argv		: return ("A");
X		case mat_eol		: return ("E");
X		case mat_maxsize	: return ("M");
X		default			: FatalError ("Bad case in ConvMat ()", (char *) NULL);
X	}
X	/*NOTREACHED*/
X}
X
X
X/*
X *	MacScan () -- Scan a string (pstring) for macros, replacing the Ease
X *		      form with the one-character form required by cf format.
X *
X */
Xchar *
XMacScan (pstring)
Xchar *pstring;		/* macro expandable string */
X{
X	register char *searchptr;	/* string search pointer 	*/
X	register char *bptr, *eptr;	/* macro begin and end pointers */
X	char macname [MAXNAME];		/* macro name buffer		*/
X
X	if ((searchptr = pstring) == NULL)
X		return ((char *) NULL);
X	while (*searchptr != '\0') 	/* find and rewrite all macros  */
X		if (*searchptr == '\\') {
X			searchptr = searchptr + 2;
X			continue;
X		} else if (*searchptr++ == '$' && *searchptr == '{') {
X			if (sscanf (searchptr + 1, "%[^}]", macname) != 1) {
X				PrintError ("Invalid macro format:", searchptr + 1);
X				return ((char *) NULL);
X			} 
X			*searchptr++ = MakeMac (LookupSymbol (macname), ID_MACRO);
X			bptr = eptr = searchptr;
X			while (*eptr++ != '}')	/* delete old macro chars */
X				/* empty */ ;
X			do
X				*bptr++ = *eptr;
X			while (*eptr++ != '\0');
X		}
X	return (pstring);
X}
X
X
X/*
X *	MakeRStr () -- Construct and return a pointer to a class read string 
X *		       using the filename fname and read format rformat.  
X *
X */
Xchar *
XMakeRStr (fname, rformat)
Xchar *fname,			/* file name for class read */
X     *rformat;			/* format for class read    */
X{
X	register char *res;	/* resultant read string    */
X
X	Rformat = TRUE;		/* set read format flag     */
X	if (rformat == NULL)
X		return (fname);
X	res = (char *) realloc (fname, strlen (fname) + strlen (rformat) + 2);
X	if (res == NULL)
X		FatalError ("System out of string space in MakeRStr ()", (char *) NULL);
X	res = strcat (res, " ");	/* construct read string */
X	res = strcat (res, rformat);
X	free (rformat);
X	return (res);
X}
X
X
X/*
X *	ListAppend () -- Append string list2 to string list1 using the 
X *			 separator sep.  A pointer to the newly constructed
X *			 string is returned.
X *
X */
Xchar *
XListAppend (list1, list2, sep)
Xchar *list1,			/* first string 	*/
X     *list2,			/* second string  	*/
X     *sep;			/* string separator	*/
X{
X	register char *res;	/* resultant string	*/
X
X	res = (char *) malloc (strlen (list1) + strlen (list2) + strlen (sep) + 1);
X	if (res == NULL)
X		FatalError ("System out of string space in ListAppend ()", (char *) NULL);
X	res = strcpy (res, list1);
X	if (list1 != NULL)	/* use separator if first string not null */
X		res = strcat (res, sep);
X	res = strcat (res, list2);
X	return (res);
X}
X
X
X/*
X *	MakeCond () -- Construct a macro conditional string in cf format.  The
X *		       conditional is based on the macro testmac, with an "if
X *		       set" result ifstring, which may contain an optional 
X *		       "if not set" result string appended to it.
X *
X */
Xchar *
XMakeCond (testmac, ifstring)
Xstruct he *testmac;		/* macro for conditional testing 	     */
Xchar 	  *ifstring; 		/* "if macro set" result string(s)  	     */
X{
X	register char *res;	/* resultant conditional string		     */
X
X	Mtest[2] = MakeMac (testmac, ID_MACRO);	   /* get one-char macro rep */
X	res = (char *) malloc (strlen (ifstring) + 6);
X	if (res == NULL)
X		FatalError ("System out of string space in MakeCond ()", (char *) NULL);
X	res = strcpy (res, Mtest);
X	res = strcat (res, ifstring);		/* build result part	  */
X	res = strcat (res, "$.");		/* end of conditional     */
X	free (ifstring);
X	return (res);
X}
X
X
X/*
X *	MakePosTok () -- Construct and return a positional token string 
X *			 representation from the parameter num.
X *
X */
Xchar *
XMakePosTok (num)
Xregister int num;	        /* numerical value of positional token */
X{
X	if (num > MAXTOKPOS) {
X		ErrorReport ("Positional token too large.\n");
X		return ((char *) NULL);
X	} else {
X		if (num > 9) {	/* two-digit positional token */
X			Ptok[1] = '0' + (num / 10);
X			Ptok[2] = '0' + (num % 10);
X			Ptok[3] = '\0';
X		} else {
X			Ptok[1] = '0' + num;
X			Ptok[2] = '\0';
X		}
X	return (Ptok);
X	}
X}
X
X
X/*
X *	Bracket () -- Construct and return a cf string form of the 
X *		      canonicalization of the string identifier passed in
X *		      the string parameter psb if dflag is true, else
X *		      simply bracket the identifier without dollar signs
X *		      for numeric hostname specifications.
X *
X */
Xchar *
XBracket (psb, dflag)
Xchar *psb;			/* identifier to be canonicalized */
Xshort dflag;			/* dollar flag 			  */
X{
X	register char *res;	/* resultant cf form 		  */
X	register short extra;	/* extra space needed for malloc  */
X	
X	extra = dflag ? 5 : 3;
X	res = (char *) malloc (strlen (psb) + extra);
X	if (res == NULL)
X		FatalError ("System out of string space in Bracket ()", (char *) NULL);
X	if (dflag)
X		res = strcpy (res, "$[");
X	else
X		res = strcpy (res, "[");
X	res = strcat (res, psb);
X	if (dflag)
X		res = strcat (res, "$");
X	res = strcat (res, "]");
X	return (res);
X}
X
X
X/*
X *	MakeRSCall () -- Construct and return a cf string form of a call
X *			 to a ruleset (cid), which would pass to it the
X *			 remainder of a rewriting address (rwaddr).
X *
X */
Xchar *
XMakeRSCall (cid, rwaddr)
Xregister struct he *cid;	/* called ruleset identifier	     */
Xregister char *rwaddr;		/* remainder of rewriting address    */
X{
X	register char *res;	/* resultant cf string for the call  */
X	
X	if (!ISRULESET(cid->idtype)) {	/* check validity of ruleset */
X		PrintError ("Undefined ruleset identifier:", cid->psb);
X		return ((char *) NULL);
X	}
X	/*
X	 * FLUKE jps - 8-may-86 - boost string size by 1 to accomodate space
X	 * character.
X	 */
X	res = (char *) malloc (strlen (cid->idval.rsn) + strlen (rwaddr) + 4);
X	if (res == NULL)
X		FatalError ("System out of string space in MakeRSCall ()", (char *) NULL);
X	res = strcpy (res, "$>");	/* construct the call string */
X	res = strcat (res, cid->idval.rsn);
X	res = strcat (res, " ");  /* FLUKE jps - work around sendmail bug:
X				   * whitespace is needed to separate tokens:
X				   * for example:  $>30$D will confuse
X				   * sendmail, but $>30 $D is OK.
X				   */
X	res = strcat (res, rwaddr);
X	return (res);
X}
X
X
X/*
X *	MakeField () -- Construct and return the cf string format for a
X *			field variable.  The match count (count), an optional
X *			class (class), and a match repetition flag (fstar)
X *			are used to determine what type of field string to
X *			construct.
X *
X *  FLUKE jps 25-apr-86 - Modified to add a fourth parameter "isYPmap".  This
X *  supports Sun's new Yellow Pages match patterns added in release 3.0.
X *
X */
Xchar *
X    MakeField (count, class, fstar, isYPmap)
Xregister int count;		/* match count (0 or 1) */
Xregister struct he *class;	/* optional class type  */
Xregister short fstar;		/* repetition flag	*/
Xregister short isYPmap;		/* "class" name is really a YP map name */
X{
X	switch (count) {
X		case 0:	  if (class == NULL)	/* any token is valid */
X				if (fstar)
X					return (Zfield);
X				else {
X					ErrorReport ("Invalid field type.\n");
X					return ((char *) NULL);
X				}
X			  else {		/* match 0 from class or map */
X				if (isYPmap) {
X				    /*  "class" is a misnomer here; it's really
X				     *  a simple macro name for a YP map.
X				     *  FLUKE jps 25-apr-86
X				     */
X				    Nfield[2] = MakeMac (class, ID_MACRO);
X				    return (Nfield);
X				} else {
X				Cfield[1] = '~';
X				Cfield[2] = MakeMac (class, ID_CLASS);
X				return (Cfield);
X			  }
X			  }
X		case 1:	  if (class == NULL)	/* any token is valid */
X				if (fstar)
X					return (Pfield);
X				else
X					return (Ofield);
X			  else {		/* match 1 from class or map */
X				if (isYPmap) {
X				    /*  "class" is a misnomer here; it's really
X				     *  a simple macro name for a YP map.
X				     *  FLUKE jps 25-apr-86
X				     */
X				    Mfield[2] = MakeMac (class, ID_MACRO);
X				    return (Mfield);
X				} else {
X				Cfield[1] = '=';
X				Cfield[2] = MakeMac (class, ID_CLASS);
X				return (Cfield);
X				}
X			  }
X		default:  ErrorReport ("Invalid field type.\n");
X	}
X	/*NOTREACHED*/
X}
END_OF_FILE
if test 12669 -ne `wc -c <'src/strops.c'`; then
    echo shar: \"'src/strops.c'\" unpacked with wrong size!
fi
chmod +x 'src/strops.c'
# end of 'src/strops.c'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.