Ease 3.0: High Level Language for Sendmail (Part 3 of 6)

Bruce Barnett barnett at grymoire.crd.ge.com
Sat Feb 23 18:15:55 AEST 1991


#! /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 3 (of 6)."
# Contents:  INTRO src/emitcf.c src/lexan.l src/strops.c
# Wrapped by barnett at grymoire on Sat Feb 23 01:13:53 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f INTRO -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"INTRO\"
else
echo shar: Extracting \"INTRO\" \(7739 characters\)
sed "s/^X//" >INTRO <<'END_OF_INTRO'
X		An introduction to Sendmail Rules
X		Copyright 1991, All rights reserved
X		Bruce Barnett
X
X	First of all, sendmail is easy to learn, once you learned all
Xabout electronic mail. Figuring out how to handle the address
X
X	bigvax::a!b!another.domain!c%d%domain.com at another.domain
X
Xis much more challenging. Here's the scoop.
X
X	When sendmail gets a, address, it always passes it to rule 3.
X
X	Rule 3 with transform the address, and eventually sent it to
X	rule 0.
X
X	Rule 0 makes the final decision, and selects three things:
X
X			The address
X			The Machine to send the address to
X			The mailer to use.
X				This could be UUCP, ethernet, DECNet,
X				a local user, a program, etc.
X
X	Once the above has been decided on, the address is transformed
X	in the following way:
X
X	Ruleset 1 is applied to the From: line
X	Ruleset 2 is applied to the To: and Cc: line
X	
X	Each mailer then applies a rule. These rules are other unique
X	for each mailer.
X
X	Finally ruleset 4 is applied.
X
X
XNow let's go through an example in detail.
X
Xgrymoire% /usr/lib/sendmail -bt -C/etc/sendmail.cf
XADDRESS TEST MODE
XEnter <ruleset> <address>
X> 0 user at crdgw1.crd		# <---- I typed this line here 
Xrewrite: ruleset  3   input: "user" "@" "crdgw1" "." "crd"
Xrewrite: ruleset  6   input: "user" "<" "@" "crdgw1" "." "crd" ">"
Xrewrite: ruleset  6 returns: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
Xrewrite: ruleset  3 returns: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
Xrewrite: ruleset  0   input: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
Xrewrite: ruleset  0 returns: $# "ether" $@ "crdgw1" $: "user" "<" "@" "crdgw1" ">"
X> 
X
XRule 3 can be given any address at all. It must determine the machine
Xand domain which corresponds to the address. Determining the machine
Xcan be tricky, because it depends o the address. What it uses to
Xspecify the address is to surround the hostname and @ sign with angle brackets.
XIt also added a imaginary domain to the hostname to indicate the type
Xof network it is on. The set of angle brackets is used to "focus" on a machine.
X
XSome typical values are:
X
X	< @ machine . LOCAL > 	=> a local host
X	< @ machine >		=> same as above
X	< @ machine . UUCP >	=> a machine on the UUCP network
X
XThe angle brackets indicate the important part - the machine and
Xperhaps what mail agent to use. However, the username isn't included
Xin the set of charatcers surrounded by angle brackets. The problem is,
Xdifferent mailers have the username in a different format. In some
Xcasess, the host is the first word, in others it's the last word.
X
XHere is an example of an address going into rule 3 and the expected
Xoutput:
X
X	Input		Output
X	a!b!c!d!user		<@a.UUCP>!b!c!d!user
X	user at a.uucp		user<@a.uucp>
X	bigvax::user		user<@bigvax.DECNET>
X	user%a.com at b.edu	user%a.com<@b.edu>	
X	a!b!user at abc.edu	a!b!user<@abc.edu>
X	@a:user at b.com		<@a>:user at b.com
X
XAs you can see, the machine that will accept the message will be
Xdifferent depending on the address. Ruleset 3 must find the right
Xmachine, and also clean up any addresses if appropriate.
XIt does it's work by looking for a pattern, and transforming the
Xaddress when it matches the pattern.
X
XThe cleaning up part can be confusing, but typically ruleset 3 calls
Xother rules to do this. One rule is used to clean up addresses before
Xthe < and > are added. Another rule is used to clean up addresses
Xafter it has been converted into the < @ machine > format.
X
XHere is the ease version of the rule that transforms a UUCP address:
X
X	if ( exactly_one ! one_or_more )	/* uucphost!user */
X		return (RULESET_6 ($2<@$1."uucp">));
X
XThis transforms the address, but calls ruleset 6, which cleans up the
Xaddresses with < and >. The variables "exactly_one" and "one_or_more"
Xmatch that number of tokens, and are replaced by the $1 or $2 on the 
Xreturned rule. ($1 is exactly_one, $2 is one_or_more).
X
XHere is a rule in ruleset 6 that looks for an address to the local
Xdomain, and replaces the domain with "LOCAL":
X
X	if ( zero_or_more <@ zero_or_more  any_in_mydomainname > zero_or_more )	/* convert local domain */
X		retry ($1<@$2"LOCAL">$4);
X
Xzero_or_more is a pattern, which matches $1, $2, or $4.
Xany_in_mydomain is a special pattern that matches the domain. It is
Xnot necessary to have a $3 because the domain is known.
XSo the test of the address user at crdgw1.crd reports this:
X
Xrewrite: ruleset  3   input: "user" "@" "crdgw1" "." "crd"
Xrewrite: ruleset  6   input: "user" "<" "@" "crdgw1" "." "crd" ">"
Xrewrite: ruleset  6 returns: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
Xrewrite: ruleset  3 returns: "user" "<" "@" "crdgw1" "." "LOCAL" ">"
X
XOnce ruleset 3 is down, it passes the address to 0.
XThis eventually gets to the rule:
X
X/* deliver to known ethernet hosts explicitly specified in our domain */
X	if ( zero_or_more <@ any_in_etc_hosts."LOCAL"> zero_or_more )	/* user at host.sun.com */
X		resolve (mailer (ether),
X				host ($2 ),
X				user ($1<@$2>$3));
X
XThis matches, so the ether mailer is used, and the address is
X$1<@2>$3, or in this case:
X
X
Xrewrite: ruleset  0 returns: $# "ether" $@ "crdgw1" $: "user" "<" "@" "crdgw1" ">"
X
XThe $#, $@, and $: are sendmail talk for the mailer, machine, and
Xaddress. 
X
XStill more to come. The specificalion of the mailer is:
X
Xmailer
X	ether {
X		Path = "[TCP]",
X		Flags = { f_mult, f_strip, f_date, f_from, f_mesg, f_upperu, f_addrw, f_dot },
X		Sender = RULESET_11,
X		Recipient = RULESET_21,
X		Argv = "TCP ${m_rhost}"
X	};
X
X
XThis says the sender's address must go thru rule 11, which means rules
X1, 11, and 4. The recipient's address goes through 2, 21, and 4.
X
XTo test this, type the address from ruleset 0 and specify either 1,
X11, and 4 or perhaps 2, 21, and 4:
X
X> 1,11,4 user at crdgw1
Xrewrite: ruleset  3   input: "user" "@" "crdgw1"
Xrewrite: ruleset  6   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  6 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  3 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  1   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  1 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset 11   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset 11 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  4   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  9   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  9 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  4 returns: "user" "@" "crdgw1"
X
XAs you can see, ruleset 3 is always applied first, which calls 6, 
XThen rule 1 is applied, followed by rule 11, and then followed by
Xrule 4. The end result tells me the From: line would look like
Xuser at crdgw1
X
X
XThe uucp mailer has a diffent set of rewrite rules.
XIn sun's sendmail.main.cf, it uses 13 and 23. To test this address,
XI typed 1,13,4 and got this:
X
X> 1,13,4 user at crdgw1
Xrewrite: ruleset  3   input: "user" "@" "crdgw1"
Xrewrite: ruleset  6   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  6 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  3 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  1   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  1 returns: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset 13   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  5   input: "user" "<" "@" "crdgw1" ">"
Xrewrite: ruleset  5 returns: "crdgw1" "!" "user"
Xrewrite: ruleset 13 returns: "grymoire" "!" "crdgw1" "!" "user"
Xrewrite: ruleset  4   input: "grymoire" "!" "crdgw1" "!" "user"
Xrewrite: ruleset  9   input: "grymoire" "!" "crdgw1" "!" "user"
Xrewrite: ruleset  9 returns: "grymoire" "!" "crdgw1" "!" "user"
Xrewrite: ruleset  4 returns: "grymoire" "!" "crdgw1" "!" "user"
X> 
X
XAs you can see, it converted the address into a uucp path relative to
Xmy machine.
X
XTo test these three cases, add the following to your debug.in file:
X
X0	user at crdgw1
X1,11,4	user at crdgw1	From_Ethernet_to_Ethernet
X1,13,4	user at crdgw1	From_Ethernet_to_UUCP
X
END_OF_INTRO
if test 7739 -ne `wc -c <INTRO`; then
    echo shar: \"INTRO\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/emitcf.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/emitcf.c\"
else
echo shar: Extracting \"src/emitcf.c\" \(7850 characters\)
sed "s/^X//" >src/emitcf.c <<'END_OF_src/emitcf.c'
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/emitcf.c,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
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 * $Log: emitcf.c,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.1  1990/01/30  14:09:49  jeff
X * Changes by Bruce Barnett - extensions for SunOS/Ultrix.
X *
X * Revision 2.0  88/06/15  14:40:47  root
X * Baseline release for net posting. ADR.
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, MacScan(defstr1));
X					if (ISCLASS(targ->idd))
X						PrintWarning ("Appending to previously defined 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: %s", 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: %s", rsid->psb);
X		else
X			PrintError ("Ruleset identifier not bound to a number: %s", 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_src/emitcf.c
if test 7850 -ne `wc -c <src/emitcf.c`; then
    echo shar: \"src/emitcf.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/lexan.l -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/lexan.l\"
else
echo shar: Extracting \"src/lexan.l\" \(8488 characters\)
sed "s/^X//" >src/lexan.l <<'END_OF_src/lexan.l'
X%{
X
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/lexan.l,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
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 * $Log: lexan.l,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.3  1991/02/12  20:49:34  barnett
X * Added several new tokens.
X * Merged Jeff's changes with my own.
X *
X * Revision 2.2  1990/05/07  11:12:53  jeff
X * Add support for the "Cflag" variable which controls whether or not
X * input lines are passed through as comments in the output stream.
X *
X * Version 2.1  90/01/30  15:26:23  jeff
X * If -C flag is specified, emit input as comments in the output stream.
X * 
X * Revision 2.0  88/06/15  15:11:30  root
X * Baseline release for net posting. ADR.
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 int	  EchoInputAsComments;
Xextern struct he *LookupSymbol ();
Xextern void	  ErrorReport ();
Xextern void	  yymark();
X
Xint  Lcount;				/* line counter		    */
Xchar FNbuf[MaxFN];			/* file name buffer	    */
Xshort RMatch  = FALSE;			/* ruleset match flag  	    */
X
X#ifdef YYDEBUG
Xextern int yychar;
X#else
Xint   yychar;
X#endif
X
X#undef input
X# define input() (((yytchar=yychar=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		/* echo input as comment */
X		if (EchoInputAsComments) {
X		    fprintf(yyout, "%s%s", (linbuf[0] == '#' ? "" : "# "), linbuf);
X		}
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 (except cpp comments) */
X			if (EchoInputAsComments) {
X			    fprintf(yyout, "%s%s",
X				(linbuf[0] == '#' ? "" : "# "), linbuf);
X			}
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 	{ "alias",		ALIAS },
X 	{ "asm",		ASM },
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	{ "default",		DEFAULT }, /* IDA */
X	{ "define",		DEFINE },
X 	{ "eval",		EVAL },
X	{ "f_addrw",		CCFLAG },
X	{ "f_arpa",		AAFLAG },
X 	{ "f_bsmtp",		BBFLAG },	/* IDA */
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_mail11",		HHFLAG },  /* Ultrix */
X	{ "f_mesg",		MMFLAG },
X	{ "f_mult",		MFLAG },
X	{ "f_noreset",		SSFLAG },
X	{ "f_noufrom",		NFLAG },
X 	{ "f_relativize",	VVFLAG },	/* IDA */
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_aliasfile",	YYOPT },	/* SunOS */
X	{ "o_bsub",		BBOPT },
X	{ "o_checkpoint",	CCOPT },
X	{ "o_delivery",		DOPT },
X	{ "o_dmuid",		UOPT },
X	{ "o_dnet",		NNOPT },
X 	{ "o_envelope",		SLOPT },	/* IDA */
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_maxempty",		BOPT },	/* SunOS */
X 	{ "o_maxhops",		HOPT }, /* SunOS */
X  	{ "o_nameserver",	IIOPT }, /* HP/UX */
X  	{ "o_newproc",		YYOPT },
X 	{ "o_nfs",		RROPT },	/* SunOS 4.0 */
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 	{ "program",		PROGRAM },	/* HP/UX */
X 	{ "quote",		QUOTE },
X	{ "readclass",		READCLASS },
X	{ "resolve",		RESOLVE },
X 	{ "resolved",		RESOLVED },
X	{ "retry",		RETRY },
X	{ "return",		RETURN },
X	{ "ruleset",		RULESET },
X	{ "trusted",		TRUSTED },
X	{ "user",		USER },
X	{ "while",		IF },
X 	{ "ypalias",		YPALIAS },	/* Ultrix */
X 	{ "ypmap",		YPMAP },	/* SunOS */
X 	{ "yppasswd",		YPPASSWD },	/* Ultrix */
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	                        yymark();
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"/"				return (SLASH);
X[\\]?.				{
X				if (RMatch) {	/* in rulesets, return literal character */
X					yylval.ival = (yytext[0] == '\\') ? yytext[1] : yytext[0];
X					return (SEPCHAR);
X				} else {
X					PrintError ("Illegal delimiter character: (octal code) \\%03o", *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_src/lexan.l
if test 8488 -ne `wc -c <src/lexan.l`; then
    echo shar: \"src/lexan.l\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/strops.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/strops.c\"
else
echo shar: Extracting \"src/strops.c\" \(14822 characters\)
sed "s/^X//" >src/strops.c <<'END_OF_src/strops.c'
X#ifdef FLUKE
X# ifndef LINT
X    static char RCSid[] = "@(#)FLUKE  $Header: /tmp_mnt/home/kreskin/u0/barnett/Src/Ease/ease/src/RCS/strops.c,v 3.0 1991/02/22 18:50:27 barnett Exp $";
X# endif LINT
X#endif FLUKE
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 * $Log: strops.c,v $
X * Revision 3.0  1991/02/22  18:50:27  barnett
X * Added support for HP/UX and IDA sendmail.
X *
X * Revision 2.1  1990/01/30  15:52:55  jeff
X * Added SunOS/Ultrix/IDA extensions  Jan 24, 1989 Bruce Barnett
X *
X * Revision 2.0  88/06/15  14:42:55  root
X * Baseline release for net posting. ADR.
X */
X
X#include "fixstrings.h"
X#include <stdio.h>
X#include <strings.h>
X#include <ctype.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 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");	/* SunOS Maxhops */
X		case opt_H  :	return ("H");
X		case opt_I  :   return ("I");	/* HP/UX */
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_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		case opt_SL  :	return ("/");
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_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		case flg_V:	return ("V");	/* IDA */
X		case flg_B:	return ("B");	/* IDA */
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	char s[11];			/* temp storage for warning below */
X	int	quote;			/* flag for detecting a quote() function */
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++ == '$') {
X		    if (*searchptr == '{') {
X			if (sscanf (searchptr + 1, "quote(%[^)])", macname) == 1) {
X			    /* a quote(macro) sequence */
X			        quote++;
X			} else if (sscanf (searchptr + 1, "%[^}]", macname) != 1) {
X				PrintError ("Invalid macro format: %s", searchptr + 1);
X				return ((char *) NULL);
X			} 
X			if (quote) {
X			    quote=0;
X			    *searchptr++='!'; /* insert a quote */
X			    /* insert the macro letter */
X			    *searchptr++ = MakeMac (LookupSymbol (macname), ID_MACRO);
X			    /* now looking at quote(   */
X			    /* must skip over everything until )}, and then rewrite
X			       the rest of the macro */
X			    bptr = eptr = searchptr; 
X			    while (*eptr && *eptr != ')') /* skip to quote */
X			      eptr++;
X			    while (*eptr && *eptr != '}') /* skip past } */
X			      eptr++;
X			    eptr++;
X			    do	/* copy everything from eptr to end of line */
X			      *bptr++ = *eptr;
X			    while (*eptr++ != '\0');
X			} else {
X			    *searchptr++ = MakeMac (LookupSymbol (macname), ID_MACRO);
X			    bptr = eptr = searchptr;
X			    while (*eptr++ != '}')	/* delete until end of {name} */
X			      /* empty */ ;
X			    do	/* copy rest of line */
X			      *bptr++ = *eptr;
X			    while (*eptr++ != '\0');
X			}
X		    } else if (isupper(*searchptr)){ /* $ not followed by { */
X			/* macro name might be one character */
X			/* but or might be more than one.    */
X			if (sscanf (searchptr, "%[A-Z]", macname) != 1) {
X				PrintError ("Invalid macro format: %s", searchptr + 1);
X				return ((char *) NULL);
X			} 
X			*searchptr++ = MakeMac (LookupSymbol (macname), ID_MACRO);
X			bptr = eptr = searchptr;
X			while (isupper(*eptr))	/* delete old macro chars */
X				eptr++;
X			do
X				*bptr++ = *eptr;
X			while (*eptr++ != '\0');
X		    } 
X		} /* end of (if char == '$' ) */
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: %s", 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_src/strops.c
if test 14822 -ne `wc -c <src/strops.c`; then
    echo shar: \"src/strops.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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
--
Bruce G. Barnett	barnett at crd.ge.com	uunet!crdgw1!barnett



More information about the Alt.sources mailing list