home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!rs
- From: rs@uunet.UU.NET (Rich Salz)
- Newsgroups: comp.sources.unix
- Subject: v10i054: Ease translator repost, Part04/04
- Message-ID: <622@uunet.UU.NET>
- Date: 10 Jul 87 11:26:59 GMT
- Organization: UUNET Communications Services, Arlington, VA
- Lines: 1337
- Approved: rs@uunet.UU.NET
-
- Submitted-by: Wombat <rsk@j.cc.purdue.edu>
- Posting-number: Volume 10, Issue 54
- Archive-name: ease/Part04
-
- #! /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 4 (of 4)."
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'doc/ease.paper' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'doc/ease.paper'\"
- else
- echo shar: Extracting \"'doc/ease.paper'\" \(29063 characters\)
- sed "s/^X//" >'doc/ease.paper' <<'END_OF_FILE'
- X.LP
- X.TL
- XEase: A Configuration Language
- Xfor Sendmail
- X.AU
- XJames S. Schoner
- X.AI
- XPurdue University Computing Center
- XWest Lafayette, Indiana 47907
- X.sp 2
- X.I
- X.ce
- XABSTRACT
- X.R
- X.PP
- XThe rapid expansion of computer networks and ensuing variation among mailing
- Xaddress formats have made address interpretation an increasingly
- Xcomplex task. In the UNIX* 4.2BSD operating system, a program named
- X\fIsendmail\fR was introduced which provided a
- Xgeneral internetwork mail routing facility. This facility has significantly
- Xdiminished the complexity of handling address interpretation.
- X.PP
- X\fISendmail\fR's address interpretation is based on a rewriting
- Xsystem composed of
- Xa number of rewriting rules (or productions) arranged as part of a
- Xconfiguration file. Unfortunately, the syntactical format of a
- Xconfiguration file for \fIsendmail\fR is both terse and rigid, making it
- Xrather difficult to modify. The standard format certainly serves its
- Xpurpose, but, as
- Xthe need to change these configurations increases in frequency, a more
- Xreadable format (i.e., one that is similar to the format
- Xof modern programming languages) is required to permit reasonably
- Xquick modifications to the configuration. As a solution to this problem,
- X\fBEase\fR
- Xprovides a level of abstraction which eliminates most of the current
- Xsyntactic hindrances
- Xfaced by programmers who must reconfigure \fIsendmail\fR's
- Xaddress parsing scheme.
- X.PP
- XAs a high-level specification format, \fBEase\fR is proving to be an
- Xexcellent alternative to \fIsendmail\fR's cryptic
- Xconfiguration file syntax. The syntactic structures of \fBEase\fR
- Xare patterned after modern language constructs, making the language
- Xeasy to learn and easy to remember. The format of the address rewriting
- Xrule is perhaps the most significant syntactical improvement. It was
- Xundoubtedly
- Xthe most needed improvement. Nevertheless, every element of a configuration
- Xfile is structurally enhanced through the use of \fBEase\fR.
- X.FS
- X* UNIX is a trademark of AT&T Bell Laboratories.
- X.FE
- X.sp 2
- X.NH
- XIntroduction
- X.PP
- XThe \fBEase\fR language is a high-level specification format for \fIsendmail\fR's
- Xconfiguration file. The motivation for its development
- Xwas to fulfill a goal of providing a readable and easily modifiable
- X\fIsendmail\fR configuration file format. \fBEase\fR fulfills this goal by
- Xshielding the programmer from the cryptic configuration specification required
- Xby \fIsendmail\fR and providing a high-level language with which the programmer
- Xmay specify all modifications to a configuration file. The development
- Xof Ease coincided with
- Xthe development of an \fBEase\fR translator, \fIet\fR,
- Xwhich translates a configuration file written
- Xin \fBEase\fR to an
- Xequivalent file of the standard format accepted by \fIsendmail\fR.
- X.NH
- XEase in Profile
- X.PP
- XAs will be seen in the next section, the syntax of \fBEase\fR is quite
- Xreadable and easy to learn. In order to acquire a relevant perspective
- Xon this issue,
- Xthe reader is advised to examine a raw configuration file for \fIsendmail\fR (the
- Xoutput
- Xof the \fBEase\fR translator, \fIet\fR, will do nicely). The raw syntax, while
- Xquite fitting for quick translation, can prove to be a programmer's nightmare.
- X.PP
- XUndoubtedly, one of the more prominent features of \fBEase\fR is the ability
- Xto attach
- Xnames to address fields. When address field names are well-chosen, a distinct,
- Xself-documenting quality becomes a visible part of the address rewriting
- Xrules. Ostensibly, address field names provide a new level of semantic
- Xabstraction. A brief comparison of the formats can be accomplished by examining
- Xthe following equivalent representations of an address pattern:
- X.DS
- X user_path@host_name (\fBEase\fR format)
- X $+@$- (raw format)
- X.DE
- XIn the above, \*Quser_path\*U represents a field of one or more address
- Xtokens, and \*Qhost_name\*U represents one address token exactly. These
- Xtoken fields are represented by \*Q$+\*U and \*Q$-\*U in the raw format. Clearly,
- Xthe \fBEase\fR format is preferable, not only for increased readability, but
- Xstructural comprehension as well.
- X.PP
- XOther features of \fBEase\fR include ruleset naming, long identifiers for
- Xmacros and classes, flow-of-control structures, and free formatting. In
- Xaddition, the C language preprocessor (cpp) can be used for file inclusion
- Xand conditionally defined code constructs. The next section describes
- Xthe \fBEase\fR language in complete detail.
- X.NH
- XEase Syntax*
- X.FS
- X* \fINo attempt is made to describe the complete semantic meaning
- Xassociated with all of the constructs of a sendmail configuration file. Items
- Xnot covered in this document include the semantic distinction among rulesets,
- Xthe special uses of
- Xpre-defined macros, and the method of building configuration files. To
- Xobtain this information, the reader is advised to refer to
- Xthe Installation and Operation Guide for Sendmail (UNIX
- XProgrammer's Manual, Volume 2c), by Eric Allman.\fR
- X.FE
- X.PP
- XAt its highest level, \fBEase\fR can be viewed as a collection of
- Xblock-structures, where each block begins with a keyword and is followed by
- Xzero or more related definitions and/or declarations. There are ten distinct
- Xblock types. The following is
- Xa list containing all ten block keywords and the block type it denotes.
- X.TS
- Xcenter;
- Xl l .
- X\fIbind\fR -ruleset identifier bindings
- X\fImacro\fR -macro definitions
- X\fIclass\fR -class definitions
- X\fIoptions\fR -\fIsendmail\fR option definitions
- X\fIprecedence\fR -precedence definitions
- X\fItrusted\fR -trusted users
- X\fIheader\fR -mail header definitions
- X\fImailer\fR -mailer definitions
- X\fIfield\fR -address field definitions
- X\fIruleset\fR -address rewriting rules
- X.TE
- X.sp 1
- XIn general,
- X.TS
- Xcenter ;
- Xl .
- X
- X* Letters are distinguished by case,
- X
- XT{
- X* An \fBEase\fR identifier is defined to be a letter, followed by zero or
- Xmore letters, digits, underscores (_), or dashes (-),
- XT}
- X
- XT{
- X* A literal newline or double quotation (") character may be included in
- Xany quoted string by preceding the character with a backslash (\\\\\), and
- XT}
- X
- XT{
- X* \fBEase\fR source is preprocessed by the C language preprocessor (cpp),
- Xthus source comments (i.e., text enclosed by \*Q/*\*U and \*Q*/\*U) may appear
- Xanywhere as part of \fBEase\fR whitespace.
- XT}
- X.TE
- X.PP
- XFor notational convenience, this document specifies all reserved
- Xwords of the \fBEase\fR language in italics. In addition, quantities
- Xenclosed in angle brackets (<..>) represent arbitrary
- Xidentifiers, strings, or numbers.
- X.NH 2
- XRuleset Identifier Bindings
- X.PP
- XA ruleset (a set of rewriting rules) is identified solely by an integer
- Xin \fIsendmail\fR's
- Xconfiguration file. \fBEase\fR, however, allows each ruleset to be named with
- Xa meaningful identifier. Since a special numeric association for each
- Xruleset is required by the address parsing scheme of \fIsendmail\fR, a \fIbind\fR
- Xblock must be present in any \fBEase\fR file which defines one or more
- Xrulesets. A
- X\fIbind\fR block consists of the keyword \fIbind\fR, followed by zero or more
- Xstatements of the form:
- X.TS
- Xcenter box;
- Xl .
- X<ruleset-id> = \fIruleset\fR <ruleset-number> ;
- X.TE
- XThe following example,
- X.sp 1
- X\fIbind\fR
- X.PP
- XFINAL_RW = \fIruleset\fR 4;
- X.sp 1
- Xspecifies that FINAL_RW, the final rewriting ruleset, is \fIsendmail\fR's ruleset
- Xnumber 4.
- X.NH 2
- XMacro Definitions
- X.PP
- XA macro is an identifier which, when referenced in the text of a program,
- Xis replaced by its value, a string of zero or more characters. The value
- Xof a macro may include references to other macros, but not itself! \fISendmail\fR
- Xallows a maximum of 26 user-declared macros in its configuration file. In
- Xaddition, there are a number of pre-declared macros which have special meaning
- Xto \fIsendmail\fR (see Appendix A). \fBEase\fR macros are defined in
- X\fImacro\fR blocks. \fBEase\fR allows any macro to be declared
- X(which is equivalent to simply referencing it) before it is defined. A macro
- Xidentifier is replaced by its value when it is preceded by the character
- X\*Q$\*U. In addition, a macro reference inside a quoted string must always
- Xinclude braces ({}) around the macro identifier (for delimiting purposes).
- X.PP
- XA \fImacro\fR block consists of the keyword \fImacro\fR, followed by zero
- Xor more statements taking either of the following forms:
- X.TS
- Xcenter box;
- Xl .
- X<macro-identifier> = "<macro-value>" ;
- X<macro-identifier> = \fBconditional-expression\fR ;
- X.TE
- XThe \fBconditional-expression\fR format will be discussed
- Xlater.
- X.sp 1
- XThe following example,
- X.sp 1
- X\fImacro\fR
- X.PP
- Xfirst_name = "James";
- X.PP
- Xlast_name = "Schoner";
- X.PP
- Xwhole_name = "${first_name} ${second_name}";
- X.sp 1
- Xdefines the macros first_name, last_name, and whole_name, where whole_name
- Xis the string, "James Schoner".
- X.NH 2
- XClass definitions
- X.PP
- XA class is denoted by an identifier representing a logical grouping of zero
- Xor more names. Classes are used to represent the range of values a token
- Xmay assume in the pattern matching of an address. Further discussion on the
- Xuse of classes will be deferred until address fields are described.
- X.PP
- XOne identifier may be used to distinctly represent both a macro
- Xand class (i.e., the set of macro identifiers and the set of class identifiers
- Xmay form a non-empty intersection). A name, or class element, may
- Xbe an identifier or any quoted word.
- X.PP
- XA \fIclass\fR block consists of the keyword \fIclass\fR, followed by zero
- Xor more statements taking any of the following forms:
- X.TS
- Xcenter box;
- Xl .
- X<class-identifier> = { <name1>, <name2>, <name3>, ... } ;
- X<class-identifier> = \fIreadclass\fR ( "<file-name>" ) ;
- X<class-identifier> = \fIreadclass\fR ( "<file-name>", "<read-format>" ) ;
- X.TE
- XThe second and third forms cause \fIsendmail\fR to read the names of the class
- Xfrom the named
- Xfile. The third form contains a read format, which should be a \fIscanf(3)\fR
- Xpattern yielding a single string.
- X.sp 1
- XThe following example,
- X.sp 1
- X\fIclass\fR
- X.PP
- Xcampus_hosts = { statistics, engineering, chemistry, physics, physics-2 } ;
- X.PP
- Xversions = { "1.0", "1.1", "4.0", "4.2", latest-and-greatest } ;
- X.PP
- Xphone_hosts = \fIreadclass\fR ( "/tmp/phonenet.list" ) ;
- X.sp 1
- Xdefines the classes campus_hosts, versions, and phone_hosts.
- X.NH 2
- XSendmail option definitions
- X.PP
- XA number of options to the \fIsendmail\fR program may be specified in
- Xan \fIoptions\fR
- Xblock. For a description of the various \fIsendmail\fR options and their
- Xvalues, see Appendix B.
- X.PP
- XAn
- X\fIoptions\fR block consists of the keyword \fIoptions\fR, followed by zero
- Xor more statements taking any of the following forms:
- X.TS
- Xcenter box;
- Xl l .
- X<option-identifier> = "<option-value>" ;
- X\fIo_delivery\fR = \fBspecial-value\fR ;
- X\fIo_handling\fR = \fBspecial-value\fR ;
- X.TE
- XAll but two options (\fIo_delivery\fR and \fIo_handling\fR) use the first
- Xform. To specify an option without a value, simply assign to it the null
- Xstring (""). The \fBspecial-value\fR field of the second and third form
- Xrefers to special values (non-quoted) which are specified in Appendix B.
- X.sp 1
- XThe following example,
- X.sp 1
- X\fIoptions\fR
- X.PP
- X\fIo_alias\fR = "/usr/lib/aliases" ;
- X.PP
- X\fIo_tmode\fR = "0600" ;
- X.PP
- X\fIo_delivery\fR = d_background ;
- X.sp 1
- Xsets the options \fIo_alias\fR, \fIo_tmode\fR, and \fIo_delivery\fR.
- X.NH 2
- XPrecedence definitions
- X.PP
- XMessage headers may contain a \*QPrecedence:\*U field describing the precedence
- Xof the message class. Identifiers which may appear in the precedence field of
- Xa message are given precedence values in a configuration file \fIprecedence\fR
- Xdefinition. This association will be illustrated below in an example.
- X.PP
- XA \fIprecedence\fR block consists of the keyword \fIprecedence\fR, followed
- Xby zero or more statements of the form:
- X.KS
- X.TS
- Xcenter box;
- Xl .
- X<precedence-identifier> = <precedence-integer> ;
- X.TE
- X.KE
- XThe following example,
- X.sp 1
- X\fIprecedence\fR
- X.PP
- Xspecial-delivery = 100;
- X.PP
- Xjunk = -100;
- X.sp 1
- Xdefines the precedence level for the names \*Qspecial-delivery\*U and
- X\*Qjunk\*U. Thus, whenever the name \*Qjunk\*U appears in
- Xa \*QPrecedence:\*U field, the corresponding message class will be set to -100.
- X.NH 2
- XTrusted users
- X.PP
- X\fISendmail\fR's \fB-f\fR flag allows trusted users to override the sender's
- Xmachine address. Trusted users are listed in \fItrusted\fR blocks. A
- X\fItrusted\fR block consists of the keyword \fItrusted\fR, followed
- Xby zero or more sets of users taking the form:
- X.TS
- Xcenter box;
- Xl .
- X{ <user1>, <user2>, <user3>, ... } ;
- X.TE
- XThe following example,
- X.sp 1
- X\fItrusted\fR
- X.PP
- X{ root, uucp, network } ;
- X.PP
- X{ acu, kcs, jss } ;
- X.sp 1
- Xspecifies that the users root, uucp, network, acu, kcs, and jss can be trusted
- Xto use the \fIsendmail\fR flag, \fB-f\fR.
- X.NH 2
- XMail header definitions
- X.PP
- XThe format of the message headers inserted by \fIsendmail\fR is defined in one
- Xor more \fIheader\fR blocks in the configuration file. A \fIheader\fR block
- Xconsists of the keyword \fIheader\fR, followed by zero or more statements
- Xtaking any of the following forms:
- X.TS
- Xcenter box;
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl
- Xl .
- X\fIfor\fR ( <mailer-flag1>, <mailer-flag2>, ... )
- X \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
- X
- X\fIfor\fR ( <mailer-flag1>, <mailer-flag2>, ... ) {
- X \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
- X \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
- X .
- X .
- X} ;
- X
- X\fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
- X.TE
- XThe first form is used to define one header for one or more mailer
- Xflags. The second form differs from the first in that more than one
- Xheader may be defined for a given set of flags. The third form is used to
- Xdefine a header,
- Xregardless of mailer flags. Refer to Appendix C for a list of \fBEase\fR
- Xidentifiers representing mailer flags. The header title is a simple
- Xstring of characters (no macro references), whereas the \fBheader-value\fR can
- Xbe either a string of characters (possibly containing macro references) or
- Xa \fBconditional-expression\fR (discussed later).
- X.sp 1
- XThe following example,
- X.DS
- X\fIheader\fR
- X
- X \fIdefine\fR ( "Subject:", "") ;
- X
- X \fIfor\fR ( \fIf_return\fR )
- X \fIdefine\fR ( "Return-Path:", "<${\fIm_sreladdr\fR}>" ) ;
- X
- X \fIfor\fR ( \fIf_date\fR ) {
- X \fIdefine\fR ( "Resent-Date:", "${\fIm_odate\fR}" ) ;
- X \fIdefine\fR ( "Date:", "${\fIm_odate\fR}" );
- X } ;
- X.DE
- Xdefines a \*QSubject\*U field for all mailers, regardless of their flags, a
- X\*QReturn-Path\*U field for mailers whose definition specifies
- Xthe flag, \fIf_return\fR, and the headers, \*QResent-Date\*U and \*QDate\*U,
- Xfor mailers whose definition specifies the flag, \fIf_date\fR.
- X.NH 2
- XMailer Definitions
- X.PP
- X\fISendmail\fR's definition of a mailer (or an interface to one) occurs in a
- X\fImailer\fR block. A \fImailer\fR block consists of the keyword \fImailer\fR,
- Xfollowed by zero or more statements of the form:
- X.TS
- Xcenter box;
- Xl .
- X<mailer-identifier> { \fBmailer-spec\fR } ;
- X.TE
- XThe field, \fBmailer-spec\fR, is a list of zero or more of the
- Xfollowing attribute assignments (where successive assignment statements are
- Xseparated by commas):
- X.TS
- Xcenter ;
- Xl l
- Xl l
- Xl l
- Xl l
- Xl l
- Xl l
- Xl l .
- X\fIPath\fR = \fBstring-attribute\fR
- X\fIArgv\fR = \fBstring-attribute\fR
- X\fIEol\fR = \fBstring-attribute\fR
- X\fIMaxsize\fR = \fBstring-attribute\fR
- X\fIFlags\fR = { <mailer-flag1>, <mailer-flag2>, ... }
- X\fISender\fR = <sender-ruleset-id>
- X\fIRecipient\fR = <recipient-ruleset-id>
- X.TE
- XThe \fBstring-attribute\fR value can take the form of a quoted string
- X(possibly containing macro references) or a \fBconditional-expression\fR
- X(discussed later).
- X.sp 1
- XThe following example,
- X.sp 1
- X\fImailer\fR
- X.DS
- X local {
- X \fIPath\fR = "/bin/mail",
- X \fIFlags\fR = { \fIf_from\fR, \fIf_locm\fR },
- X \fISender\fR = Sender_RW,
- X \fIRecipient\fR = Recip_RW,
- X \fIArgv\fR = "mail -d ${\fIm_ruser\fR}",
- X \fIMaxsize\fR = "200000"
- X } ;
- X.DE
- Xdefines a mailer named \*Qlocal\*U.
- X.NH 2
- XAddress field definitions
- X.PP
- X\fISendmail\fR's address parsing scheme treats an address as a group of tokens
- X(an address token is precisely defined in the Arpanet protocol RFC822). In
- Xgeneral, \fIsendmail\fR divides an address into tokens based on a list of
- Xcharacters assigned as a string to the special macro \fIm_addrops\fR. These
- Xcharacters will individually be considered as tokens and will separate tokens
- Xwhen parsing is performed.
- X.PP
- XFor
- Xthe \fBEase\fR language, there is a distinct set of address tokens (defined
- Xbelow) which are used in combination to represent generic forms of
- Xaddresses. In
- Xaddition to literal address tokens, the pattern to be matched in a rewriting
- Xrule (often refered to as the LHS) may
- Xinclude field identifiers which match one of five possibilities:
- X.DS
- X - zero or more tokens
- X - one or more tokens
- X - one token exactly
- X - one token which is an element of an aribitrary class \fBX\fR
- X - one token which is not an element of an aribitrary class \fBX\fR
- X.DE
- XA particular field type may be assigned to one or more identifiers. Each
- Xfield identifier is associated with (or defined to be) a field type in
- Xa \fIfield\fR declarations block. A \fIfield\fR declarations block consists
- Xof the keyword \fIfield\fR, followed by zero or more field definitions of
- Xthe form:
- X.TS
- Xcenter box;
- Xl .
- X\fBfield-id-list\fR : \fBfield-type\fR ;
- X.TE
- XA \fBfield-id-list\fR is a list of one or more identifiers, each separated by
- Xa comma. A \fBfield-type\fR, on the other hand, is a representation of
- Xone of the five fields
- Xdescribed above. The syntax for each of the five forms follows:
- X.DS
- X \fImatch\fR ( 0* )
- X \fImatch\fR ( 1* )
- X \fImatch\fR ( 1 )
- X \fImatch\fR ( 1 ) in <class-X>
- X \fImatch\fR ( 0 ) in <class-X>
- X.DE
- XThe star in the first two forms means: "or more". Thus, the first
- Xform would read: "match zero or more tokens". The fourth form describes
- Xa field where one token is matched from an arbitrary class (class-X), whereas
- Xthe fifth form describes a field where one token is matched if it is not of the
- Xgiven class (class-X).
- X.sp 1
- XThe following example,
- X.sp 1
- X.DS
- X\fIfield\fR
- X anypath : \fImatch\fR ( 0* );
- X recipient_host : \fImatch\fR ( 1 );
- X local_site : \fImatch\fR ( 1 ) in \fIm_sitename\fR;
- X remote_site : \fImatch\fR ( 0 ) in \fIm_sitename\fR;
- X.DE
- Xdefines the fields anypath, recipient_host, local_site, and remote_site.
- X.NH 2
- XAddress rewriting rules
- X.PP
- XAddress rewriting rules are grouped according to the function they perform. For
- Xexample, it is desirable to form a distinct group for those rewriting rules
- Xwhich perform transformations on recipient addresses.
- X.PP
- XSets of rewriting rules are defined in \fIruleset\fR blocks. A \fIruleset\fR
- Xblock consists of the keyword \fIruleset\fR, followed by zero or more
- Xruleset definitions of the form:
- X.TS
- Xcenter box;
- Xl .
- X<ruleset-id> { <rewriting-rule1> <rewriting-rule2> ... }
- X.TE
- XThe ruleset identifier, ruleset-id, must be defined in a \fIbind\fR block, as
- Xdescribed earlier. The rewriting rules have the form:
- X.DS
- X \fIif\fR ( <match-pattern> )
- X <match-action> ( <rewriting-pattern> ) ;
- X.DE
- Xwhere match-pattern, rewriting-pattern, and match-action are described below.
- X.NH 3
- XMatch-patterns
- X.PP
- XA match-pattern is a sequence of Ease address elements representing an
- Xaddress format. If the address being rewritten matches the pattern
- X\*Qmatch-pattern\*U,
- Xthen the address is reformatted using the pattern \*Qrewriting-pattern\*U, and
- Xthe corresponding
- Xaction (\*Qmatch-action\*U) is performed. The five distinct Ease address
- Xelements which may constitute a match-pattern are as follows:
- X.TS
- Xcenter ;
- Xl .
- X1. Field Identifiers (refer to previous section)
- XT{
- X2. Non-alphanumeric characters (the exception is the case for literal
- Xdouble quotes, which must be preceded by a backslash (\\\\\)
- XT}
- X3. Macro references
- X4. Quoted strings ("...")
- X5. \fBConditional-expressions\fR (discussed later)
- X.TE
- XBelow are two sample match-patterns, each describing the same address format:
- X.DS
- X user-id @ hostname . $arpa_suffix
- X user-id @ hostname ".ARPA"
- X.DE
- Xwhere user-id and hostname are field identifiers, and arpa_suffix is a
- Xuser-defined macro with the value \*QARPA\*U.
- X.NH 3
- XRewriting-patterns
- X.PP
- XA rewriting-pattern specifies the form in which to rewrite a matched
- Xaddress. The seven distinct elements which may be used to form
- Xa rewriting-pattern are as follows:
- X.TS
- Xcenter ;
- Xl .
- X
- XT{
- X1. Non-alphanumeric characters (the exception is the case for literal
- Xdouble quotes, left parentheses, or right parentheses, each of which
- Xmust be preceded by a backslash (\\\\\).
- XT}
- X
- XT{
- X2. A call to another ruleset. This is used to perform rewrites
- Xon a suffix of the rewriting-pattern. The proper use of this
- Xfeature will be demonstrated by example below.
- XT}
- X
- X3. Quoted strings ("...").
- X
- X4. \fBConditional-expressions\fR (discussed later).
- X
- X5. A macro reference.
- X
- XT{
- X6. A positional reference in the matched address. A positional
- Xreference takes the form: $<integer-position>. For example,
- X$3 references the value of the third \fBEase\fR address
- Xelement in the matched address.
- XT}
- X
- XT{
- X7. Canonicalized host names of the form \fIcanon\fR (<id-token>),
- Xwhere id-token is a regular identifier, a quoted identifier (with
- Xdouble quotes), a macro reference yielding an identifier, or a
- Xpositional reference in the matched address. The canonicalization of
- Xa host name is simply a mapping to its canonical (or official) form.
- XT}
- X
- X.TE
- XBelow are two sample rewriting-patterns:
- X.DS
- X $1 % $2 < @ $3 ".ARPA" >
- X OLDSTYLE_RW ( $1 )
- X.DE
- XThe first form specifies an address such as a%b<@c.ARPA>, where a, b, and c
- Xrepresent matched identifiers or paths. The second form specifies a call to
- Xthe ruleset \*QOLDSTYLE_RW\*U, for old-style rewriting on the parameter
- X$1, which probably references the entire matched address. This will become
- Xclear in later examples.
- X.NH 3
- XMatch-actions
- X.PP
- XWhen a ruleset is called, the address to be rewritten is compared (or matched)
- Xsequentially against the match-address of each rewriting rule. When a
- Xmatch-address describes the address \fIsendmail\fR is attempting to rewrite, the
- Xaddress is rewritten (or reformatted) using the rule's
- Xrewriting-pattern. Following this rewrite, the corresponding match-action
- Xis performed. There are four match-actions:
- X.TS
- Xcenter ;
- Xl l .
- X\fIretry\fR T{
- X-a standard action which causes the rewritten address
- Xto be again compared to the match-address of the current rule.
- XT}
- X
- X\fInext\fR T{
- X-an action which causes the rewritten address to be
- Xcompared to the match-address of the next rewriting rule of the current
- Xruleset. If the end of the list is reached, the ruleset returns the
- Xrewritten address.
- XT}
- X
- X\fIreturn\fR T{
- X-an action which causes an immediate return of the
- Xruleset with the current rewritten address.
- XT}
- X
- X\fIresolve\fR T{
- X-an action which specifies that the address has been
- Xcompletely resolved (i.e., no further rewriting is necessary). The
- X\fIresolve\fR action is described in more detail below.
- XT}
- X.TE
- X.PP
- XThe match-action, \fIresolve\fR, is special in that it terminates
- Xthe address rewriting altogether. The semantic structure of \fIsendmail\fR's
- Xrewriting scheme requires that a \fIresolve\fR action appear only in the
- Xruleset whose numerical binding is to the number zero. The \fIresolve\fR action
- Xmust specify three parameters: \fImailer\fR, \fIhost\fR, and \fIuser\fR. If
- Xthe \fImailer\fR is local, the \fIhost\fR parameter may be omitted. The
- X\fImailer\fR argument must be specified as a single word, macro, or positional
- Xreference in the matched address. The \fIhost\fR argument may be specified as
- Xa single word or as an expression which expands to a single word (i.e.,
- X\fIhost\fR ($1 ".ARPA")). In addition, the \fIhost\fR argument may be a
- Xcanonicalization (as described above) or a numeric internet specification. The
- Xkeyword \fIhostnum\fR is used for numeric internet specifications, as in
- X\fIhostnum\fR ("00.00.00.00") or \fIhostnum\fR ( $2 ). The \fIuser\fR
- Xspecification is a rewriting-pattern, as described above.
- X.PP
- XIn general, the format of a \fIresolve\fR action will be as follows:
- X.DS
- X \fIresolve\fR ( \fImailer\fR ( <mailer-name> ),
- X \fIhost\fR ( <host-name> ),
- X \fIuser\fR ( <user-address>) );
- X.DE
- XExamples of the match-action statement are shown below:
- X.DS
- X\fIfield\fR
- X anypath : \fImatch\fR (0*);
- X usr, path : \fImatch\fR (1*);
- X hostname : \fImatch\fR (1);
- X phone_host : \fImatch\fR (1) in phonehosts;
- X.DE
- X.DS
- X\fIruleset\fR
- X
- X EXAMPLE_RW {
- X
- X \fIif\fR ( anypath < path > anypath ) /* basic RFC821/822 parse */
- X \fIretry\fR ( $2 );
- X \fIif\fR ( usr " at " path ) /* \*Qat\*U -> \*Q@\*U */
- X \fInext\fR ( $1 @ $2 );
- X \fIif\fR ( @path: usr )
- X \fIreturn\fR ( LOCAL_RW ( < @$1 > : $2 ) );
- X \fIif\fR ( anypath < @phone_host".ARPA" > anypath )
- X \fIresolve\fR ( \fImailer\fR ( tcp ),
- X \fIhost\fR ( csnet-relay ),
- X \fIuser\fR ( $1 % $2 < @"csnet-relay" > $3 ) );
- X }
- X.DE
- X.PP
- XThe example above defines the ruleset \*QEXAMPLE_RW\*U, which contains four
- Xrewriting rules. The first rewriting rule discards all tokens of an address
- Xwhich lie on either side of a pair of angle brackets (<>), thereby
- Xrewriting the address as
- Xthe sequence of tokens contained within the angle brackets ($2). Following the
- Xaddress rewrite, the rule is applied again (\fIretry\fR). When the first rule
- Xfails to match the address being rewritten, the second rule is applied.
- X.PP
- XThe second
- Xrule simply replaces the word \*Qat\*U by the symbol \*Q@\*U. The \*Q\fInext\fR\*U
- Xaction specifies that if a match is made, a rewrite is performed and
- Xmatching continues at the next (or following) rule.
- X.PP
- XThe third rule illustrates
- Xthe use of the \*Q\fIreturn\fR\*U action, which is executed if the
- Xpattern \*Q@path: usr\*U
- Xdescribes the current format of the address being rewritten. In this example,
- Xthe \fIreturn\fR action returns the result of a call to ruleset \*QLOCAL_RW\*U,
- Xwhich rewrites the address \*Q<@$1>:$2\*U, where $1 and $2 are substituted
- Xwith the token(s) matched respectively by \*Qpath\*U and \*Qusr\*U.
- X.PP
- XThe fourth (and final) rule signals a resolution (and termination) of the
- Xrewriting process if the given pattern is matched. The resolution specifies
- Xthat the mailer \*Qtcp\*U will be used to deliver the message to the host
- X\*Qcsnet-relay\*U. The \fIuser\fR parameter specifies the final form of the address
- Xwhich \fIsendmail\fR has just resolved.
- X.sp 2
- X.PP
- XThe \fBEase\fR construct which remains to be examined is the
- X\fBconditional-expression\fR. The \fBconditional-expression\fR provides a
- Xmethod for
- Xconstructing strings based on the condition that some test macro is (or is not)
- Xset. The general form begins with the concatenation of a string and a
- X\fBstring-conditional\fR:
- X.DS
- X \fIconcat\fR ( <quoted-string>, \fBstring-conditional\fR )
- X \fIconcat\fR ( \fBstring-conditional\fR, <quoted-string> )
- X.DE
- XA \fBstring-conditional\fR assumes either of the following forms:
- X.DS
- X \fIifset\fR ( <macro-name>, <ifset-string> )
- X \fIifset\fR ( <macro-name>, <ifset-string>, <notset-string> )
- X.DE
- XA \fBstring-conditional\fR of the first form evaluates to \*Qifset-string\*U
- Xif the macro \*Qmacro-name\*U has been assigned a value; otherwise it
- Xevaluates to the null string. The second form behaves similarly, except
- Xthat the \fBstring-conditional\fR evaluates to \*Qnotset-string\*U, instead
- Xof the null string, if the macro \*Qmacro-name\*U has no value.
- X.sp 1
- XThe following \fBconditional-expression\fR,
- X.DS
- X \fIconcat\fR ( "New ", \fIifset\fR ( city, "York", "Jersey" ) )
- X.DE
- Xevaluates to the string "New York", if the macro \*Qcity\*U is set. Otherwise,
- Xthe \fBconditional-expression\fR evaluates to the string "New Jersey".
- X.NH
- XEase Translation
- X.PP
- XIt is important to note that \fBEase\fR is translated by a stand-alone
- Xtranslator to the raw configuration file format. No modifications were
- Xmade to the \fIsendmail\fR program itself. As a result, syntactical verification
- Xof a configuration file can be performed without invoking \fIsendmail\fR.
- X.PP
- XThe \fBEase\fR language is translated by invoking
- Xthe C language preprocessor (cpp) with \fBEase\fR source as input, then piping
- Xthe output as input to the \fBEase\fR translator (\fIet\fR). The \fBEase\fR
- Xtranslator may be invoked on the command line in one of four ways:
- X.TS
- Xcenter box ;
- Xl l .
- X\fIet\fR <input-file> <output-file> [read from a file, write to a file]
- X\fIet\fR <input-file> [read from a file, write to standard output]
- X\fIet\fR - <output-file> [read from standard input, write to a file]
- X\fIet\fR [read from standard input, write to standard output]
- X.TE
- X.NH
- XConclusion
- X.PP
- X\fBEase\fR is currently in use at the Purdue University Computing
- XCenter. Source code for the \fBEase\fR translator (\fIet\fR) may be
- Xobtained on request by writing to:
- X.DS
- XU.S. Mail:
- X James S. Schoner
- X c/o Kevin S. Braunsdorf
- X Purdue University Computing Center
- X Purdue University
- X West Lafayette, Indiana 47907
- X
- XElectronic Mail:
- X ksb@j.cc.purdue.edu
- X.DE
- X.PP
- XMuch of the success of this project is attributable to the constant support
- Xand insight offered by Mark Shoemaker. To him, I owe a debt of gratitude. In
- Xaddition, I would like to thank Kevin Smallwood, Paul Albitz, and Rich Kulawiec
- Xfor their many notable suggestions and valuable insight.
- END_OF_FILE
- if test 29063 -ne `wc -c <'doc/ease.paper'`; then
- echo shar: \"'doc/ease.paper'\" unpacked with wrong size!
- fi
- # end of 'doc/ease.paper'
- fi
- if test -f 'maketd/maketd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'maketd/maketd.c'\"
- else
- echo shar: Extracting \"'maketd/maketd.c'\" \(16381 characters\)
- sed "s/^X//" >'maketd/maketd.c' <<'END_OF_FILE'
- X/* maketd - MAKE Transitive Dependencies.
- X * (This is a lie - the dependencies are not transitive, but "all"
- X * dependencies are correctly made.)
- X *
- X * Based loosely on a shell script by Stephan Bechtolsheim, svb@purdue
- X * Other Makefile related features have been added or merged in from
- X * other programs.
- X *
- X * Written & hacked by Stephen Uitti, PUCC staff, ach@pucc-j, 1985
- X * maketd is copyright (C) Purdue University, 1985
- X *
- X * removed some of Steve's good, but unnecessary, options in favor
- X * of more compile time flags & better implicit rules in the makefile
- X * dinked: -q -e -E -k
- X * Kevin S Braunsdorf, PUCC UNIX Group 1986 (ksb@j.cc.purdue.edu)
- X *
- X * Permission is hereby given for its free reproduction and
- X * modification for non-commercial purposes, provided that this
- X * notice and all embedded copyright notices be retained.
- X * Commercial organisations may give away copies as part of their
- X * systems provided that they do so without charge, and that they
- X * acknowledge the source of the software.
- X */
- X#include <sys/types.h>
- X#include <sys/param.h>
- X#include <sys/file.h> /* for access */
- X#ifdef BSD2_9
- X#include <ndir.h> /* for MAXPATHLEN, MAXNAMLEN */
- X#endif
- X#ifdef BSD4_2
- X#include <sys/dir.h> /* for MAXNAMLEN in 4.2 */
- X#endif
- X#include <ctype.h> /* for isupper */
- X#include <stdio.h>
- Xextern char *rindex(), *index(), *strcat(), *strcpy();
- X
- X#include "srtunq.h"
- X#include "abrv.h"
- X#include "nshpopen.h"
- X#include "maketd.h"
- X
- X#ifndef CPP
- X#define CPP "/lib/cpp "
- X#endif CPP not in Makefile
- X
- X/* forward functions */
- Xvoid msoio(); /* open output file */
- Xvoid rdwr(); /* read old Makefile into new */
- Xvoid mkdepend(); /* does the real work */
- X
- X/* globals */
- Xchar *prgnm; /* our program name */
- XFILE *makefd; /* makefile stream */
- Xint alldep = FALSE; /* -a all - /usr/include too */
- Xchar *targetname = NULL; /* -t target name for next file */
- Xchar *destsuffix = ".o"; /* -s suffix for targets */
- Xint header = TRUE; /* print header & trailer */
- Xint usestdout = FALSE; /* -d use stdout for makefile */
- Xint forcehead = FALSE; /* -f force header/trailer */
- Xint makenseen = FALSE; /* output file has been specified */
- Xchar *makename = "makefile"; /* -m default file for edit */
- Xint backedup = FALSE; /* for interupt recovery */
- Xchar backupfn[MAXNAMLEN+1]; /* backup file name */
- Xint ismakeopen = FALSE; /* if the output file is open */
- Xchar objpath[MAXPATHLEN+1]; /* -o prepended to .o's */
- Xint nonlocalo = FALSE; /* -nonlocalo objects in source dir */
- Xint replace = FALSE; /* -r replace depends in Makefile */
- Xchar cppflags[BUFSIZ]; /* -D, -I, -U flags to pass to cpp */
- Xint shortincl = TRUE; /* -x do abreviations */
- Xint verbose = FALSE; /* -v verbage for the debugger */
- Xstatic char sopts[] = "abdfhrxv"; /* single char opts */
- Xstatic SRTUNQ u; /* unique include files */
- X
- Xchar usage[] =
- X"Usage: maketd [-a -b -d -f -h -mMAKEFILE -nonlocalo -oDIR -r -sSUFFIX\n\
- X -tTARGETNAME -x -v -Iincludedir -Ddefine -Uundefine file...]\n";
- Xchar helptext[] =
- X"-a\tdo all dependencies, including /usr/include\n\
- X-b\tgenerate binary, rather than object related dependencies\n\
- X-d\tdependencies to stdout, rather than Makefile\n\
- X-f\tforce header/trailer (use with -d)\n\
- X-h\thelp (this text)\n\
- X-m\tspecify MAKEFILE for edit\n\
- X-nonlocalo Objects live in source directory\n\
- X-o\tprepend DIR to target: DIR/a.o: foo.h\n\
- X-r\treplace dependencies for a target\n\
- X-s\tchange suffix target's SUFFIX: a.SUFFIX: foo.h\n\
- X-t\tchange target's basename: TARGET.o: foo.h\n\
- X-x\tdon't abbreviate includes\n\
- X-v\tprint extra verbose (debug) output to stderr\n\
- X-I\tspecify include directory, as in /lib/cpp\n\
- X-D\tspecify defines, as in /lib/cpp\n\
- X-U\tspecify undefines, as in /lib/cpp\n";
- X
- Xchar deplin[] = "# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT\n";
- Xchar searchdep[] = "# DO NOT DELETE THIS LINE";
- Xchar trailer[] = "\n# *** Do not add anything here - It will go away. ***\n";
- X
- X/* some init & argv parsing */
- Xmain(argc, argv)
- Xregister int argc;
- Xregister char **argv;
- X{
- X register a; /* argv subscript */
- X register i; /* tmp */
- X register len; /* length of current argument */
- X register files = FALSE; /* files ever seen */
- X register char *q; /* tmp */
- X
- X /* prgnm = program name, for error printing */
- X if ((prgnm = rindex(argv[0], '/')) == NULL)
- X prgnm = argv[0];
- X else
- X prgnm++;
- X catchsig(); /* init signal traps */
- X srtinit(&abrv); /* init abbreviations tree */
- X for (a = 1; a < argc; a++) { /* argv prepass: find all -I's */
- X if (argv[a][0] == '-' && argv[a][1] == 'I' && strlen(&argv[a][2]) > 2)
- X if ((q = srtin(&abrv, hincl(&argv[a][2]), lngsrt)) != NULL)
- X fprintf(stderr, "%s: %s - %s\n", prgnm, q, &argv[a][2]);
- X }
- X cppflags[0] = '\0'; /* terminate cpp flags string */
- X objpath[0] = '\0'; /* init object path */
- X srtinit(&u); /* init sorting database tag */
- X for (a = 1; a < argc; a++) {
- X len = strlen(argv[a]);
- X if (argv[a][0] == '-' && len > 2 && index(sopts, argv[a][1]) != NULL)
- X err("options must be listed seperately - '%s'\n", argv[a]);
- X if (len > 1 && argv[a][0] == '-') {
- X switch (argv[a][1]) {
- X case 'D': /* /lib/cpp flags to pass */
- X case 'I':
- X case 'U':
- X if (strlen(cppflags) + strlen(argv[a]) + 2 > BUFSIZ)
- X err("too many cpp flags - buffer overflow");
- X strcat(cppflags, argv[a]);
- X strcat(cppflags, " "); /* add a space separator */
- X break;
- X case 'a': /* /usr/include deps too */
- X alldep = TRUE;
- X break;
- X case 'b': /* target has no suffix */
- X destsuffix = "";
- X break;
- X case 'd': /* don't edit Makefile */
- X if (ismakeopen)
- X err("Makefile already open, -d must precede filenames");
- X if (makenseen)
- X err("Conflict - check -d and -m options");
- X makenseen = TRUE;
- X usestdout = TRUE;
- X if (!forcehead)
- X header = FALSE; /* don't do header & trailer */
- X break;
- X case 'f': /* force header/trailer */
- X forcehead = TRUE;
- X header = TRUE;
- X break;
- X case 'h': /* help */
- X fputs(usage, stdout);
- X fputs(helptext, stdout);
- X exit(0);
- X break;
- X case 'm': /* specify makefile name for edit */
- X if (ismakeopen)
- X err("Makefile already open, -m must precede filenames");
- X if (makenseen)
- X err("Conflict, check -m and -d options.");
- X if (strlen(makename) == 0)
- X err("-m option requires file name.");
- X makenseen = TRUE;
- X makename = &argv[a][2];
- X break;
- X case 'n': /* objects reside with sources */
- X if (strcmp("nonlocalo", &argv[a][1]) != 0)
- X err("bad -n option"); /* what a crock of an option */
- X if (objpath[0] != '\0')
- X err("nonlocalo conflict - check -o's");
- X nonlocalo = TRUE;
- X break;
- X case 'o':
- X if (nonlocalo)
- X err("object path conflict - check -o's and -nonlocalo's");
- X strcpy(objpath, &argv[a][2]);
- X i = strlen(objpath);
- X if (i == 0)
- X err("-o requires path string.");
- X if (i >= MAXPATHLEN)
- X err("Object path too long: max is %d.", MAXPATHLEN);
- X if (objpath[i - 1] != '/')
- X strcat(objpath, "/");
- X break;
- X case 'r': /* replace mode */
- X if (ismakeopen)
- X err("Makefile already open, -r must precede filenames");
- X replace = TRUE;
- X break;
- X case 's': /* destination suffix */
- X destsuffix = &argv[a][2];
- X break;
- X case 't': /* set target's basename */
- X targetname = &argv[a][2];
- X if (len <= 2)
- X err("target option requires name.");
- X break;
- X case 'v': /* user wants to hear noise */
- X verbose = TRUE;
- X break;
- X case 'x': /* don't abbrev. */
- X if (files)
- X err("-x option must preceed all files.");
- X shortincl = FALSE;
- X break;
- X default:
- X err("Unknown option %s.", argv[a]);
- X } /* end switch */
- X } else { /* must be a filename */
- X if (verbose)
- X fprintf(stderr, "%s: working on %s.\n", prgnm, argv[a]);
- X files = TRUE; /* at least one file seen */
- X if (replace && a != argc - 1)
- X err("Only one file allowed with -r (edit aborted)");
- X mkdepend(argv[a]); /* file to process */
- X targetname = NULL; /* affect only one file */
- X } /* if option */
- X } /* for argv */
- X if (ismakeopen && header)
- X fputs(trailer, makefd); /* do not delete... */
- X#if DEL_BACKUP
- X if (backedup)
- X if (unlink(backupfn))
- X err("Can't delete backup file %s on completion", backupfn);
- X#endif DEL_BACKUP
- X if (!files)
- X err("No files to process, use -h for full help.\n%s", usage);
- X exit(0); /* exit status - good */
- X}
- X
- X/* msoio - Make Sure Output Is Open.
- X * Interacts strongly via globals: makefd, backedup, backupfn, makename,
- X * header, ismakeopen
- X */
- Xvoid
- Xmsoio(targ)
- Xchar *targ; /* if -r, is target name */
- X{
- X FILE *tmpfd; /* temp file desc for -d */
- X char buf[BUFSIZ]; /* for reading the makefile */
- X
- X if (ismakeopen)
- X return;
- X ismakeopen = TRUE; /* will be: all errs are fatal */
- X if (usestdout) {
- X makefd = stdout;
- X if (header) {
- X fputc('\n', makefd); /* one blank line */
- X fputs(deplin, makefd); /* the first line */
- X }
- X /* scan "makefile" or "Makefile" for include defines */
- X if (access(makename, R_OK) != 0) {
- X makename[0] = 'M'; /* try Makefile */
- X if (access(makename, R_OK) != 0)
- X return; /* just punt */
- X }
- X if ((tmpfd = fopen(makename, "r")) == NULL)
- X return; /* just punt */
- X while (fgets(buf, BUFSIZ, tmpfd) != NULL)
- X srchincl(buf); /* scan whole file */
- X fclose(tmpfd);
- X return;
- X } /* ... if standard out */
- X/* !makenseen means (default) try "makefile" then "Makefile" */
- X if (!makenseen && access(makename, F_OK) != 0)
- X makename[0] = 'M'; /* try Makefile */
- X/* side effect: "Makefile" will be created if neither exist */
- X if (access(makename, F_OK) == 0) { /* if makefile exits */
- X strcpy(backupfn, makename); /* get rid of .bak */
- X strcat(backupfn, ".bak");
- X if (access(backupfn, F_OK) == 0) {
- X if (unlink(backupfn))
- X err("Can't remove %s for pre-edit\n", backupfn);
- X }
- X if (link(makename, backupfn)) /* mv makefile to .bak */
- X err("Can't link %s to %s.", backupfn, makename);
- X backedup = TRUE; /* for interupt status */
- X if (unlink(makename))
- X err("Can't unlink %s during rename.", makename);
- X } else {
- X backupfn[0] = '\0'; /* no copy (no makefile) */
- X }
- X if ((makefd = fopen(makename, "w")) == NULL)
- X err("Can't open output file '%s' for write.", makename);
- X if (backupfn[0] != '\0') /* if no .bak file - done */
- X rdwr(targ); /* read/write Makefile */
- X else
- X fputs(deplin, makefd); /* must start with this */
- X}
- X
- X/* create beginging of new Makefile by reading old one */
- Xvoid
- Xrdwr(targ)
- Xchar *targ;
- X{
- X register FILE *oldfd; /* file pointer for .old */
- X char rwbuf[BUFSIZ]; /* temp for read/write */
- X register tlen; /* targ length */
- X register puntln = FALSE; /* punt current line? */
- X register contln = FALSE; /* previous line ended with '\'? */
- X register blankln = 0; /* number of blank lines seen */
- X register srchsn = FALSE; /* search line seen? */
- X
- X if ((oldfd = fopen(backupfn, "r")) == NULL)
- X err("Can't open backup copy of %s\n", makename);
- X tlen = strlen(targ);
- X while (fgets(rwbuf, BUFSIZ, oldfd) != NULL) { /* until EOF */
- X if (!srchsn) {
- X if (strncmp(searchdep, rwbuf, (sizeof searchdep) - 1) == 0) {
- X srchsn = TRUE;
- X fputs(deplin, makefd); /* re-write this line */
- X if (!replace)
- X break;
- X continue; /* don't print this line */
- X }
- X } else {
- X if (strcmp("\n", rwbuf) == 0) {
- X if (!puntln)
- X blankln++;
- X contln = FALSE;
- X puntln = FALSE;
- X continue; /* don't output this blank line */
- X }
- X if (!contln) {
- X if (strncmp(targ, rwbuf, tlen) == 0)
- X puntln = TRUE;
- X else if (strcmp(&trailer[1], rwbuf) == 0)
- X puntln = TRUE;
- X }
- X if (lastlnch(rwbuf) == '\\')
- X contln = TRUE;
- X else
- X contln = FALSE;
- X } /* if srchsn */
- X if (!puntln) {
- X srchincl(&rwbuf[0]); /* search this line for defines */
- X if (blankln != 0) { /* compress mult blank lines to one */
- X putc('\n', makefd);
- X blankln = 0;
- X }
- X fputs(rwbuf, makefd); /* non targ lines */
- X }
- X } /* while fgets */
- X if (!srchsn) /* deplin never found */
- X fputs(deplin, makefd); /* so write one */
- X (void) fclose(oldfd); /* close the .old file for gigles */
- X}
- X
- X#define MAXCOL 78 /* output width max for makefile */
- X
- X/* mkdepend - name is historical, but does the "real work" */
- Xvoid
- Xmkdepend(infile)
- Xchar *infile;
- X{
- X register char *p; /* temp pointer */
- X register char *q; /* temp pointer */
- X register char *r; /* temp pointer */
- X register FILE *cppfd; /* file desc for /lib/cpp */
- X char buf[BUFSIZ]; /* temp buff */
- X char basename[MAXNAMLEN+1]; /* just the file name */
- X register oplen; /* length target & path */
- X register le; /* length of current output line */
- X register char *targ; /* target's name */
- X register i; /* tmp for index */
- X register firstln; /* first line of a list */
- X
- X if ((p = rindex(infile, '/')) == NULL) /* past path */
- X p = infile;
- X else
- X p++;
- X if (nonlocalo && p != infile) { /* objpath = source path */
- X for (q = objpath, r = infile; r < p;)
- X *q++ = *r++;
- X *q = '\0'; /* null terminate */
- X }
- X strcpy(basename, p);
- X if ((p = rindex(basename, '.')) != NULL)
- X *p = '\0'; /* remove trailing ".*" */
- X if (targetname != NULL) /* set up target's name */
- X targ = targetname;
- X else
- X targ = basename;
- X if (makename == NULL) {
- X makename = "Makefile";
- X if (access(makename, F_OK) != 0)
- X makename[0] = 'm'; /* not a real check */
- X }
- X msoio(targ); /* Make Sure Output Is Open */
- X abrvsetup(); /* create abrev table, write defs. */
- X if (access(infile, R_OK) != 0) {
- X fprintf(stderr, "%s: Can't open input file '%s', skipped.\n",
- X prgnm, infile);
- X return;
- X }
- X (void)strcpy(buf, CPP); /* build cpp cmd line */
- X#if CPP_M
- X strcat(buf, "-M "); /* -M flag - does dependencies */
- X#endif
- X if (strlen(buf) + strlen(cppflags) + strlen(infile) + 1 > BUFSIZ)
- X err("cpp command line buffer overflow");
- X (void)strcat(buf, cppflags); /* add command flags */
- X (void)strcat(buf, infile); /* add file name */
- X srtfree(&u); /* init insertion sorter */
- X if (verbose)
- X fprintf(stderr, "%s: cpp line is '%s'\n", prgnm, buf);
- X if ((cppfd = nshpopen(buf, "r")) == NULL)
- X err("Can't open pipe for %s", buf);
- X#if CPP_M
- X while (fgets(buf, BUFSIZ, cppfd) != NULL) {
- X if ((p = index(buf, ':')) == NULL)
- X err("cpp -M format error - colon");
- X p++; /* pass colon */
- X if (*p++ != SPC)
- X err("cpp -M format error - space");
- X p = hincl(p); /* skip any uglies in include path */
- X if (!alldep && strncmp("/usr/include", p, 12) == 0)
- X continue; /* ignore /usr/include... stuff */
- X if (index(p, '\n') != NULL) /* replace newline with EOS */
- X *index(p, '\n') = '\0';
- X if ((q = srtin(&u, p, (int (*)())0)) != NULL) /* insert into list */
- X fprintf(stderr, "%s: %s - %s\n", prgnm, q, p); /* warning */
- X }
- X#else
- X while (fgets(buf, BUFSIZ, cppfd) != NULL) {
- X if (buf[0] != '#') /* must start with '#' */
- X continue;
- X if ((p = index(buf, '"')) == NULL) /* find first double quote */
- X continue;
- X p++;
- X p = hincl(p); /* skip any uglies in include path */
- X if (index(p, '"') != NULL) /* terminate the file name */
- X *index(p, '"') = '\0';
- X if (!alldep && strncmp("/usr/include", p, 12) == 0)
- X continue; /* ignore /usr/include... stuff */
- X if ((q = srtin(&u, p, (int (*)())0)) != NULL) /* insert into list */
- X fprintf(stderr, "%s: %s - %s\n", prgnm, q, p); /* warning */
- X }
- X#endif
- X srtgti(&u); /* init for srtgets */
- X /* 2 for colon space */
- X oplen = strlen(objpath) + strlen(targ) + strlen(destsuffix) + 2;
- X le = MAXCOL; /* force new line output */
- X firstln = TRUE; /* first line of a file entry */
- X while ((p = srtgets(&u)) != NULL) { /* write out the entries */
- X if (shortincl)
- X if ((i = findabr(p)) != MXABR) /* i = found index or MXABR */
- X p += abrvlen[i] - 2;
- X if (le + strlen(p) >= MAXCOL) {
- X if (firstln) {
- X le = oplen;
- X fprintf(makefd, "\n%s%s%s: ", objpath, targ, destsuffix);
- X firstln = FALSE;
- X } else {
- X le = 8;
- X fprintf(makefd, " \\\n\t");
- X }
- X } else {
- X fputc(SPC, makefd);
- X }
- X if (shortincl && i != MXABR) {
- X fprintf(makefd, "$%c", 'A' + i);
- X p += 2; /* right place */
- X le += 2;
- X }
- X fputs(p, makefd);
- X le += 1 + strlen(p);
- X }
- X fputc('\n', makefd); /* end with newline */
- X nshpclose(cppfd); /* end of that file */
- X}
- END_OF_FILE
- if test 16381 -ne `wc -c <'maketd/maketd.c'`; then
- echo shar: \"'maketd/maketd.c'\" unpacked with wrong size!
- fi
- # end of 'maketd/maketd.c'
- fi
- echo shar: End of archive 4 \(of 4\).
- cp /dev/null ark4isdone
- MISSING=""
- for I in 1 2 3 4 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 4 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
-
- --
-
- Rich $alz "Anger is an energy"
- Cronus Project, BBN Labs rsalz@bbn.com
- Moderator, comp.sources.unix sources@uunet.uu.net
-