home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume10 / ease / part04 < prev    next >
Encoding:
Internet Message Format  |  1987-07-09  |  47.7 KB

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i054:  Ease translator repost, Part04/04
  5. Message-ID: <622@uunet.UU.NET>
  6. Date: 10 Jul 87 11:26:59 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1337
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: Wombat <rsk@j.cc.purdue.edu>
  12. Posting-number: Volume 10, Issue 54
  13. Archive-name: ease/Part04
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 4 (of 4)."
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. if test -f 'doc/ease.paper' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'doc/ease.paper'\"
  25. else
  26. echo shar: Extracting \"'doc/ease.paper'\" \(29063 characters\)
  27. sed "s/^X//" >'doc/ease.paper' <<'END_OF_FILE'
  28. X.LP
  29. X.TL
  30. XEase: A Configuration Language
  31. Xfor Sendmail
  32. X.AU
  33. XJames S. Schoner
  34. X.AI
  35. XPurdue University Computing Center
  36. XWest Lafayette, Indiana  47907
  37. X.sp 2
  38. X.I
  39. X.ce
  40. XABSTRACT
  41. X.R
  42. X.PP
  43. XThe rapid expansion of computer networks and ensuing variation among mailing
  44. Xaddress formats have made address interpretation an increasingly
  45. Xcomplex task.  In the UNIX* 4.2BSD operating system, a program named 
  46. X\fIsendmail\fR was introduced which provided a
  47. Xgeneral internetwork mail routing facility.  This facility has significantly
  48. Xdiminished the complexity of handling address interpretation.
  49. X.PP
  50. X\fISendmail\fR's address interpretation is based on a rewriting
  51. Xsystem composed of
  52. Xa number of rewriting rules (or productions) arranged as part of a 
  53. Xconfiguration file.  Unfortunately, the syntactical format of a
  54. Xconfiguration file for \fIsendmail\fR is both terse and rigid, making it
  55. Xrather difficult to modify.  The standard format certainly serves its 
  56. Xpurpose, but, as 
  57. Xthe need to change these configurations increases in frequency, a more 
  58. Xreadable format (i.e., one that is similar to the format 
  59. Xof modern programming languages) is required to permit reasonably 
  60. Xquick modifications to the configuration.  As a solution to this problem, 
  61. X\fBEase\fR 
  62. Xprovides a level of abstraction which eliminates most of the current
  63. Xsyntactic hindrances
  64. Xfaced by programmers who must reconfigure \fIsendmail\fR's 
  65. Xaddress parsing scheme.  
  66. X.PP
  67. XAs a high-level specification format, \fBEase\fR is proving to be an 
  68. Xexcellent alternative to \fIsendmail\fR's cryptic 
  69. Xconfiguration file syntax.  The syntactic structures of \fBEase\fR 
  70. Xare patterned after modern language constructs, making the language
  71. Xeasy to learn and easy to remember.  The format of the address rewriting
  72. Xrule is perhaps the most significant syntactical improvement.  It was 
  73. Xundoubtedly
  74. Xthe most needed improvement.  Nevertheless, every element of a configuration 
  75. Xfile is structurally enhanced through the use of \fBEase\fR. 
  76. X.FS
  77. X*  UNIX is a trademark of AT&T Bell Laboratories.
  78. X.FE
  79. X.sp 2
  80. X.NH
  81. XIntroduction
  82. X.PP
  83. XThe \fBEase\fR language is a high-level specification format for \fIsendmail\fR's
  84. Xconfiguration file.  The motivation for its development
  85. Xwas to fulfill a goal of providing a readable and easily modifiable 
  86. X\fIsendmail\fR configuration file format.  \fBEase\fR fulfills this goal by
  87. Xshielding the programmer from the cryptic configuration specification required
  88. Xby \fIsendmail\fR and providing a high-level language with which the programmer
  89. Xmay specify all modifications to a configuration file.  The development 
  90. Xof Ease coincided with
  91. Xthe development of an \fBEase\fR translator, \fIet\fR,
  92. Xwhich translates a configuration file written 
  93. Xin \fBEase\fR to an
  94. Xequivalent file of the standard format accepted by \fIsendmail\fR.
  95. X.NH
  96. XEase in Profile
  97. X.PP
  98. XAs will be seen in the next section, the syntax of \fBEase\fR is quite
  99. Xreadable and easy to learn.  In order to acquire a relevant perspective
  100. Xon this issue,
  101. Xthe reader is advised to examine a raw configuration file for \fIsendmail\fR (the 
  102. Xoutput
  103. Xof the \fBEase\fR translator, \fIet\fR, will do nicely).  The raw syntax, while
  104. Xquite fitting for quick translation, can prove to be a programmer's nightmare.  
  105. X.PP
  106. XUndoubtedly, one of the more prominent features of \fBEase\fR is the ability 
  107. Xto attach
  108. Xnames to address fields.  When address field names are well-chosen, a distinct,
  109. Xself-documenting quality becomes a visible part of the address rewriting 
  110. Xrules.  Ostensibly, address field names provide a new level of semantic 
  111. Xabstraction.  A brief comparison of the formats can be accomplished by examining
  112. Xthe following equivalent representations of an address pattern:
  113. X.DS
  114. X    user_path@host_name            (\fBEase\fR format)
  115. X    $+@$-                    (raw format)
  116. X.DE
  117. XIn the above, \*Quser_path\*U represents a field of one or more address
  118. Xtokens, and \*Qhost_name\*U represents one address token exactly.  These
  119. Xtoken fields are represented by \*Q$+\*U and \*Q$-\*U in the raw format.  Clearly, 
  120. Xthe \fBEase\fR format is preferable, not only for increased readability, but 
  121. Xstructural comprehension as well.
  122. X.PP
  123. XOther features of \fBEase\fR include ruleset naming, long identifiers for 
  124. Xmacros and classes, flow-of-control structures, and free formatting.  In
  125. Xaddition, the C language preprocessor (cpp) can be used for file inclusion
  126. Xand conditionally defined code constructs.  The next section describes
  127. Xthe \fBEase\fR language in complete detail.
  128. X.NH
  129. XEase Syntax*
  130. X.FS
  131. X*  \fINo attempt is made to describe the complete semantic meaning 
  132. Xassociated with all of the constructs of a sendmail configuration file.  Items 
  133. Xnot covered in this document include the semantic distinction among rulesets, 
  134. Xthe special uses of
  135. Xpre-defined macros, and the method of building configuration files.  To
  136. Xobtain this information, the reader is advised to refer to
  137. Xthe Installation and Operation Guide for Sendmail (UNIX
  138. XProgrammer's Manual, Volume 2c), by Eric Allman.\fR
  139. X.FE
  140. X.PP
  141. XAt its highest level, \fBEase\fR can be viewed as a collection of 
  142. Xblock-structures, where each block begins with a keyword and is followed by
  143. Xzero or more related definitions and/or declarations.  There are ten distinct 
  144. Xblock types.  The following is 
  145. Xa list containing all ten block keywords and the block type it denotes.
  146. X.TS
  147. Xcenter;
  148. Xl l .
  149. X\fIbind\fR    -ruleset identifier bindings
  150. X\fImacro\fR    -macro definitions
  151. X\fIclass\fR    -class definitions
  152. X\fIoptions\fR    -\fIsendmail\fR option definitions
  153. X\fIprecedence\fR    -precedence definitions
  154. X\fItrusted\fR    -trusted users
  155. X\fIheader\fR    -mail header definitions
  156. X\fImailer\fR    -mailer definitions
  157. X\fIfield\fR    -address field definitions
  158. X\fIruleset\fR    -address rewriting rules
  159. X.TE
  160. X.sp 1
  161. XIn general,
  162. X.TS
  163. Xcenter ;
  164. Xl .
  165. X
  166. X* Letters are distinguished by case,
  167. X
  168. XT{
  169. X* An \fBEase\fR identifier is defined to be a letter, followed by zero or 
  170. Xmore letters, digits, underscores (_), or dashes (-),
  171. XT}
  172. X
  173. XT{
  174. X* A literal newline or double quotation (") character may be included in 
  175. Xany quoted string by preceding the character with a backslash (\\\\\), and
  176. XT}
  177. X
  178. XT{
  179. X* \fBEase\fR source is preprocessed by the C language preprocessor (cpp),
  180. Xthus source comments (i.e., text enclosed by \*Q/*\*U and \*Q*/\*U) may appear 
  181. Xanywhere as part of \fBEase\fR whitespace.
  182. XT}
  183. X.TE
  184. X.PP
  185. XFor notational convenience, this document specifies all reserved
  186. Xwords of the \fBEase\fR language in italics.  In addition, quantities
  187. Xenclosed in angle brackets (<..>) represent arbitrary 
  188. Xidentifiers, strings, or numbers.  
  189. X.NH 2
  190. XRuleset Identifier Bindings
  191. X.PP
  192. XA ruleset (a set of rewriting rules) is identified solely by an integer 
  193. Xin \fIsendmail\fR's
  194. Xconfiguration file.  \fBEase\fR, however, allows each ruleset to be named with
  195. Xa meaningful identifier.  Since a special numeric association for each 
  196. Xruleset is required by the address parsing scheme of \fIsendmail\fR, a \fIbind\fR
  197. Xblock must be present in any \fBEase\fR file which defines one or more 
  198. Xrulesets.  A
  199. X\fIbind\fR block consists of the keyword \fIbind\fR, followed by zero or more
  200. Xstatements of the form:
  201. X.TS
  202. Xcenter box;
  203. Xl .
  204. X<ruleset-id> = \fIruleset\fR <ruleset-number> ;
  205. X.TE
  206. XThe following example, 
  207. X.sp 1
  208. X\fIbind\fR
  209. X.PP
  210. XFINAL_RW = \fIruleset\fR 4;
  211. X.sp 1
  212. Xspecifies that FINAL_RW, the final rewriting ruleset, is \fIsendmail\fR's ruleset 
  213. Xnumber 4.
  214. X.NH 2
  215. XMacro Definitions
  216. X.PP
  217. XA macro is an identifier which, when referenced in the text of a program,
  218. Xis replaced by its value, a string of zero or more characters.  The value
  219. Xof a macro may include references to other macros, but not itself!  \fISendmail\fR
  220. Xallows a maximum of 26 user-declared macros in its configuration file.  In 
  221. Xaddition, there are a number of pre-declared macros which have special meaning
  222. Xto \fIsendmail\fR (see Appendix A).  \fBEase\fR macros are defined in 
  223. X\fImacro\fR blocks.  \fBEase\fR allows any macro to be declared 
  224. X(which is equivalent to simply referencing it) before it is defined.  A macro
  225. Xidentifier is replaced by its value when it is preceded by the character
  226. X\*Q$\*U.  In addition, a macro reference inside a quoted string must always 
  227. Xinclude braces ({}) around the macro identifier (for delimiting purposes).  
  228. X.PP
  229. XA \fImacro\fR block consists of the keyword \fImacro\fR, followed by zero
  230. Xor more statements taking either of the following forms:
  231. X.TS
  232. Xcenter box;
  233. Xl .
  234. X<macro-identifier> = "<macro-value>" ;
  235. X<macro-identifier> = \fBconditional-expression\fR ;
  236. X.TE
  237. XThe \fBconditional-expression\fR format will be discussed 
  238. Xlater.  
  239. X.sp 1
  240. XThe following example,
  241. X.sp 1
  242. X\fImacro\fR
  243. X.PP
  244. Xfirst_name = "James";
  245. X.PP
  246. Xlast_name = "Schoner";
  247. X.PP
  248. Xwhole_name = "${first_name} ${second_name}";
  249. X.sp 1
  250. Xdefines the macros first_name, last_name, and whole_name, where whole_name
  251. Xis the string, "James Schoner".
  252. X.NH 2
  253. XClass definitions
  254. X.PP
  255. XA class is denoted by an identifier representing a logical grouping of zero 
  256. Xor more names.  Classes are used to represent the range of values a token
  257. Xmay assume in the pattern matching of an address.  Further discussion on the
  258. Xuse of classes will be deferred until address fields are described.
  259. X.PP
  260. XOne identifier may be used to distinctly represent both a macro
  261. Xand class (i.e., the set of macro identifiers and the set of class identifiers
  262. Xmay form a non-empty intersection).  A name, or class element, may 
  263. Xbe an identifier or any quoted word.
  264. X.PP
  265. XA \fIclass\fR block consists of the keyword \fIclass\fR, followed by zero
  266. Xor more statements taking any of the following forms:
  267. X.TS
  268. Xcenter box;
  269. Xl .
  270. X<class-identifier> = { <name1>, <name2>, <name3>, ... } ;
  271. X<class-identifier> = \fIreadclass\fR ( "<file-name>" ) ;
  272. X<class-identifier> = \fIreadclass\fR ( "<file-name>", "<read-format>" ) ;
  273. X.TE
  274. XThe second and third forms cause \fIsendmail\fR to read the names of the class 
  275. Xfrom the named
  276. Xfile.  The third form contains a read format, which should be a \fIscanf(3)\fR 
  277. Xpattern yielding a single string.
  278. X.sp 1
  279. XThe following example,
  280. X.sp 1
  281. X\fIclass\fR
  282. X.PP
  283. Xcampus_hosts = { statistics, engineering, chemistry, physics, physics-2 } ;
  284. X.PP
  285. Xversions     = { "1.0", "1.1", "4.0", "4.2", latest-and-greatest } ;
  286. X.PP
  287. Xphone_hosts  = \fIreadclass\fR ( "/tmp/phonenet.list" ) ;
  288. X.sp 1
  289. Xdefines the classes campus_hosts, versions, and phone_hosts.
  290. X.NH 2
  291. XSendmail option definitions
  292. X.PP
  293. XA number of options to the \fIsendmail\fR program may be specified in 
  294. Xan \fIoptions\fR
  295. Xblock.  For a description of the various \fIsendmail\fR options and their 
  296. Xvalues, see Appendix B.  
  297. X.PP
  298. XAn
  299. X\fIoptions\fR block consists of the keyword \fIoptions\fR, followed by zero
  300. Xor more statements taking any of the following forms:
  301. X.TS
  302. Xcenter box;
  303. Xl l .
  304. X<option-identifier>    = "<option-value>" ;
  305. X\fIo_delivery\fR    = \fBspecial-value\fR ;
  306. X\fIo_handling\fR    = \fBspecial-value\fR ;
  307. X.TE
  308. XAll but two options (\fIo_delivery\fR and \fIo_handling\fR) use the first 
  309. Xform.  To specify an option without a value, simply assign to it the null 
  310. Xstring ("").  The \fBspecial-value\fR field of the second and third form
  311. Xrefers to special values (non-quoted) which are specified in Appendix B.
  312. X.sp 1
  313. XThe following example,
  314. X.sp 1
  315. X\fIoptions\fR
  316. X.PP
  317. X\fIo_alias\fR = "/usr/lib/aliases" ;
  318. X.PP
  319. X\fIo_tmode\fR = "0600" ;
  320. X.PP
  321. X\fIo_delivery\fR = d_background ;
  322. X.sp 1
  323. Xsets the options \fIo_alias\fR, \fIo_tmode\fR, and \fIo_delivery\fR.
  324. X.NH 2
  325. XPrecedence definitions
  326. X.PP
  327. XMessage headers may contain a \*QPrecedence:\*U field describing the precedence
  328. Xof the message class.  Identifiers which may appear in the precedence field of
  329. Xa message are given precedence values in a configuration file \fIprecedence\fR 
  330. Xdefinition.  This association will be illustrated below in an example.
  331. X.PP
  332. XA \fIprecedence\fR block consists of the keyword \fIprecedence\fR, followed 
  333. Xby zero or more statements of the form:
  334. X.KS
  335. X.TS
  336. Xcenter box;
  337. Xl .
  338. X<precedence-identifier> = <precedence-integer> ;
  339. X.TE
  340. X.KE
  341. XThe following example,
  342. X.sp 1
  343. X\fIprecedence\fR
  344. X.PP
  345. Xspecial-delivery = 100;
  346. X.PP
  347. Xjunk = -100;
  348. X.sp 1
  349. Xdefines the precedence level for the names \*Qspecial-delivery\*U and 
  350. X\*Qjunk\*U.  Thus, whenever the name \*Qjunk\*U appears in 
  351. Xa \*QPrecedence:\*U field, the corresponding message class will be set to -100.
  352. X.NH 2
  353. XTrusted users
  354. X.PP
  355. X\fISendmail\fR's \fB-f\fR flag allows trusted users to override the sender's
  356. Xmachine address.  Trusted users are listed in \fItrusted\fR blocks.  A 
  357. X\fItrusted\fR block consists of the keyword \fItrusted\fR, followed 
  358. Xby zero or more sets of users taking the form:
  359. X.TS
  360. Xcenter box;
  361. Xl .
  362. X{ <user1>, <user2>, <user3>, ... } ;
  363. X.TE
  364. XThe following example,
  365. X.sp 1
  366. X\fItrusted\fR
  367. X.PP
  368. X{ root, uucp, network } ;
  369. X.PP
  370. X{ acu, kcs, jss } ;
  371. X.sp 1
  372. Xspecifies that the users root, uucp, network, acu, kcs, and jss can be trusted 
  373. Xto use the \fIsendmail\fR flag, \fB-f\fR.
  374. X.NH 2
  375. XMail header definitions
  376. X.PP
  377. XThe format of the message headers inserted by \fIsendmail\fR is defined in one
  378. Xor more \fIheader\fR blocks in the configuration file.  A \fIheader\fR block
  379. Xconsists of the keyword \fIheader\fR, followed by zero or more statements
  380. Xtaking any of the following forms:
  381. X.TS
  382. Xcenter box;
  383. Xl 
  384. Xl
  385. Xl
  386. Xl
  387. Xl
  388. Xl
  389. Xl
  390. Xl
  391. Xl
  392. Xl
  393. Xl .
  394. X\fIfor\fR ( <mailer-flag1>, <mailer-flag2>, ... )
  395. X       \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
  396. X
  397. X\fIfor\fR ( <mailer-flag1>, <mailer-flag2>, ... ) {
  398. X       \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
  399. X       \fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
  400. X       .
  401. X       .
  402. X} ;
  403. X
  404. X\fIdefine\fR ( "<header-title>" , \fBheader-value\fR ) ;
  405. X.TE
  406. XThe first form is used to define one header for one or more mailer
  407. Xflags.  The second form differs from the first in that more than one
  408. Xheader may be defined for a given set of flags.  The third form is used to 
  409. Xdefine a header,
  410. Xregardless of mailer flags.  Refer to Appendix C for a list of \fBEase\fR 
  411. Xidentifiers representing mailer flags.  The header title is a simple
  412. Xstring of characters (no macro references), whereas the \fBheader-value\fR can
  413. Xbe either a string of characters (possibly containing macro references) or 
  414. Xa \fBconditional-expression\fR (discussed later).
  415. X.sp 1
  416. XThe following example,
  417. X.DS
  418. X\fIheader\fR
  419. X
  420. X    \fIdefine\fR ( "Subject:", "") ;
  421. X
  422. X    \fIfor\fR ( \fIf_return\fR )
  423. X        \fIdefine\fR ( "Return-Path:", "<${\fIm_sreladdr\fR}>" ) ;
  424. X
  425. X    \fIfor\fR ( \fIf_date\fR ) {
  426. X        \fIdefine\fR ( "Resent-Date:", "${\fIm_odate\fR}" ) ;
  427. X        \fIdefine\fR ( "Date:", "${\fIm_odate\fR}" );
  428. X    } ;
  429. X.DE
  430. Xdefines a \*QSubject\*U field for all mailers, regardless of their flags, a
  431. X\*QReturn-Path\*U field for mailers whose definition specifies
  432. Xthe flag, \fIf_return\fR, and the headers, \*QResent-Date\*U and \*QDate\*U,
  433. Xfor mailers whose definition specifies the flag, \fIf_date\fR.
  434. X.NH 2
  435. XMailer Definitions
  436. X.PP
  437. X\fISendmail\fR's definition of a mailer (or an interface to one) occurs in a
  438. X\fImailer\fR block.  A \fImailer\fR block consists of the keyword \fImailer\fR,
  439. Xfollowed by zero or more statements of the form:
  440. X.TS
  441. Xcenter box;
  442. Xl .
  443. X<mailer-identifier> { \fBmailer-spec\fR } ;
  444. X.TE
  445. XThe field, \fBmailer-spec\fR, is a list of zero or more of the
  446. Xfollowing attribute assignments (where successive assignment statements are
  447. Xseparated by commas):
  448. X.TS
  449. Xcenter ;
  450. Xl l 
  451. Xl l
  452. Xl l
  453. Xl l
  454. Xl l
  455. Xl l
  456. Xl l .
  457. X\fIPath\fR    = \fBstring-attribute\fR
  458. X\fIArgv\fR    = \fBstring-attribute\fR
  459. X\fIEol\fR    = \fBstring-attribute\fR
  460. X\fIMaxsize\fR    = \fBstring-attribute\fR
  461. X\fIFlags\fR    = { <mailer-flag1>, <mailer-flag2>, ... } 
  462. X\fISender\fR    = <sender-ruleset-id>
  463. X\fIRecipient\fR    = <recipient-ruleset-id>
  464. X.TE
  465. XThe \fBstring-attribute\fR value can take the form of a quoted string
  466. X(possibly containing macro references) or a \fBconditional-expression\fR 
  467. X(discussed later).
  468. X.sp 1
  469. XThe following example,
  470. X.sp 1
  471. X\fImailer\fR
  472. X.DS
  473. X    local {
  474. X        \fIPath\fR        = "/bin/mail",
  475. X        \fIFlags\fR        = { \fIf_from\fR, \fIf_locm\fR },
  476. X        \fISender\fR    = Sender_RW,
  477. X        \fIRecipient\fR    = Recip_RW,
  478. X        \fIArgv\fR        = "mail -d ${\fIm_ruser\fR}",
  479. X        \fIMaxsize\fR    = "200000"
  480. X    } ;
  481. X.DE
  482. Xdefines a mailer named \*Qlocal\*U.
  483. X.NH 2
  484. XAddress field definitions
  485. X.PP
  486. X\fISendmail\fR's address parsing scheme treats an address as a group of tokens
  487. X(an address token is precisely defined in the Arpanet protocol RFC822).  In
  488. Xgeneral, \fIsendmail\fR divides an address into tokens based on a list of
  489. Xcharacters assigned as a string to the special macro \fIm_addrops\fR.  These
  490. Xcharacters will individually be considered as tokens and will separate tokens
  491. Xwhen parsing is performed. 
  492. X.PP
  493. XFor
  494. Xthe \fBEase\fR language, there is a distinct set of address tokens (defined
  495. Xbelow) which are used in combination to represent generic forms of 
  496. Xaddresses.  In 
  497. Xaddition to literal address tokens, the pattern to be matched in a rewriting 
  498. Xrule (often refered to as the LHS) may
  499. Xinclude field identifiers which match one of five possibilities:
  500. X.DS
  501. X    - zero or more tokens
  502. X    - one or more tokens
  503. X    - one token exactly
  504. X    - one token which is an element of an aribitrary class \fBX\fR
  505. X    - one token which is not an element of an aribitrary class \fBX\fR
  506. X.DE
  507. XA particular field type may be assigned to one or more identifiers.  Each
  508. Xfield identifier is associated with (or defined to be) a field type in
  509. Xa \fIfield\fR declarations block.  A \fIfield\fR declarations block consists
  510. Xof the keyword \fIfield\fR, followed by zero or more field definitions of
  511. Xthe form:
  512. X.TS
  513. Xcenter box;
  514. Xl .
  515. X\fBfield-id-list\fR : \fBfield-type\fR ;
  516. X.TE
  517. XA \fBfield-id-list\fR is a list of one or more identifiers, each separated by
  518. Xa comma.  A \fBfield-type\fR, on the other hand, is a representation of 
  519. Xone of the five fields 
  520. Xdescribed above.  The syntax for each of the five forms follows:
  521. X.DS
  522. X    \fImatch\fR ( 0* )
  523. X    \fImatch\fR ( 1* )
  524. X    \fImatch\fR ( 1 )
  525. X    \fImatch\fR ( 1 ) in <class-X>
  526. X    \fImatch\fR ( 0 ) in <class-X>
  527. X.DE
  528. XThe star in the first two forms means: "or more".  Thus, the first
  529. Xform would read: "match zero or more tokens".  The fourth form describes
  530. Xa field where one token is matched from an arbitrary class (class-X), whereas
  531. Xthe fifth form describes a field where one token is matched if it is not of the
  532. Xgiven class (class-X).
  533. X.sp 1
  534. XThe following example,
  535. X.sp 1
  536. X.DS
  537. X\fIfield\fR
  538. X    anypath        : \fImatch\fR ( 0* );
  539. X    recipient_host    : \fImatch\fR ( 1 );
  540. X    local_site        : \fImatch\fR ( 1 ) in \fIm_sitename\fR;
  541. X    remote_site        : \fImatch\fR ( 0 ) in \fIm_sitename\fR;
  542. X.DE
  543. Xdefines the fields anypath, recipient_host, local_site, and remote_site.
  544. X.NH 2
  545. XAddress rewriting rules
  546. X.PP
  547. XAddress rewriting rules are grouped according to the function they perform.  For
  548. Xexample, it is desirable to form a distinct group for those rewriting rules 
  549. Xwhich perform transformations on recipient addresses.
  550. X.PP
  551. XSets of rewriting rules are defined in \fIruleset\fR blocks.  A \fIruleset\fR
  552. Xblock consists of the keyword \fIruleset\fR, followed by zero or more
  553. Xruleset definitions of the form:
  554. X.TS
  555. Xcenter box;
  556. Xl .
  557. X<ruleset-id> { <rewriting-rule1> <rewriting-rule2> ... }
  558. X.TE
  559. XThe ruleset identifier, ruleset-id, must be defined in a \fIbind\fR block, as
  560. Xdescribed earlier.  The rewriting rules have the form:
  561. X.DS
  562. X    \fIif\fR ( <match-pattern> )
  563. X        <match-action> ( <rewriting-pattern> ) ;
  564. X.DE
  565. Xwhere match-pattern, rewriting-pattern, and match-action are described below.
  566. X.NH 3
  567. XMatch-patterns
  568. X.PP
  569. XA match-pattern is a sequence of Ease address elements representing an
  570. Xaddress format.  If the address being rewritten matches the pattern
  571. X\*Qmatch-pattern\*U,
  572. Xthen the address is reformatted using the pattern \*Qrewriting-pattern\*U, and 
  573. Xthe corresponding
  574. Xaction (\*Qmatch-action\*U) is performed.  The five distinct Ease address
  575. Xelements which may constitute a match-pattern are as follows:
  576. X.TS
  577. Xcenter ;
  578. Xl .
  579. X1. Field Identifiers (refer to previous section)
  580. XT{
  581. X2. Non-alphanumeric characters (the exception is the case for literal 
  582. Xdouble quotes, which must be preceded by a backslash (\\\\\)
  583. XT}
  584. X3. Macro references
  585. X4. Quoted strings ("...")
  586. X5. \fBConditional-expressions\fR (discussed later)
  587. X.TE
  588. XBelow are two sample match-patterns, each describing the same address format:
  589. X.DS
  590. X    user-id @ hostname . $arpa_suffix
  591. X    user-id @ hostname ".ARPA"
  592. X.DE
  593. Xwhere user-id and hostname are field identifiers, and arpa_suffix is a 
  594. Xuser-defined macro with the value \*QARPA\*U.
  595. X.NH 3
  596. XRewriting-patterns
  597. X.PP
  598. XA rewriting-pattern specifies the form in which to rewrite a matched 
  599. Xaddress.  The seven distinct elements which may be used to form 
  600. Xa rewriting-pattern are as follows:
  601. X.TS
  602. Xcenter ;
  603. Xl .
  604. X
  605. XT{
  606. X1. Non-alphanumeric characters (the exception is the case for literal
  607. Xdouble quotes, left parentheses, or right parentheses, each of which 
  608. Xmust be preceded by a backslash (\\\\\). 
  609. XT}
  610. X
  611. XT{
  612. X2. A call to another ruleset.  This is used to perform rewrites
  613. Xon a suffix of the rewriting-pattern.  The proper use of this
  614. Xfeature will be demonstrated by example below. 
  615. XT}
  616. X
  617. X3. Quoted strings ("...").
  618. X
  619. X4. \fBConditional-expressions\fR (discussed later).
  620. X
  621. X5. A macro reference.
  622. X
  623. XT{
  624. X6. A positional reference in the matched address.  A positional 
  625. Xreference takes the form: $<integer-position>.  For example, 
  626. X$3 references the value of the third \fBEase\fR address 
  627. Xelement in the matched address.
  628. XT}
  629. X
  630. XT{
  631. X7. Canonicalized host names of the form \fIcanon\fR (<id-token>),
  632. Xwhere id-token is a regular identifier, a quoted identifier (with
  633. Xdouble quotes), a macro reference yielding an identifier, or a 
  634. Xpositional reference in the matched address.  The canonicalization of 
  635. Xa host name is simply a mapping to its canonical (or official) form.
  636. XT}
  637. X
  638. X.TE
  639. XBelow are two sample rewriting-patterns:
  640. X.DS
  641. X    $1 % $2 < @ $3 ".ARPA" >
  642. X    OLDSTYLE_RW ( $1 )
  643. X.DE
  644. XThe first form specifies an address such as a%b<@c.ARPA>, where a, b, and c
  645. Xrepresent matched identifiers or paths.  The second form specifies a call to
  646. Xthe ruleset \*QOLDSTYLE_RW\*U, for old-style rewriting on the parameter 
  647. X$1, which probably references the entire matched address.  This will become 
  648. Xclear in later examples.
  649. X.NH 3
  650. XMatch-actions
  651. X.PP
  652. XWhen a ruleset is called, the address to be rewritten is compared (or matched)
  653. Xsequentially against the match-address of each rewriting rule.  When a
  654. Xmatch-address describes the address \fIsendmail\fR is attempting to rewrite, the
  655. Xaddress is rewritten (or reformatted) using the rule's 
  656. Xrewriting-pattern.  Following this rewrite, the corresponding match-action
  657. Xis performed.  There are four match-actions:
  658. X.TS
  659. Xcenter ;
  660. Xl l .
  661. X\fIretry\fR    T{
  662. X-a standard action which causes the rewritten address
  663. Xto be again compared to the match-address of the current rule. 
  664. XT}
  665. X
  666. X\fInext\fR    T{
  667. X-an action which causes the rewritten address to be
  668. Xcompared to the match-address of the next rewriting rule of the current 
  669. Xruleset.  If the end of the list is reached, the ruleset returns the 
  670. Xrewritten address.
  671. XT}
  672. X
  673. X\fIreturn\fR    T{
  674. X-an action which causes an immediate return of the 
  675. Xruleset with the current rewritten address.
  676. XT}
  677. X
  678. X\fIresolve\fR    T{
  679. X-an action which specifies that the address has been
  680. Xcompletely resolved (i.e., no further rewriting is necessary).  The 
  681. X\fIresolve\fR action is described in more detail below. 
  682. XT}
  683. X.TE
  684. X.PP
  685. XThe match-action, \fIresolve\fR, is special in that it terminates
  686. Xthe address rewriting altogether.  The semantic structure of \fIsendmail\fR's
  687. Xrewriting scheme requires that a \fIresolve\fR action appear only in the 
  688. Xruleset whose numerical binding is to the number zero.  The \fIresolve\fR action
  689. Xmust specify three parameters: \fImailer\fR, \fIhost\fR, and \fIuser\fR.  If
  690. Xthe \fImailer\fR is local, the \fIhost\fR parameter may be omitted.  The
  691. X\fImailer\fR argument must be specified as a single word, macro, or positional
  692. Xreference in the matched address.  The \fIhost\fR argument may be specified as 
  693. Xa single word or as an expression which expands to a single word (i.e.,
  694. X\fIhost\fR ($1 ".ARPA")).  In addition, the \fIhost\fR argument may be a
  695. Xcanonicalization (as described above) or a numeric internet specification.  The
  696. Xkeyword \fIhostnum\fR is used for numeric internet specifications, as in 
  697. X\fIhostnum\fR ("00.00.00.00") or \fIhostnum\fR ( $2 ).  The \fIuser\fR 
  698. Xspecification is a rewriting-pattern, as described above.  
  699. X.PP
  700. XIn general, the format of a \fIresolve\fR action will be as follows:
  701. X.DS
  702. X    \fIresolve\fR (    \fImailer\fR ( <mailer-name> ),
  703. X            \fIhost\fR   ( <host-name> ),
  704. X            \fIuser\fR   ( <user-address>)   );
  705. X.DE
  706. XExamples of the match-action statement are shown below:
  707. X.DS
  708. X\fIfield\fR
  709. X    anypath    : \fImatch\fR (0*);
  710. X    usr, path    : \fImatch\fR (1*);
  711. X    hostname    : \fImatch\fR (1);
  712. X    phone_host    : \fImatch\fR (1) in phonehosts;
  713. X.DE
  714. X.DS
  715. X\fIruleset\fR
  716. X
  717. X    EXAMPLE_RW {
  718. X    
  719. X        \fIif\fR ( anypath < path > anypath )   /* basic RFC821/822 parse */
  720. X            \fIretry\fR ( $2 );
  721. X        \fIif\fR ( usr " at " path )        /* \*Qat\*U -> \*Q@\*U */
  722. X            \fInext\fR ( $1 @ $2 );
  723. X        \fIif\fR ( @path: usr )
  724. X            \fIreturn\fR ( LOCAL_RW ( < @$1 > : $2 ) );
  725. X        \fIif\fR ( anypath < @phone_host".ARPA" > anypath )
  726. X            \fIresolve\fR (    \fImailer\fR ( tcp ),
  727. X                    \fIhost\fR ( csnet-relay ),
  728. X                    \fIuser\fR ( $1 % $2 < @"csnet-relay" > $3 ) );
  729. X    }
  730. X.DE
  731. X.PP
  732. XThe example above defines the ruleset \*QEXAMPLE_RW\*U, which contains four
  733. Xrewriting rules.  The first rewriting rule discards all tokens of an address
  734. Xwhich lie on either side of a pair of angle brackets (<>), thereby 
  735. Xrewriting the address as
  736. Xthe sequence of tokens contained within the angle brackets ($2).  Following the
  737. Xaddress rewrite, the rule is applied again (\fIretry\fR).  When the first rule
  738. Xfails to match the address being rewritten, the second rule is applied.  
  739. X.PP
  740. XThe second 
  741. Xrule simply replaces the word \*Qat\*U by the symbol \*Q@\*U.  The \*Q\fInext\fR\*U
  742. Xaction specifies that if a match is made, a rewrite is performed and 
  743. Xmatching continues at the next (or following) rule.  
  744. X.PP
  745. XThe third rule illustrates
  746. Xthe use of the \*Q\fIreturn\fR\*U action, which is executed if the 
  747. Xpattern \*Q@path: usr\*U
  748. Xdescribes the current format of the address being rewritten.  In this example,
  749. Xthe \fIreturn\fR action returns the result of a call to ruleset \*QLOCAL_RW\*U,
  750. Xwhich rewrites the address \*Q<@$1>:$2\*U, where $1 and $2 are substituted
  751. Xwith the token(s) matched respectively by \*Qpath\*U and \*Qusr\*U.
  752. X.PP
  753. XThe fourth (and final) rule signals a resolution (and termination) of the
  754. Xrewriting process if the given pattern is matched.  The resolution specifies
  755. Xthat the mailer \*Qtcp\*U will be used to deliver the message to the host
  756. X\*Qcsnet-relay\*U.  The \fIuser\fR parameter specifies the final form of the address
  757. Xwhich \fIsendmail\fR has just resolved.
  758. X.sp 2
  759. X.PP
  760. XThe \fBEase\fR construct which remains to be examined is the 
  761. X\fBconditional-expression\fR.  The \fBconditional-expression\fR provides a 
  762. Xmethod for
  763. Xconstructing strings based on the condition that some test macro is (or is not)
  764. Xset.  The general form begins with the concatenation of a string and a
  765. X\fBstring-conditional\fR:
  766. X.DS
  767. X    \fIconcat\fR ( <quoted-string>, \fBstring-conditional\fR )
  768. X    \fIconcat\fR ( \fBstring-conditional\fR, <quoted-string> )
  769. X.DE
  770. XA \fBstring-conditional\fR assumes either of the following forms:
  771. X.DS
  772. X    \fIifset\fR ( <macro-name>, <ifset-string> )
  773. X    \fIifset\fR ( <macro-name>, <ifset-string>, <notset-string> )
  774. X.DE
  775. XA \fBstring-conditional\fR of the first form evaluates to \*Qifset-string\*U 
  776. Xif the macro \*Qmacro-name\*U has been assigned a value; otherwise it
  777. Xevaluates to the null string.  The second form behaves similarly, except
  778. Xthat the \fBstring-conditional\fR evaluates to \*Qnotset-string\*U, instead
  779. Xof the null string, if the macro \*Qmacro-name\*U has no value.
  780. X.sp 1
  781. XThe following \fBconditional-expression\fR,
  782. X.DS
  783. X    \fIconcat\fR ( "New ", \fIifset\fR ( city, "York", "Jersey" ) )
  784. X.DE
  785. Xevaluates to the string "New York", if the macro \*Qcity\*U is set.  Otherwise,
  786. Xthe \fBconditional-expression\fR evaluates to the string "New Jersey".
  787. X.NH
  788. XEase Translation
  789. X.PP
  790. XIt is important to note that \fBEase\fR is translated by a stand-alone
  791. Xtranslator to the raw configuration file format.  No modifications were
  792. Xmade to the \fIsendmail\fR program itself.  As a result, syntactical verification
  793. Xof a configuration file can be performed without invoking \fIsendmail\fR.
  794. X.PP
  795. XThe \fBEase\fR language is translated by invoking 
  796. Xthe C language preprocessor (cpp) with \fBEase\fR source as input, then piping
  797. Xthe output as input to the \fBEase\fR translator (\fIet\fR).  The \fBEase\fR
  798. Xtranslator may be invoked on the command line in one of four ways:
  799. X.TS
  800. Xcenter box ;
  801. Xl l .
  802. X\fIet\fR  <input-file>  <output-file>    [read from a file, write to a file]
  803. X\fIet\fR  <input-file>    [read from a file, write to standard output]
  804. X\fIet\fR  -  <output-file>    [read from standard input, write to a file]
  805. X\fIet\fR    [read from standard input, write to standard output]
  806. X.TE
  807. X.NH
  808. XConclusion
  809. X.PP
  810. X\fBEase\fR is currently in use at the Purdue University Computing 
  811. XCenter.  Source code for the \fBEase\fR translator (\fIet\fR) may be
  812. Xobtained on request by writing to:
  813. X.DS
  814. XU.S. Mail:
  815. X        James S. Schoner
  816. X        c/o Kevin S. Braunsdorf
  817. X        Purdue University Computing Center
  818. X        Purdue University
  819. X        West Lafayette, Indiana  47907
  820. X
  821. XElectronic Mail:
  822. X        ksb@j.cc.purdue.edu
  823. X.DE
  824. X.PP
  825. XMuch of the success of this project is attributable to the constant support 
  826. Xand insight offered by Mark Shoemaker.  To him, I owe a debt of gratitude.  In 
  827. Xaddition, I would like to thank Kevin Smallwood, Paul Albitz, and Rich Kulawiec
  828. Xfor their many notable suggestions and valuable insight.
  829. END_OF_FILE
  830. if test 29063 -ne `wc -c <'doc/ease.paper'`; then
  831.     echo shar: \"'doc/ease.paper'\" unpacked with wrong size!
  832. fi
  833. # end of 'doc/ease.paper'
  834. fi
  835. if test -f 'maketd/maketd.c' -a "${1}" != "-c" ; then 
  836.   echo shar: Will not clobber existing file \"'maketd/maketd.c'\"
  837. else
  838. echo shar: Extracting \"'maketd/maketd.c'\" \(16381 characters\)
  839. sed "s/^X//" >'maketd/maketd.c' <<'END_OF_FILE'
  840. X/* maketd - MAKE Transitive Dependencies.
  841. X * (This is a lie - the dependencies are not transitive, but "all"
  842. X * dependencies are correctly made.)
  843. X *
  844. X * Based loosely on a shell script by Stephan Bechtolsheim, svb@purdue
  845. X * Other Makefile related features have been added or merged in from
  846. X * other programs.
  847. X *
  848. X * Written & hacked by Stephen Uitti, PUCC staff, ach@pucc-j, 1985
  849. X * maketd is copyright (C) Purdue University, 1985
  850. X *
  851. X * removed some of Steve's good, but unnecessary, options in favor
  852. X * of more compile time flags & better implicit rules in the makefile
  853. X * dinked: -q -e -E -k
  854. X * Kevin S Braunsdorf, PUCC UNIX Group 1986    (ksb@j.cc.purdue.edu)
  855. X *
  856. X * Permission is hereby given for its free reproduction and
  857. X * modification for non-commercial purposes, provided that this
  858. X * notice and all embedded copyright notices be retained.
  859. X * Commercial organisations may give away copies as part of their
  860. X * systems provided that they do so without charge, and that they
  861. X * acknowledge the source of the software.
  862. X */
  863. X#include <sys/types.h>
  864. X#include <sys/param.h>
  865. X#include <sys/file.h>            /* for access */
  866. X#ifdef BSD2_9
  867. X#include <ndir.h>            /* for MAXPATHLEN, MAXNAMLEN */
  868. X#endif
  869. X#ifdef BSD4_2
  870. X#include <sys/dir.h>            /* for MAXNAMLEN in 4.2 */
  871. X#endif
  872. X#include <ctype.h>            /* for isupper */
  873. X#include <stdio.h>
  874. Xextern char *rindex(), *index(), *strcat(), *strcpy();
  875. X
  876. X#include "srtunq.h"
  877. X#include "abrv.h"
  878. X#include "nshpopen.h"
  879. X#include "maketd.h"
  880. X
  881. X#ifndef CPP
  882. X#define CPP    "/lib/cpp "
  883. X#endif CPP not in Makefile
  884. X
  885. X/* forward functions */
  886. Xvoid    msoio();            /* open output file */
  887. Xvoid    rdwr();                /* read old Makefile into new */
  888. Xvoid    mkdepend();            /* does the real work */
  889. X
  890. X/* globals */
  891. Xchar *prgnm;                /* our program name        */
  892. XFILE *makefd;                /* makefile stream        */
  893. Xint    alldep = FALSE;            /* -a all - /usr/include too    */
  894. Xchar   *targetname = NULL;        /* -t target name for next file */
  895. Xchar   *destsuffix = ".o";        /* -s suffix for targets    */
  896. Xint    header = TRUE;            /* print header & trailer    */
  897. Xint    usestdout = FALSE;        /* -d use stdout for makefile    */
  898. Xint    forcehead = FALSE;        /* -f force header/trailer    */
  899. Xint    makenseen = FALSE;        /* output file has been specified */
  900. Xchar   *makename = "makefile";        /* -m default file for edit    */
  901. Xint    backedup = FALSE;        /* for interupt recovery    */
  902. Xchar    backupfn[MAXNAMLEN+1];        /* backup file name        */
  903. Xint    ismakeopen = FALSE;        /* if the output file is open    */
  904. Xchar    objpath[MAXPATHLEN+1];        /* -o prepended to .o's        */
  905. Xint    nonlocalo = FALSE;        /* -nonlocalo objects in source dir */
  906. Xint    replace = FALSE;        /* -r replace depends in Makefile */
  907. Xchar    cppflags[BUFSIZ];        /* -D, -I, -U flags to pass to cpp */
  908. Xint    shortincl = TRUE;        /* -x do abreviations        */
  909. Xint    verbose = FALSE;        /* -v verbage for the debugger    */
  910. Xstatic char   sopts[] = "abdfhrxv";    /* single char opts        */
  911. Xstatic SRTUNQ u;            /* unique include files        */
  912. X
  913. Xchar   usage[] =
  914. X"Usage: maketd [-a -b -d -f -h -mMAKEFILE -nonlocalo -oDIR -r -sSUFFIX\n\
  915. X -tTARGETNAME -x -v -Iincludedir -Ddefine -Uundefine file...]\n";
  916. Xchar   helptext[] =
  917. X"-a\tdo all dependencies, including /usr/include\n\
  918. X-b\tgenerate binary, rather than object related dependencies\n\
  919. X-d\tdependencies to stdout, rather than Makefile\n\
  920. X-f\tforce header/trailer (use with -d)\n\
  921. X-h\thelp (this text)\n\
  922. X-m\tspecify MAKEFILE for edit\n\
  923. X-nonlocalo Objects live in source directory\n\
  924. X-o\tprepend DIR to target: DIR/a.o: foo.h\n\
  925. X-r\treplace dependencies for a target\n\
  926. X-s\tchange suffix target's SUFFIX: a.SUFFIX: foo.h\n\
  927. X-t\tchange target's basename: TARGET.o: foo.h\n\
  928. X-x\tdon't abbreviate includes\n\
  929. X-v\tprint extra verbose (debug) output to stderr\n\
  930. X-I\tspecify include directory, as in /lib/cpp\n\
  931. X-D\tspecify defines, as in /lib/cpp\n\
  932. X-U\tspecify undefines, as in /lib/cpp\n";
  933. X
  934. Xchar deplin[] = "# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT\n";
  935. Xchar searchdep[] = "# DO NOT DELETE THIS LINE";
  936. Xchar trailer[] = "\n# *** Do not add anything here - It will go away. ***\n";
  937. X
  938. X/* some init & argv parsing */
  939. Xmain(argc, argv)
  940. Xregister int argc;
  941. Xregister char **argv;
  942. X{
  943. X    register a;                /* argv subscript        */
  944. X    register i;                /* tmp                */
  945. X    register len;            /* length of current argument    */
  946. X    register files = FALSE;        /* files ever seen        */
  947. X    register char *q;            /* tmp                */
  948. X
  949. X    /* prgnm = program name, for error printing */
  950. X    if ((prgnm = rindex(argv[0], '/')) == NULL)
  951. X    prgnm = argv[0];
  952. X    else
  953. X    prgnm++;
  954. X    catchsig();                /* init signal traps */
  955. X    srtinit(&abrv);            /* init abbreviations tree */
  956. X    for (a = 1; a < argc; a++) {    /* argv prepass: find all -I's */
  957. X    if (argv[a][0] == '-' && argv[a][1] == 'I' && strlen(&argv[a][2]) > 2)
  958. X        if ((q = srtin(&abrv, hincl(&argv[a][2]), lngsrt)) != NULL)
  959. X        fprintf(stderr, "%s: %s - %s\n", prgnm, q, &argv[a][2]);
  960. X    }
  961. X    cppflags[0] = '\0';            /* terminate cpp flags string */
  962. X    objpath[0] = '\0';            /* init object path */
  963. X    srtinit(&u);            /* init sorting database tag */
  964. X    for (a = 1; a < argc; a++) {
  965. X    len = strlen(argv[a]);
  966. X    if (argv[a][0] == '-' && len > 2 && index(sopts, argv[a][1]) != NULL)
  967. X        err("options must be listed seperately - '%s'\n", argv[a]);
  968. X    if (len > 1 && argv[a][0] == '-') {
  969. X        switch (argv[a][1]) {
  970. X        case 'D':            /* /lib/cpp flags to pass */
  971. X        case 'I':
  972. X        case 'U':
  973. X        if (strlen(cppflags) + strlen(argv[a]) + 2 > BUFSIZ)
  974. X            err("too many cpp flags - buffer overflow");
  975. X        strcat(cppflags, argv[a]);
  976. X        strcat(cppflags, " ");    /* add a space separator */
  977. X        break;
  978. X        case 'a':            /* /usr/include deps too */
  979. X        alldep = TRUE;
  980. X        break;
  981. X        case 'b':            /* target has no suffix */
  982. X        destsuffix = "";
  983. X        break;
  984. X        case 'd':            /* don't edit Makefile */
  985. X        if (ismakeopen)
  986. X            err("Makefile already open, -d must precede filenames");
  987. X        if (makenseen)
  988. X            err("Conflict - check -d and -m options");
  989. X        makenseen = TRUE;
  990. X        usestdout = TRUE;
  991. X        if (!forcehead)
  992. X            header = FALSE;    /* don't do header & trailer */
  993. X        break;
  994. X        case 'f':            /* force header/trailer */
  995. X        forcehead = TRUE;
  996. X        header = TRUE;
  997. X        break;
  998. X        case 'h':            /* help */
  999. X        fputs(usage, stdout);
  1000. X        fputs(helptext, stdout);
  1001. X        exit(0);
  1002. X        break;
  1003. X        case 'm':            /* specify makefile name for edit */
  1004. X        if (ismakeopen)
  1005. X            err("Makefile already open, -m must precede filenames");
  1006. X        if (makenseen)
  1007. X            err("Conflict, check -m and -d options.");
  1008. X        if (strlen(makename) == 0)
  1009. X            err("-m option requires file name.");
  1010. X        makenseen = TRUE;
  1011. X        makename = &argv[a][2];
  1012. X        break;
  1013. X        case 'n':            /* objects reside with sources */
  1014. X        if (strcmp("nonlocalo", &argv[a][1]) != 0)
  1015. X            err("bad -n option"); /* what a crock of an option */
  1016. X        if (objpath[0] != '\0')
  1017. X            err("nonlocalo conflict - check -o's");
  1018. X        nonlocalo = TRUE;
  1019. X        break;
  1020. X        case 'o':
  1021. X        if (nonlocalo)
  1022. X            err("object path conflict - check -o's and -nonlocalo's");
  1023. X        strcpy(objpath, &argv[a][2]);
  1024. X        i = strlen(objpath);
  1025. X        if (i == 0)
  1026. X            err("-o requires path string.");
  1027. X        if (i >= MAXPATHLEN)
  1028. X            err("Object path too long: max is %d.", MAXPATHLEN);
  1029. X        if (objpath[i - 1] != '/')
  1030. X            strcat(objpath, "/");
  1031. X        break;
  1032. X        case 'r':            /* replace mode */
  1033. X        if (ismakeopen)
  1034. X            err("Makefile already open, -r must precede filenames");
  1035. X        replace = TRUE;
  1036. X        break;
  1037. X        case 's':            /* destination suffix */
  1038. X        destsuffix = &argv[a][2];
  1039. X        break;
  1040. X        case 't':            /* set target's basename */
  1041. X        targetname = &argv[a][2];
  1042. X        if (len <= 2)
  1043. X            err("target option requires name.");
  1044. X        break;
  1045. X        case 'v':            /* user wants to hear noise */
  1046. X        verbose = TRUE;
  1047. X        break;
  1048. X        case 'x':            /* don't abbrev. */
  1049. X        if (files)
  1050. X            err("-x option must preceed all files.");
  1051. X        shortincl = FALSE;
  1052. X        break;
  1053. X        default:
  1054. X        err("Unknown option %s.", argv[a]);
  1055. X        }                /* end switch */
  1056. X    } else {            /* must be a filename */
  1057. X        if (verbose)
  1058. X        fprintf(stderr, "%s: working on %s.\n", prgnm, argv[a]);
  1059. X        files = TRUE;        /* at least one file seen */
  1060. X        if (replace && a != argc - 1)
  1061. X        err("Only one file allowed with -r (edit aborted)");
  1062. X        mkdepend(argv[a]);        /* file to process */
  1063. X        targetname = NULL;        /* affect only one file */
  1064. X    }                /* if option */
  1065. X    }                    /* for argv */
  1066. X    if (ismakeopen && header)
  1067. X    fputs(trailer, makefd);        /* do not delete... */
  1068. X#if    DEL_BACKUP
  1069. X    if (backedup)
  1070. X    if (unlink(backupfn))
  1071. X        err("Can't delete backup file %s on completion", backupfn);
  1072. X#endif    DEL_BACKUP
  1073. X    if (!files)
  1074. X    err("No files to process, use -h for full help.\n%s", usage);
  1075. X    exit(0);                /* exit status - good */
  1076. X}
  1077. X
  1078. X/* msoio - Make Sure Output Is Open.
  1079. X * Interacts strongly via globals: makefd, backedup, backupfn, makename,
  1080. X * header, ismakeopen
  1081. X */
  1082. Xvoid
  1083. Xmsoio(targ)
  1084. Xchar *targ;                /* if -r, is target name */
  1085. X{
  1086. X    FILE *tmpfd;            /* temp file desc for -d */
  1087. X    char buf[BUFSIZ];            /* for reading the makefile */
  1088. X
  1089. X    if (ismakeopen)
  1090. X    return;
  1091. X    ismakeopen = TRUE;            /* will be: all errs are fatal */
  1092. X    if (usestdout) {
  1093. X    makefd = stdout;
  1094. X    if (header) {
  1095. X        fputc('\n', makefd);    /* one blank line */
  1096. X        fputs(deplin, makefd);    /* the first line */
  1097. X    }
  1098. X    /* scan "makefile" or "Makefile" for include defines */
  1099. X    if (access(makename, R_OK) != 0) {
  1100. X        makename[0] = 'M';        /* try Makefile */
  1101. X        if (access(makename, R_OK) != 0)
  1102. X        return;            /* just punt */
  1103. X    }
  1104. X    if ((tmpfd = fopen(makename, "r")) == NULL)
  1105. X        return;            /* just punt */
  1106. X    while (fgets(buf, BUFSIZ, tmpfd) != NULL)
  1107. X        srchincl(buf);        /* scan whole file */
  1108. X    fclose(tmpfd);
  1109. X    return;
  1110. X    }                    /* ... if standard out */
  1111. X/* !makenseen means (default) try "makefile" then "Makefile" */
  1112. X    if (!makenseen && access(makename, F_OK) != 0)
  1113. X    makename[0] = 'M';        /* try Makefile */
  1114. X/* side effect: "Makefile" will be created if neither exist */
  1115. X    if (access(makename, F_OK) == 0) {    /* if makefile exits */
  1116. X    strcpy(backupfn, makename);    /* get rid of .bak */
  1117. X    strcat(backupfn, ".bak");
  1118. X    if (access(backupfn, F_OK) == 0) {
  1119. X        if (unlink(backupfn))
  1120. X        err("Can't remove %s for pre-edit\n", backupfn);
  1121. X    }
  1122. X    if (link(makename, backupfn))    /* mv makefile to .bak */
  1123. X        err("Can't link %s to %s.", backupfn, makename);
  1124. X    backedup = TRUE;        /* for interupt status */
  1125. X    if (unlink(makename))
  1126. X        err("Can't unlink %s during rename.", makename);
  1127. X    } else {
  1128. X    backupfn[0] = '\0';        /* no copy (no makefile) */
  1129. X    }
  1130. X    if ((makefd = fopen(makename, "w")) == NULL)
  1131. X    err("Can't open output file '%s' for write.", makename);
  1132. X    if (backupfn[0] != '\0')        /* if no .bak file - done */
  1133. X    rdwr(targ);            /* read/write Makefile */
  1134. X    else
  1135. X    fputs(deplin, makefd);        /* must start with this */
  1136. X}
  1137. X
  1138. X/* create beginging of new Makefile by reading old one */
  1139. Xvoid
  1140. Xrdwr(targ)
  1141. Xchar *targ;
  1142. X{
  1143. X    register FILE *oldfd;        /* file pointer for .old */
  1144. X    char rwbuf[BUFSIZ];            /* temp for read/write */
  1145. X    register tlen;            /* targ length */
  1146. X    register puntln = FALSE;        /* punt current line? */
  1147. X    register contln = FALSE;        /* previous line ended with '\'? */
  1148. X    register blankln = 0;        /* number of blank lines seen */
  1149. X    register srchsn = FALSE;        /* search line seen? */
  1150. X
  1151. X    if ((oldfd = fopen(backupfn, "r")) == NULL)
  1152. X    err("Can't open backup copy of %s\n", makename);
  1153. X    tlen = strlen(targ);
  1154. X    while (fgets(rwbuf, BUFSIZ, oldfd) != NULL) { /* until EOF */
  1155. X    if (!srchsn) {
  1156. X        if (strncmp(searchdep, rwbuf, (sizeof searchdep) - 1) == 0) {
  1157. X        srchsn = TRUE;
  1158. X        fputs(deplin, makefd);    /* re-write this line */
  1159. X        if (!replace)
  1160. X            break;
  1161. X        continue;        /* don't print this line */
  1162. X        }
  1163. X    } else {
  1164. X        if (strcmp("\n", rwbuf) == 0) {
  1165. X        if (!puntln)
  1166. X            blankln++;
  1167. X        contln = FALSE;
  1168. X        puntln = FALSE;
  1169. X        continue;        /* don't output this blank line */
  1170. X        }
  1171. X        if (!contln) {
  1172. X        if (strncmp(targ, rwbuf, tlen) == 0)
  1173. X            puntln = TRUE;
  1174. X        else if (strcmp(&trailer[1], rwbuf) == 0)
  1175. X            puntln = TRUE;
  1176. X        }
  1177. X        if (lastlnch(rwbuf) == '\\')
  1178. X        contln = TRUE;
  1179. X        else
  1180. X        contln = FALSE;
  1181. X    }                /* if srchsn */
  1182. X    if (!puntln) {
  1183. X        srchincl(&rwbuf[0]);    /* search this line for defines */
  1184. X        if (blankln != 0) {        /* compress mult blank lines to one */
  1185. X        putc('\n', makefd);
  1186. X        blankln = 0;
  1187. X        }
  1188. X        fputs(rwbuf, makefd);    /* non targ lines */
  1189. X    }
  1190. X    }                    /* while fgets */
  1191. X    if (!srchsn)            /* deplin never found */
  1192. X    fputs(deplin, makefd);        /* so write one */
  1193. X    (void) fclose(oldfd);        /* close the .old file for gigles */
  1194. X}
  1195. X
  1196. X#define MAXCOL 78            /* output width max for makefile */
  1197. X
  1198. X/* mkdepend - name is historical, but does the "real work" */
  1199. Xvoid
  1200. Xmkdepend(infile)
  1201. Xchar *infile;
  1202. X{
  1203. X    register char *p;            /* temp pointer */
  1204. X    register char *q;            /* temp pointer */
  1205. X    register char *r;            /* temp pointer */
  1206. X    register FILE *cppfd;        /* file desc for /lib/cpp */
  1207. X    char buf[BUFSIZ];            /* temp buff */
  1208. X    char basename[MAXNAMLEN+1];        /* just the file name */
  1209. X    register oplen;            /* length target & path */
  1210. X    register le;            /* length of current output line */
  1211. X    register char *targ;        /* target's name */
  1212. X    register i;                /* tmp for index */
  1213. X    register firstln;            /* first line of a list */
  1214. X
  1215. X    if ((p = rindex(infile, '/')) == NULL) /* past path */
  1216. X    p = infile;
  1217. X    else
  1218. X    p++;
  1219. X    if (nonlocalo && p != infile) {    /* objpath = source path */
  1220. X    for (q = objpath, r = infile; r < p;)
  1221. X        *q++ = *r++;
  1222. X    *q = '\0';            /* null terminate */
  1223. X    }
  1224. X    strcpy(basename, p);
  1225. X    if ((p = rindex(basename, '.')) != NULL)
  1226. X    *p = '\0';            /* remove trailing ".*" */
  1227. X    if (targetname != NULL)        /* set up target's name */
  1228. X    targ = targetname;
  1229. X    else
  1230. X    targ = basename;
  1231. X    if (makename == NULL) {
  1232. X    makename = "Makefile";
  1233. X    if (access(makename, F_OK) != 0)
  1234. X        makename[0] = 'm';        /* not a real check */
  1235. X    }
  1236. X    msoio(targ);            /* Make Sure Output Is Open */
  1237. X    abrvsetup();            /* create abrev table, write defs. */
  1238. X    if (access(infile, R_OK) != 0) {
  1239. X    fprintf(stderr, "%s: Can't open input file '%s', skipped.\n",
  1240. X        prgnm, infile);
  1241. X    return;
  1242. X    }
  1243. X    (void)strcpy(buf, CPP);    /* build cpp cmd line */
  1244. X#if CPP_M
  1245. X    strcat(buf, "-M ");        /* -M flag - does dependencies */
  1246. X#endif
  1247. X    if (strlen(buf) + strlen(cppflags) + strlen(infile) + 1 > BUFSIZ)
  1248. X    err("cpp command line buffer overflow");
  1249. X    (void)strcat(buf, cppflags);    /* add command flags */
  1250. X    (void)strcat(buf, infile);        /* add file name */
  1251. X    srtfree(&u);            /* init insertion sorter */
  1252. X    if (verbose)
  1253. X    fprintf(stderr, "%s: cpp line is '%s'\n", prgnm, buf);
  1254. X    if ((cppfd = nshpopen(buf, "r")) == NULL)
  1255. X    err("Can't open pipe for %s", buf);
  1256. X#if CPP_M
  1257. X     while (fgets(buf, BUFSIZ, cppfd) != NULL) {
  1258. X     if ((p = index(buf, ':')) == NULL)
  1259. X         err("cpp -M format error - colon");
  1260. X     p++;            /* pass colon */
  1261. X     if (*p++ != SPC)
  1262. X         err("cpp -M format error - space");
  1263. X     p = hincl(p);        /* skip any uglies in include path */
  1264. X     if (!alldep && strncmp("/usr/include", p, 12) == 0)
  1265. X         continue;        /* ignore /usr/include... stuff */
  1266. X     if (index(p, '\n') != NULL) /* replace newline with EOS */
  1267. X         *index(p, '\n') = '\0';
  1268. X     if ((q = srtin(&u, p, (int (*)())0)) != NULL) /* insert into list */
  1269. X         fprintf(stderr, "%s: %s - %s\n", prgnm, q, p); /* warning */
  1270. X     }
  1271. X#else
  1272. X     while (fgets(buf, BUFSIZ, cppfd) != NULL) {
  1273. X     if (buf[0] != '#')        /* must start with '#' */
  1274. X         continue;
  1275. X     if ((p = index(buf, '"')) == NULL) /* find first double quote */
  1276. X         continue;
  1277. X     p++;
  1278. X     p = hincl(p);        /* skip any uglies in include path */
  1279. X     if (index(p, '"') != NULL)    /* terminate the file name */
  1280. X         *index(p, '"') = '\0';
  1281. X     if (!alldep && strncmp("/usr/include", p, 12) == 0)
  1282. X         continue;        /* ignore /usr/include... stuff */
  1283. X     if ((q = srtin(&u, p, (int (*)())0)) != NULL) /* insert into list */
  1284. X         fprintf(stderr, "%s: %s - %s\n", prgnm, q, p); /* warning */
  1285. X     }
  1286. X#endif
  1287. X    srtgti(&u);                /* init for srtgets */
  1288. X    /* 2 for colon space */
  1289. X    oplen = strlen(objpath) + strlen(targ) + strlen(destsuffix) + 2;
  1290. X    le = MAXCOL;            /* force new line output */
  1291. X    firstln = TRUE;            /* first line of a file entry */
  1292. X    while ((p = srtgets(&u)) != NULL) { /* write out the entries */
  1293. X    if (shortincl)
  1294. X        if ((i = findabr(p)) != MXABR) /* i = found index or MXABR */
  1295. X        p += abrvlen[i] - 2;
  1296. X    if (le + strlen(p) >= MAXCOL) {
  1297. X        if (firstln) {
  1298. X        le = oplen;
  1299. X        fprintf(makefd, "\n%s%s%s: ", objpath, targ, destsuffix);
  1300. X        firstln = FALSE;
  1301. X        } else {
  1302. X        le = 8;
  1303. X        fprintf(makefd, " \\\n\t");
  1304. X        }
  1305. X    } else {
  1306. X        fputc(SPC, makefd);
  1307. X    }
  1308. X    if (shortincl && i != MXABR) {
  1309. X        fprintf(makefd, "$%c", 'A' + i);
  1310. X        p += 2;            /* right place */
  1311. X        le += 2;
  1312. X    }
  1313. X    fputs(p, makefd);
  1314. X    le += 1 + strlen(p);
  1315. X    }
  1316. X    fputc('\n', makefd);        /* end with newline */
  1317. X    nshpclose(cppfd);            /* end of that file */
  1318. X}
  1319. END_OF_FILE
  1320. if test 16381 -ne `wc -c <'maketd/maketd.c'`; then
  1321.     echo shar: \"'maketd/maketd.c'\" unpacked with wrong size!
  1322. fi
  1323. # end of 'maketd/maketd.c'
  1324. fi
  1325. echo shar: End of archive 4 \(of 4\).
  1326. cp /dev/null ark4isdone
  1327. MISSING=""
  1328. for I in 1 2 3 4 ; do
  1329.     if test ! -f ark${I}isdone ; then
  1330.     MISSING="${MISSING} ${I}"
  1331.     fi
  1332. done
  1333. if test "${MISSING}" = "" ; then
  1334.     echo You have unpacked all 4 archives.
  1335.     rm -f ark[1-9]isdone
  1336. else
  1337.     echo You still need to unpack the following archives:
  1338.     echo "        " ${MISSING}
  1339. fi
  1340. ##  End of shell archive.
  1341. exit 0
  1342.  
  1343. -- 
  1344.  
  1345. Rich $alz            "Anger is an energy"
  1346. Cronus Project, BBN Labs    rsalz@bbn.com
  1347. Moderator, comp.sources.unix    sources@uunet.uu.net
  1348.