home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume23 / awf next >
Encoding:
Internet Message Format  |  1990-09-27  |  54.2 KB

  1. Path: wuarchive!uunet!papaya.bbn.com!rsalz
  2. From: rsalz@bbn.com (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v23i027:  nroff -man/-ms clone written in (old) awk
  5. Message-ID: <2829@litchi.bbn.com>
  6. Date: 7 Sep 90 20:49:04 GMT
  7. Organization: BBN Systems and Technologies, Cambridge MA
  8. Lines: 2331
  9. Approved: rsalz@uunet.UU.NET
  10. X-Checksum-Snefru: 8f01fd90 8fe678dc 00c31377 965ef65e
  11.  
  12. Submitted-by: henry@zoo.toronto.edu
  13. Posting-number: Volume 23, Issue 27
  14. Archive-name: awf
  15.  
  16. This is awf, the Amazingly Workable Formatter -- a "nroff -man" or
  17. (subset) "nroff -ms" clone written entirely in (old) awk.
  18.  
  19. I can't believe I really wrote this.
  20. [  You're not alone in that sentiment, Henry.  --r$  ]
  21.  
  22.                                          Henry Spencer at U of Toronto Zoology
  23.                                           henry@zoo.toronto.edu   utzoo!henry
  24.  
  25. #! /bin/sh
  26. echo 'README':
  27. sed 's/^X//' >'README' <<'!'
  28. XThis is awf, the Amazingly Workable Formatter -- a "nroff -man" or
  29. X(subset) "nroff -ms" clone written entirely in (old) awk.
  30. X
  31. XIt is slow and has many restrictions, but does a decent job on most
  32. Xmanual pages and simple -ms documents, and isn't subject to AT&T's
  33. Xbrain-damaged licensing that denies many System V users any text
  34. Xformatter at all.  It is also a text formatter that is simple enough
  35. Xto be tinkered with, for people who want to experiment.
  36. X
  37. XType "make r" to run a regression test, formatting the manual page
  38. X(awf.1) and comparing it to a preformatted copy (awf.1.out).  Type
  39. X"make install" to install it.  Pathnames may need changing.
  40. X
  41. XI don't know whether awf will run on 16-bit machines.  Data requirements
  42. Xare modest, but I fear the programs are probably big enough to run awk
  43. Xout of space.
  44. X
  45. XI can't believe I really wrote this.
  46. X
  47. X                                         Henry Spencer at U of Toronto Zoology
  48. X                                          henry@zoo.toronto.edu   utzoo!henry
  49. X                        13 July 1990
  50. !
  51. echo 'COPYRIGHT':
  52. sed 's/^X//' >'COPYRIGHT' <<'!'
  53. X/*
  54. X * Copyright 1990 University of Toronto.  All rights reserved.
  55. X * Written by Henry Spencer.
  56. X * This software is not subject to any license of the American Telephone
  57. X * and Telegraph Company or of the Regents of the University of California.
  58. X *
  59. X * Permission is granted to anyone to use this software for any purpose on
  60. X * any computer system, and to alter it and redistribute it freely, subject
  61. X * to the following restrictions:
  62. X *
  63. X * 1. The author is not responsible for the consequences of use of this
  64. X *    software, no matter how awful, even if they arise from flaws in it.
  65. X *
  66. X * 2. The origin of this software must not be misrepresented, either by
  67. X *    explicit claim or by omission.  Since few users ever read sources,
  68. X *    credits must appear in the documentation.
  69. X *
  70. X * 3. Altered versions must be plainly marked as such, and must not be
  71. X *    misrepresented as being the original software.  Since few users
  72. X *    ever read sources, credits must appear in the documentation.
  73. X *
  74. X * 4. This notice may not be removed or altered.
  75. X */
  76. !
  77. echo 'Makefile':
  78. sed 's/^X//' >'Makefile' <<'!'
  79. XAWFLIB = /usr/lib/awf    # beware, awf itself knows this
  80. XBIN = /usr/bin
  81. XMAN = /usr/man/man1
  82. XCP = common dev.dumb mac.man mac.ms pass1 pass2.base pass2.man pass2.ms pass3
  83. XDTR = README COPYRIGHT Makefile awf awf.1 awf.1.out common dev.dumb mac.man \
  84. X    mac.ms pass1 pass2.base pass2.man pass2.ms pass3
  85. X# System V brain damage
  86. XSHELL = /bin/sh
  87. X
  88. Xr:    awf.1
  89. X    chmod +x awf
  90. X    AWFLIB=. awf -man awf.1 >tmp
  91. X    cmp tmp awf.1.out
  92. X    rm tmp
  93. X
  94. Xinstall:
  95. X    -if test ! -d $(AWFLIB) ; then mkdir $(AWFLIB) ; fi
  96. X    cp $(CP) $(AWFLIB)
  97. X    cp awf $(BIN)
  98. X    cp awf.1 $(MAN)
  99. X
  100. Xrr:    r testm tests.Z tests.out.Z
  101. X    AWFLIB=. awf -man testm >tmp
  102. X    cmp tmp testm.out
  103. X    rm tmp
  104. X    uncompress <tests.Z | AWFLIB=. awf -ms >tmp
  105. X    uncompress <tests.out.Z | cmp - tmp
  106. X    rm tmp
  107. X
  108. Xdtr:    $(DTR)
  109. X    makedtr $(DTR) >$@
  110. X
  111. Xtar:    $(DTR)
  112. X    tar cvf awf.tar $(DTR)
  113. X    compress -v awf.tar
  114. X
  115. Xclean:
  116. X    rm -f tmp tests tests.out dtr awf.tar awf.tar.Z j*
  117. !
  118. echo 'awf':
  119. sed 's/^X//' >'awf' <<'!'
  120. X#! /bin/sh
  121. XPATH=/bin:/usr/bin ; export PATH
  122. X# AWFLIB is where the pieces live
  123. XAWFLIB=${AWFLIB-/usr/lib/awf}
  124. X
  125. Xtmp=/tmp/awp$$            # tempfile for building pass 2
  126. Xerrs=/tmp/awe$$        # error messages (awk can't send to stderr)
  127. X
  128. Xcase "$1" in
  129. X-ms)    mac=ms    ;;
  130. X-man)    mac=man    ;;
  131. X*)    echo "$0: must specify -ms or -man" >&2
  132. X    exit 2
  133. X    ;;
  134. Xesac
  135. Xshift
  136. X
  137. Xdev="$AWFLIB/dev.$TERM"
  138. Xif test ! -r $dev
  139. Xthen
  140. X    dev="$AWFLIB/dev.dumb"
  141. Xfi
  142. X
  143. Xtrap "rm -f $tmp $errs ; exit 0" 0 1 2
  144. X
  145. X# build the full, macro-set-dependent, pass-2 awk program
  146. X(
  147. X    sed -n '1,/^#include/p' $AWFLIB/pass2.base
  148. X    cat $AWFLIB/pass2.$mac
  149. X    sed -n '/^#include/,$p' $AWFLIB/pass2.base
  150. X) >$tmp
  151. X
  152. X# do it
  153. X(
  154. X    echo ".^x $errs"
  155. X    echo ".^b"
  156. X    echo ".^# 1 <prolog>"
  157. X    cat $dev $AWFLIB/common $AWFLIB/mac.$mac
  158. X    if test " $*" = " "
  159. X    then
  160. X        echo ".^# 1 <stdin>"
  161. X        cat
  162. X    else
  163. X        for f
  164. X        do
  165. X            echo ".^# 1 $f"
  166. X            cat $f
  167. X        done
  168. X    fi
  169. X    echo ".^e"
  170. X) | awk -f $AWFLIB/pass1 | awk -f $tmp | awk -f $AWFLIB/pass3
  171. X
  172. X# error messages, if any
  173. Xif test -s $errs
  174. Xthen
  175. X    cat $errs >&2
  176. X    exit 1
  177. Xelse
  178. X    exit 0
  179. Xfi
  180. !
  181. echo 'awf.1':
  182. sed 's/^X//' >'awf.1' <<'!'
  183. X.\" Some of the stuff in this file is a bit contorted, because it's also
  184. X.\" the regression-test input.
  185. X.nr ES 5n
  186. X.de ES
  187. X.PP
  188. X.in +\\n(ESu
  189. X.nf
  190. X..
  191. X.de EE
  192. X.in -\\n(ESu
  193. X.fi
  194. X.PP
  195. X..
  196. X.de PT
  197. X.ie \\n(.$>1 .TP "\\$2"
  198. X.el .TP
  199. X.ie !'\\$1'' \\$1
  200. X.el \(bu
  201. X..
  202. X.ds Nr \fInroff\fR
  203. X.TH AWF 1 "13 July 1990"
  204. X.BY "U of Toronto"
  205. X.SH NAME
  206. Xawf \- amazingly workable (text) formatter
  207. X.SH SYNOPSIS
  208. X.B awf
  209. X.BI \-m acros
  210. X[ file ] ...
  211. X.SH DESCRIPTION
  212. X.if t .tm OOPS -- AWF THINKS IT'S TROFF!!!
  213. X.I Awf
  214. Xformats the text from the input \fIfile\fR(s)
  215. X(standard input if none)
  216. Xin an imitation of
  217. X\*(Nr's style with the \fB\-man\fR or \fB\-ms\fR macro packages.
  218. XThe
  219. X.BI \-m acro
  220. Xoption is mandatory and must be `\-man' or `\-ms'.
  221. X.PP
  222. X.I Awf
  223. Ximplements the following raw \*(Nr requests:
  224. X.LP
  225. X    .\e"    .ce    .fi    .in    .ne    .pl    .sp
  226. X    .ad    .de    .ft    .it    .nf    .po    .ta
  227. X    .bp    .ds    .ie    .ll    .nr    .ps    .ti
  228. X    .br    .el    .if    .na    .ns    .rs    .tm
  229. X.LP
  230. Xand the following in-text codes:
  231. X.ES
  232. X\e$    \e%    \e*    \ec    \ef    \en    \es
  233. X.EE
  234. Xplus the full list of \*(Nr/\c
  235. X.I troff
  236. Xspecial characters in
  237. Xthe original V7 \fItroff\fR manual.
  238. X.PP
  239. XMany restrictions are present; the behavior in general is a subset of
  240. X\*(Nr's.  Of particular note are the following:
  241. X.IP \(bu 2
  242. XPoint sizes do not exist;
  243. X.B .ps
  244. Xand
  245. X.B \es
  246. Xare ignored.
  247. X.PT
  248. XConditionals implement only numeric comparisons on
  249. X.BR \en(.$ ,
  250. Xstring com\%par\%isons between a macro parameter and a literal,
  251. Xand
  252. X.B n
  253. X(always true)
  254. Xand
  255. X.BR t
  256. X(always false).
  257. X.PT
  258. XThe implementation of strings is generally primitive.
  259. X.IP \(bu
  260. XExpressions in (e.g.)\&
  261. X.B .sp
  262. Xare fairly general, but the
  263. X.BR | ,
  264. X.BR & ,
  265. Xand
  266. X.BR :\&
  267. Xoperators do not exist, and the implementation of
  268. X.B \ew
  269. Xrequires that quote (') be used as the delimiter and
  270. Xsimply counts the characters inside (so that, e.g.,
  271. X\ew'\e(bu'
  272. Xequals 4).
  273. X.P
  274. XWhite space at the beginning of lines,
  275. Xand imbedded white space within lines, is dealt with properly.
  276. XSentence terminators at ends of lines are understood to imply
  277. Xextra space afterward in filled lines.
  278. XTabs are im\%plemented crudely and not quite correctly, although
  279. Xin most cases they work as expected.
  280. XHyphenation is done only at explicit hyphens, em-dashes, and \*(Nr
  281. Xdiscretionary hyphens.
  282. X.SH "MAN MACROS"
  283. XThe
  284. X.B \-man
  285. Xmacro set implements the full V7 manual macros,
  286. Xplus a few semi-random oddballs.
  287. XThe full list is:
  288. X.ES
  289. X\&.B    .DT    .IP    .P    .RE    .SM
  290. X\&.BI    .HP    .IR    .PD    .RI    .TH
  291. X\&.BR    .I    .LP    .PP    .RS    .TP
  292. X\&.BY    .IB    .NB    .RB    .SH    .UC
  293. X.EE
  294. X.B .BY
  295. Xand
  296. X.B .NB
  297. Xeach take a single string argument (respectively, an indi\%cation of
  298. Xauthorship and a note about the status of the manual page) and arrange
  299. Xto place it in the page footer.
  300. X.SH "MS MACROS"
  301. XThe
  302. X.B \-ms
  303. Xmacro set is a substantial subset of the V7 manuscript macros.
  304. XThe implemented macros are:
  305. X.ES
  306. X\&.AB    .CD    .ID    .ND    .QP    .RS    .UL
  307. X\&.AE    .DA    .IP    .NH    .QS    .SH    .UX
  308. X\&.AI    .DE    .LD    .NL    .R    .SM
  309. X\&.AU    .DS    .LG    .PP    .RE    .TL
  310. X\&.B    .I    .LP    .QE    .RP    .TP
  311. X.EE
  312. XSize changes are recognized but ignored, as are
  313. X.B .RP
  314. Xand
  315. X.BR .ND .
  316. X.B .UL
  317. Xjust prints its argument in italics.
  318. X.BR .DS / .DE
  319. Xdoes not do a keep,
  320. Xnor do any of the other macros that normally imply keeps.
  321. X.PP
  322. XAssignments to the header/footer string variables are recognized and
  323. Ximplemented, but there is otherwise no control over header/footer
  324. Xformatting.
  325. XThe
  326. X.B DY
  327. Xstring variable is available.
  328. XThe
  329. X.BR PD ,
  330. X.BR PI ,
  331. Xand
  332. X.BR LL
  333. Xnumber registers exist and can be changed.
  334. X.SH OUTPUT
  335. XThe only output format supported by
  336. X.IR awf ,
  337. Xin its distributed form,
  338. Xis that appropriate to a dumb terminal,
  339. Xusing overprinting for italics (via underlining) and bold.
  340. XThe \*(Nr special characters are printed as some vague approximation
  341. X(it's sometimes very vague) to their correct appearance.
  342. X.PP
  343. X.IR Awf 's
  344. Xknowledge of the output device is established by a device file,
  345. Xwhich is read before the user's input.
  346. XIt is sought in
  347. X.IR awf 's
  348. Xlibrary directory, first as
  349. X.BI dev. term
  350. X(where \fIterm\fR is the value of the TERM environment variable)
  351. Xand, failing that, as
  352. X.BR dev.dumb .
  353. XThe device file
  354. Xuses special internal commands
  355. Xto set up resolution, special characters, fonts, etc.,
  356. Xand more normal \*(Nr commands to set up page length etc.
  357. X.SH FILES
  358. XAll in \fI/usr/lib/awf\fR (this can be overridden by the AWFLIB
  359. Xenvironment variable):
  360. X
  361. X.ta \w'pass2.base'u+((3n-1n)/2u)
  362. X.nf
  363. Xcommon    common device-independent initialization
  364. Xdev.*    device-specific initialization
  365. Xmac.m*    macro packages
  366. Xpass1    macro substituter
  367. Xpass2.base    central formatter
  368. Xpass2.m*    macro-package-specific bits of formatter
  369. Xpass3    line and page composer
  370. X.SH SEE ALSO
  371. Xawk(1), nroff(1), man(7), ms(7)
  372. X.SH DIAGNOSTICS
  373. X.na
  374. XUnlike
  375. X.IR nroff ,
  376. X.I awf
  377. Xcomplains whenever it sees unknown commands and macros.
  378. XAll diagnostics (these and some internal ones) appear on standard error
  379. Xat the end of the run.
  380. X.ad
  381. X.SH HISTORY
  382. XWritten at University of Toronto by Henry Spencer,
  383. Xmore or less as a supplement to the C News project.
  384. X.LP
  385. X.ce 99
  386. X\(rh None of the above really want to admit it. \(lh
  387. X.ce 0
  388. X.SH BUGS
  389. XThere are plenty, but what do you expect for a text formatter
  390. Xwritten entirely in (old) \fIawk\fR?
  391. X.PP
  392. XThe
  393. X.B \-ms
  394. Xstuff has not been checked out very thoroughly.
  395. !
  396. echo 'awf.1.out':
  397. sed 's/^X//' >'awf.1.out' <<'!'
  398. X
  399. X
  400. XAWF(1)                     Unix Programmer's Manual                     AWF(1)
  401. X
  402. X
  403. XNNNAAAMMMEEE
  404. X     awf - amazingly workable (text) formatter
  405. X
  406. XSSSYYYNNNOOOPPPSSSIIISSS
  407. X     aaawwwfff -mmm_a_c_r_o_s [ file ] ...
  408. X
  409. XDDDEEESSSCCCRRRIIIPPPTTTIIIOOONNN
  410. X     _A_w_f formats the text from the input _f_i_l_e(s) (standard input if  none)  in
  411. X     an  imitation  of _n_r_o_f_f's style with the -mmmaaannn or -mmmsss macro packages.  The
  412. X     -mmm_a_c_r_o option is mandatory and must be `-man' or `-ms'.
  413. X
  414. X     _A_w_f implements the following raw _n_r_o_f_f requests:
  415. X
  416. X          .\"  .ce  .fi  .in  .ne  .pl  .sp
  417. X          .ad  .de  .ft  .it  .nf  .po  .ta
  418. X          .bp  .ds  .ie  .ll  .nr  .ps  .ti
  419. X          .br  .el  .if  .na  .ns  .rs  .tm
  420. X
  421. X     and the following in-text codes:
  422. X
  423. X          \$   \%   \*   \c   \f   \n   \s
  424. X
  425. X     plus the full list of _n_r_o_f_f/_t_r_o_f_f special characters in the  original  V7
  426. X     _t_r_o_f_f manual.
  427. X
  428. X     Many restrictions are present; the behavior in general  is  a  subset  of
  429. X     _n_r_o_f_f's.  Of particular note are the following:
  430. X
  431. X     +o Point sizes do not exist; ...pppsss and \sss are ignored.
  432. X
  433. X     +o Conditionals implement only numeric comparisons on \nnn(((...$$$,  string  com-
  434. X       parisons  between  a macro parameter and a literal, and nnn (always true)
  435. X       and ttt (always false).
  436. X
  437. X     +o The implementation of strings is generally primitive.
  438. X
  439. X     +o Expressions in (e.g.) ...sssppp are fairly general,  but  the  |||,  &&&,  and  :::
  440. X       operators  do  not  exist,  and  the implementation of \www requires that
  441. X       quote (') be used as the delimiter and  simply  counts  the  characters
  442. X       inside (so that, e.g., \w'\(bu' equals 4).
  443. X
  444. X     White space at the beginning of lines, and imbedded  white  space  within
  445. X     lines, is dealt with properly.  Sentence terminators at ends of lines are
  446. X     understood to imply extra space afterward in filled lines.  Tabs are  im-
  447. X     plemented  crudely  and  not quite correctly, although in most cases they
  448. X     work as expected.  Hyphenation is done  only  at  explicit  hyphens,  em-
  449. X     dashes, and _n_r_o_f_f discretionary hyphens.
  450. X
  451. XMMMAAANNN MMMAAACCCRRROOOSSS
  452. X     The -mmmaaannn macro set implements the full V7 manual macros, plus a few semi-
  453. X     random oddballs.  The full list is:
  454. X
  455. X          .B   .DT  .IP  .P   .RE  .SM
  456. X          .BI  .HP  .IR  .PD  .RI  .TH
  457. X          .BR  .I   .LP  .PP  .RS  .TP
  458. X          .BY  .IB  .NB  .RB  .SH  .UC
  459. X
  460. X
  461. XU of Toronto                          13 July 1990                           1
  462. X
  463. X
  464. X
  465. X
  466. XAWF(1)                     Unix Programmer's Manual                     AWF(1)
  467. X
  468. X
  469. X     ...BBBYYY and ...NNNBBB each take a single string argument  (respectively,  an  indi-
  470. X     cation  of authorship and a note about the status of the manual page) and
  471. X     arrange to place it in the page footer.
  472. X
  473. XMMMSSS MMMAAACCCRRROOOSSS
  474. X     The -mmmsss macro set is a substantial subset of the  V7  manuscript  macros.
  475. X     The implemented macros are:
  476. X
  477. X          .AB  .CD  .ID  .ND  .QP  .RS  .UL
  478. X          .AE  .DA  .IP  .NH  .QS  .SH  .UX
  479. X          .AI  .DE  .LD  .NL  .R   .SM
  480. X          .AU  .DS  .LG  .PP  .RE  .TL
  481. X          .B   .I   .LP  .QE  .RP  .TP
  482. X
  483. X     Size changes are recognized but ignored, as are ...RRRPPP and  ...NNNDDD.   ...UUULLL  just
  484. X     prints  its  argument in italics.  ...DDDSSS/...DDDEEE does not do a keep, nor do any
  485. X     of the other macros that normally imply keeps.
  486. X
  487. X     Assignments to the header/footer  string  variables  are  recognized  and
  488. X     implemented,  but  there  is  otherwise  no  control  over  header/footer
  489. X     formatting.  The DDDYYY string variable is available.  The  PPPDDD,  PPPIII,  and  LLLLLL
  490. X     number registers exist and can be changed.
  491. X
  492. XOOOUUUTTTPPPUUUTTT
  493. X     The only output format supported by _a_w_f, in its distributed form, is that
  494. X     appropriate  to  a  dumb  terminal,  using  overprinting for italics (via
  495. X     underlining) and bold.  The _n_r_o_f_f special characters are printed as  some
  496. X     vague   approximation  (it's  sometimes  very  vague)  to  their  correct
  497. X     appearance.
  498. X
  499. X     _A_w_f's knowledge of the output device is established  by  a  device  file,
  500. X     which  is  read  before  the user's input.  It is sought in _a_w_f's library
  501. X     directory, first as dddeeevvv..._t_e_r_m  (where  _t_e_r_m  is  the  value  of  the  TERM
  502. X     environment  variable)  and,  failing that, as dddeeevvv...ddduuummmbbb.  The device file
  503. X     uses special internal commands to set up resolution, special  characters,
  504. X     fonts, etc., and more normal _n_r_o_f_f commands to set up page length etc.
  505. X
  506. XFFFIIILLLEEESSS
  507. X     All in /_u_s_r/_l_i_b/_a_w_f (this can be overridden  by  the  AWFLIB  environment
  508. X     variable):
  509. X
  510. X     common     common device-independent initialization
  511. X     dev.*      device-specific initialization
  512. X     mac.m*     macro packages
  513. X     pass1      macro substituter
  514. X     pass2.base central formatter
  515. X     pass2.m*   macro-package-specific bits of formatter
  516. X     pass3      line and page composer
  517. X
  518. XSSSEEEEEE AAALLLSSSOOO
  519. X     awk(1), nroff(1), man(7), ms(7)
  520. X
  521. X
  522. X
  523. X
  524. X
  525. X
  526. X
  527. XU of Toronto                          13 July 1990                           2
  528. X
  529. X
  530. X
  531. X
  532. XAWF(1)                     Unix Programmer's Manual                     AWF(1)
  533. X
  534. X
  535. XDDDIIIAAAGGGNNNOOOSSSTTTIIICCCSSS
  536. X     Unlike _n_r_o_f_f, _a_w_f complains whenever it sees unknown commands and macros.
  537. X     All diagnostics (these and some internal ones) appear on standard error
  538. X     at the end of the run.
  539. X
  540. XHHHIIISSSTTTOOORRRYYY
  541. X     Written at University of Toronto by Henry Spencer,  more  or  less  as  a
  542. X     supplement to the C News project.
  543. X
  544. X                     => None of the above really want to admit it. =<
  545. X
  546. XBBBUUUGGGSSS
  547. X     There are plenty, but what do you expect for  a  text  formatter  written
  548. X     entirely in (old) _a_w_k?
  549. X
  550. X     The -mmmsss stuff has not been checked out very thoroughly.
  551. X
  552. X
  553. X
  554. X
  555. X
  556. X
  557. X
  558. X
  559. X
  560. X
  561. X
  562. X
  563. X
  564. X
  565. X
  566. X
  567. X
  568. X
  569. X
  570. X
  571. X
  572. X
  573. X
  574. X
  575. X
  576. X
  577. X
  578. X
  579. X
  580. X
  581. X
  582. X
  583. X
  584. X
  585. X
  586. X
  587. X
  588. X
  589. X
  590. X
  591. X
  592. X
  593. XU of Toronto                          13 July 1990                           3
  594. X
  595. X
  596. !
  597. echo 'common':
  598. sed 's/^X//' >'common' <<'!'
  599. X.\" Common startup code, fully device-independent.
  600. X.\" --------------------------------
  601. X.fi
  602. X.ce 0
  603. X.ta +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5
  604. X.in 0
  605. X.ti 0
  606. !
  607. echo 'dev.dumb':
  608. sed 's/^X//' >'dev.dumb' <<'!'
  609. X.\" Device-dependent but not macro-set-dependent definitions.
  610. X.\" --------------------------------
  611. X.\" overall formatting initialization
  612. X.\" 12 cpi horizontal exploits 80-column terminal well (6.5i@12 = 78)
  613. X.^r cpi 12 6
  614. X.\" call margin adjustment device-dependent for sake of some unusual cases
  615. X.ad
  616. X.\" page parameters
  617. X.pl 11i
  618. X.ll 6.5i
  619. X.po 0
  620. X.\" --------------------------------
  621. X.\" fonts, and their hyphens, last font change doubled to set up \fP
  622. X.^f R
  623. X.ft R
  624. X.^c hy 1 -
  625. X.^f I
  626. X.ft I
  627. X.^c hy 1 -
  628. X.^f B
  629. X.ft B
  630. X.^c hy 1 -\b-\b-
  631. X.ft R
  632. X.ft R
  633. X.\" --------------------------------
  634. X.\" definitions of nroff special characters
  635. X.\" The character definitions here operate on the "better ugly than invisible"
  636. X.\" principle, and try to approximate the character *somehow*.  They were
  637. X.\" tuned for a Teletype 40 line printer, but should give vaguely plausible
  638. X.\" results on any overprinting ASCII device.
  639. X.\"
  640. X.\" first, things that nroff considered builtins
  641. X.^c \ 1 \\
  642. X.^c e 1 \\
  643. X.^c ' 1 '
  644. X.^c ` 1 `
  645. X.^c - 1 -
  646. X.\" some things seem to assume that \+ is like \-
  647. X.^c + 1 +
  648. X.\" we do not do backslash-space here, it can't be done with .^c, but the
  649. X.\" other forms of space we can do
  650. X.^c 0 1 " 
  651. X.^c | 0
  652. X.^c ^ 0
  653. X.^c & 0
  654. X.\"
  655. X.\" and more normal characters
  656. X.\" note, the hyphenation logic knows about em
  657. X.^c em 2 --
  658. X.\" hy is a special case, see above
  659. X.^c bu 1 +\bo
  660. X.^c sq 2 []
  661. X.^c ru 1 _
  662. X.^c 12 3 1/2
  663. X.^c 14 3 1/4
  664. X.^c 34 3 3/4
  665. X.^c de 1 '\b`
  666. X.^c dg 1 -\b!
  667. X.^c fm 1 '
  668. X.^c ct 1 /\bc
  669. X.^c rg 3 (R)
  670. X.^c co 3 (c)
  671. X.^c pl 1 +
  672. X.^c mi 1 -
  673. X.^c eq 1 =
  674. X.^c ** 1 *
  675. X.^c sc 1 j\bf
  676. X.^c aa 1 '
  677. X.^c ga 1 `
  678. X.^c ul 1 _
  679. X.^c sl 1 /
  680. X.^c *a 1 <\ba
  681. X.^c *b 1 ,\bB
  682. X.^c *g 1 ,\by
  683. X.^c *d 1 S\bo
  684. X.^c *e 1 -\bc
  685. X.^c *z 1 ,\bL
  686. X.^c *y 1 ,\bn
  687. X.^c *h 1 -\b0
  688. X.^c *i 1 ,\bi
  689. X.^c *k 1 <\bK
  690. X.^c *l 1 \\\b>
  691. X.^c *m 1 ,\bu
  692. X.^c *n 1 ,\bv
  693. X.^c *c 1 ,\b3
  694. X.^c *o 1 o
  695. X.^c *p 1 -\bn
  696. X.^c *r 1 p
  697. X.^c *s 1 -\bo
  698. X.^c ts 1 s
  699. X.^c *t 1 ~\bt
  700. X.^c *u 1 u
  701. X.^c *f 1 /\bo
  702. X.^c *x 1 /\b\\
  703. X.^c *q 1 |\bu
  704. X.^c *w 1 u\bw
  705. X.^c *G 2 ~\b|~
  706. X.^c *D 2 _\b/_\b\\
  707. X.^c *H 1 -\bO
  708. X.^c *L 2 /\\
  709. X.^c *C 1 _\b-\b~
  710. X.^c *P 2 ~\b|~\b|
  711. X.^c *S 1 ~\b_\b>
  712. X.^c *U 1 Y
  713. X.^c *F 1 |\bO
  714. X.^c *Q 1 |\bU
  715. X.^c *W 2 _\b(_\b)
  716. X.^c sr 2 \\/
  717. X.^c rn 1 ~
  718. X.^c >= 1 _\b>
  719. X.^c <= 1 _\b<
  720. X.^c == 1 _\b=
  721. X.^c ~= 1 ~\b=
  722. X.^c ap 1 ~
  723. X.^c != 1 /\b=
  724. X.^c -> 2 ->
  725. X.^c <- 2 <-
  726. X.^c ua 1 |\b^
  727. X.^c da 1 |\bv
  728. X.^c mu 1 x
  729. X.^c di 1 -\b:
  730. X.^c +- 1 _\b+
  731. X.^c cu 1 U
  732. X.^c ca 3 (^)
  733. X.^c sb 2 (_\b~
  734. X.^c sp 2 _\b~)
  735. X.^c ib 2 (~\b_\b=
  736. X.^c ip 2 ~\b_\b=)
  737. X.^c if 2 oo
  738. X.^c pd 1 3\bo
  739. X.^c gr 1 ~\bV
  740. X.^c no 1 -
  741. X.^c is 1 '\b,\bI
  742. X.^c pt 2 oc
  743. X.^c es 1 /\bO
  744. X.^c mo 1 -\bC
  745. X.^c br 1 |
  746. X.^c dd 1 I\b|
  747. X.^c rh 1 =\b>
  748. X.^c lh 1 =\b<
  749. X.^c bs 4 (:-)
  750. X.^c or 1 |
  751. X.^c ci 1 O
  752. X.^c lt 1 ~\b(
  753. X.^c lb 1 _\b(
  754. X.^c rt 1 ~\b)
  755. X.^c rb 1 _\b)
  756. X.^c lk 1 -\b(
  757. X.^c rk 1 -\b)
  758. X.^c bv 1 |
  759. X.^c lf 1 _\b[
  760. X.^c rf 1 _\b]
  761. X.^c lc 1 ~\b[
  762. X.^c rc 1 ~\b]
  763. !
  764. echo 'mac.man':
  765. sed 's/^X//' >'mac.man' <<'!'
  766. X.\"-----------------
  767. X.de TH
  768. X.ds LH "\\$1(\\$2)
  769. X.ds CH "Unix Programmer's Manual
  770. X.ds RH "\\$1(\\$2)
  771. X.ds LF "
  772. X.ds CF "\\$3
  773. X.ds RF "%
  774. X..
  775. X.\"-----------------
  776. X.de NB
  777. X.ds nb "\\$1
  778. X.lF
  779. X..
  780. X.\"-----------------
  781. X.de BY
  782. X.ds by "\\$1
  783. X.lF
  784. X..
  785. X.\"-----------------
  786. X.de UC
  787. X.BY "\\$1BSD"
  788. X..
  789. X.\"-----------------
  790. X.\" common initialization for headers and paragraphs:  .In need
  791. X.de In
  792. X.ne \\$1
  793. X.sp \\n(PDu
  794. X.fi
  795. X.in \\n(inu
  796. X.ti 0
  797. X.it
  798. X.ft R
  799. X.ns
  800. X..
  801. X.\"-----------------
  802. X.de SH
  803. X.In 6
  804. X.in 0
  805. X.ft B
  806. X\&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
  807. X.ft R
  808. X.nr in 5n
  809. X.in \\n(inu
  810. X..
  811. X.\"-----------------
  812. X.de LP
  813. X.In 4
  814. X..
  815. X.\"-----------------
  816. X.de PP
  817. X.LP
  818. X..
  819. X.\"-----------------
  820. X.de P
  821. X.LP
  822. X..
  823. X.\"-----------------
  824. X.de HP
  825. X.In 4
  826. X.ti 0-\\n(tpu
  827. X..
  828. X.\"-----------------
  829. X.de TP
  830. X.In 4
  831. X.if \\n(.$>0 .nr tp \\$1n
  832. X.in \\n(inu+\\n(tpu
  833. X.ti 0-\\n(tpu
  834. X.it 1 tP
  835. X..
  836. X.\"-----------------
  837. X.de IP
  838. X.ie \\n(.$>1 .TP "\\$2"
  839. X.el .TP
  840. X\&\\$1
  841. X..
  842. X.\"-----------------
  843. X.de I
  844. X.ft I
  845. X.it 1 fP
  846. X.if \\n(.$>0 \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
  847. X..
  848. X.\"-----------------
  849. X.de B
  850. X.ft B
  851. X.it 1 fP
  852. X.if \\n(.$>0 \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
  853. X..
  854. X.\"-----------------
  855. X.de IR
  856. X\&\\fI\\$1\\fR\\$2\\fI\\$3\\fR\\$4\\fI\\$5\\fR\\$6\\fI\\$7\\fR\\$8\\fI\\$9\\fR
  857. X..
  858. X.\"-----------------
  859. X.de RI
  860. X\&\\$1\\fI\\$2\\fR\\$3\\fI\\$4\\fR\\$5\\fI\\$6\\fR\\$7\\fI\\$8\\fR\\$9
  861. X..
  862. X.\"-----------------
  863. X.de BR
  864. X\&\\fB\\$1\\fR\\$2\\fB\\$3\\fR\\$4\\fB\\$5\\fR\\$6\\fB\\$7\\fR\\$8\\fB\\$9\\fR
  865. X..
  866. X.\"-----------------
  867. X.de RB
  868. X\&\\$1\\fB\\$2\\fR\\$3\\fB\\$4\\fR\\$5\\fB\\$6\\fR\\$7\\fB\\$8\\fR\\$9
  869. X..
  870. X.\"-----------------
  871. X.de BI
  872. X\&\\fB\\$1\\fI\\$2\\fB\\$3\\fI\\$4\\fB\\$5\\fI\\$6\\fB\\$7\\fI\\$8\\fB\\$9\\fR
  873. X..
  874. X.\"-----------------
  875. X.de IB
  876. X\&\\fI\\$1\\fB\\$2\\fI\\$3\\fB\\$4\\fI\\$5\\fB\\$6\\fI\\$7\\fB\\$8\\fI\\$9\\fR
  877. X..
  878. X.\"-----------------
  879. X.de SM
  880. X.\" no-op
  881. X.if \\n(.$>0 \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
  882. X..
  883. X.\"-----------------
  884. X.de DT
  885. X.ta +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5
  886. X..
  887. X.\"-----------------
  888. X.de RS
  889. X.in +5n
  890. X..
  891. X.\"-----------------
  892. X.de RE
  893. X.in -5n
  894. X..
  895. X.\"-----------------
  896. X.de PD
  897. X.ie \\n(.$=0 .nr PD 0.3v
  898. X.el .nr PD \\$1n
  899. X..
  900. X.\"-----------------
  901. X.\" misc. initialization
  902. X.nr tp 5n
  903. X.PD
  904. X.ds R \(rg
  905. X.ds S "
  906. X.ds Tm (TM)
  907. !
  908. echo 'mac.ms':
  909. sed 's/^X//' >'mac.ms' <<'!'
  910. X.\"-----------------
  911. X.de R
  912. X.ie \\n(.$=0 .ft R
  913. X.el \\fR\\$1\\fP\\$2
  914. X..
  915. X.\"-----------------
  916. X.de I
  917. X.ie \\n(.$=0 .ft I
  918. X.el \\fI\\$1\\fP\\$2
  919. X..
  920. X.\"-----------------
  921. X.de B
  922. X.ie \\n(.$=0 .ft B
  923. X.el \\fB\\$1\\fP\\$2
  924. X..
  925. X.\"-----------------
  926. X.de UX
  927. X.\" old-fashioned capitalization -- I've never gotten used to the new one
  928. X\\$2Unix\\$1
  929. X..
  930. X.\"-----------------
  931. X.de DA
  932. X.ds DY "\\$1 \\$2 \\$3
  933. X.\" keep trailing spaces out of CF
  934. X.if \\n(.$=1 .ds CF "\\$1
  935. X.if \\n(.$=2 .ds CF "\\$1 \\$2
  936. X.if \\n(.$>2 .ds CF "\\$1 \\$2 \\$3
  937. X..
  938. X.\"-----------------
  939. X.de ND
  940. X.\" it's our default, ignore it
  941. X..
  942. X.\"-----------------
  943. X.de TL
  944. X.rs
  945. X.sp 5
  946. X.ft B
  947. X.ce 9999
  948. X..
  949. X.\"-----------------
  950. X.de AU
  951. X.sp 2
  952. X.ft R
  953. X..
  954. X.\"-----------------
  955. X.de AI
  956. X.sp
  957. X.ft R
  958. X..
  959. X.\"-----------------
  960. X.de AB
  961. X.sp 2
  962. X.ce 0
  963. X.ll -7n
  964. X.in +7n
  965. X..
  966. X.\"-----------------
  967. X.de AE
  968. X.sp
  969. X.ll
  970. X.in
  971. X..
  972. X.\"-----------------
  973. X.\" common initialization for headers and paragraphs:  .In need extraspace
  974. X.de In
  975. X.ne \\$1
  976. X.sp \\n(Tsu
  977. X.nr Ts 0
  978. X.ie \\n(.$>1 .nr iN \\$2v
  979. X.el .nr iN 0
  980. X.sp \\n(PDu+\\n(iNu
  981. X.ce 0
  982. X.ft R
  983. X.in \\n(inu
  984. X.ll \\n(LLu
  985. X.ns
  986. X.fi
  987. X.ti 0
  988. X..
  989. X.\"-----------------
  990. X.de SH
  991. X.nr in 0
  992. X.In 6 1
  993. X.ft B
  994. X..
  995. X.\"-----------------
  996. X.de NH
  997. X.nr in 0
  998. X.In 6 1
  999. X.ft B
  1000. X.\" punt to awk code to get the header numbering right
  1001. X.nH \\$1
  1002. X.\" and pick up the result
  1003. X\&\\*(Nh
  1004. X..
  1005. X.\"-----------------
  1006. X.de LP
  1007. X.In 4
  1008. X..
  1009. X.\"-----------------
  1010. X.de PP
  1011. X.In 4
  1012. X.ti \\n(PIu
  1013. X..
  1014. X.\"-----------------
  1015. X.de TP
  1016. X.In 4
  1017. X.if \\n(.$>0 .nr tp \\$1n
  1018. X.in \\n(inu+\\n(tpu
  1019. X.ti 0-\\n(tpu
  1020. X.it 1 tP
  1021. X..
  1022. X.\"-----------------
  1023. X.de IP
  1024. X.ie \\n(.$>1 .TP "\\$2"
  1025. X.el .TP
  1026. X\&\\$1
  1027. X..
  1028. X.\"-----------------
  1029. X.de QP
  1030. X.In 4
  1031. X.in +5n
  1032. X.ll -5n
  1033. X..
  1034. X.\"-----------------
  1035. X.de QS
  1036. X.nr in +5n
  1037. X.nr LL -5n
  1038. X.In 4
  1039. X..
  1040. X.\"-----------------
  1041. X.de QE
  1042. X.nr in -5n
  1043. X.nr LL +5n
  1044. X.In 4
  1045. X..
  1046. X.\"-----------------
  1047. X.de DS
  1048. X.In 5
  1049. X.if '\\$1'C' .ce 9999
  1050. X.if '\\$1'' .in +5n
  1051. X.nf
  1052. X..
  1053. X.\"-----------------
  1054. X.de CD
  1055. X.In 5
  1056. X.ce 9999
  1057. X.nf
  1058. X..
  1059. X.\"-----------------
  1060. X.de LD
  1061. X.In 5
  1062. X.nf
  1063. X..
  1064. X.\"-----------------
  1065. X.de ID
  1066. X.In 5
  1067. X.in +5n
  1068. X.nf
  1069. X..
  1070. X.\"-----------------
  1071. X.de DE
  1072. X.In 3
  1073. X..
  1074. X.\"-----------------
  1075. X.de RS
  1076. X.nr in +5n
  1077. X.in \\n(inu
  1078. X..
  1079. X.\"-----------------
  1080. X.de RE
  1081. X.nr in -5n
  1082. X.in \\n(inu
  1083. X..
  1084. X.\"-----------------
  1085. X.de UL
  1086. X\&\\fI$1\\fP
  1087. X..
  1088. X.\"-----------------
  1089. X.de RP
  1090. X..
  1091. X.\"-----------------
  1092. X.de LG
  1093. X..
  1094. X.\"-----------------
  1095. X.de SM
  1096. X..
  1097. X.\"-----------------
  1098. X.de NL
  1099. X..
  1100. X.\"-----------------
  1101. X.\" the -ms accent strings
  1102. X.ds ' "'\b
  1103. X.ds ` "`\b
  1104. X.ds : ":\b
  1105. X.ds ^ "^\b
  1106. X.ds ~ "~\b
  1107. X.ds C "v\b
  1108. X.ds , ",\b
  1109. X.\" post-title spacing
  1110. X.nr Ts 4v
  1111. X.\" and parameter setup
  1112. X.nr LL 6i
  1113. X.ll \n(LLu
  1114. X.nr PD 0.3v
  1115. X.nr PI 5n
  1116. !
  1117. echo 'pass1':
  1118. sed 's/^X//' >'pass1' <<'!'
  1119. X# first pass:  macro expansion and .if
  1120. X# We support macros, conditionals (of three quite limited forms), and macro
  1121. X# argument substitution.
  1122. XBEGIN {
  1123. X    curmacro = ""
  1124. X    macros[""] = 0        # just to make it an array
  1125. X    macrolen[""] = 0    # just to make it an array
  1126. X    macrotext[0] = ""    # just to make it an array
  1127. X    args[""] = ""        # just to make it an array
  1128. X    ntext = 1        # first slot in macrotext; cannot be 0
  1129. X    nroffset = 0        # offset between NR and "real" line numbers
  1130. X    inname = "?"        # input filename
  1131. X    sp = 0            # stack "pointer" (number of stacked macros)
  1132. X    maxsp = 25        # limit on nesting depth
  1133. X    macrostack[sp] = ""    # to make it an array
  1134. X    nleftstack[sp] = ""    # to make it an array
  1135. X    ptrstack[sp] = ""    # to make it an array
  1136. X    nargstack[sp] = ""    # to make it an array
  1137. X    argstack[sp] = ""    # to make it an array
  1138. X    condstack[sp] = ""    # to make it an array
  1139. X}
  1140. X/^\.\^#/ {            # filename and line no of next line: .^# no fn
  1141. X    nroffset = (NR+1) - $2
  1142. X    inname = $3
  1143. X    print
  1144. X    next
  1145. X}
  1146. X/^\.de/ {            # macro start
  1147. X    curmacro = "." $2
  1148. X    macros[curmacro] = ntext
  1149. X    macrostart = ntext
  1150. X    next
  1151. X}
  1152. Xcurmacro != "" && $0 !~ /^\.\.$/ {    # macro text - \\ becomes \
  1153. X    if ($0 !~ /\\/)        # quick case, no backslashes
  1154. X        line = $0
  1155. X    else {
  1156. X        line = ""
  1157. X        for (n = 1; n <= length; n++) {
  1158. X            if (substr($0, n, 2) == "\\\\")
  1159. X                n++
  1160. X            line = line substr($0, n, 1)
  1161. X        }
  1162. X    }
  1163. X    macrotext[ntext++] = line
  1164. X    next
  1165. X}
  1166. Xcurmacro != "" && $0 ~ /^\.\.$/ {    # macro end
  1167. X    macrolen[curmacro] = ntext - macrostart
  1168. X    curmacro = ""
  1169. X    print ".^#", NR - nroffset + 1, inname
  1170. X    next
  1171. X}
  1172. X$0 ~ /^\./ && ( macros[$1] != 0 || $0 ~ /^\.(i[ef]|el)/ ) {
  1173. X    # something that needs attention
  1174. X    print ".^=", NR - nroffset, inname
  1175. X    line = $0
  1176. X    nleft = 0
  1177. X    macro = "<none>"
  1178. X    nargs = 0
  1179. X
  1180. X    while (line != "") {
  1181. X        # conditionals; note that 1-n is !n (awk doesn't have !)
  1182. X        invert = 0
  1183. X        if (line ~ /^\.i[ef] !/)
  1184. X            invert = 1
  1185. X        prevcond = cond
  1186. X        cond = 0
  1187. X        if (line !~ /^\.(i[ef]|el)/) {        # not conditional
  1188. X            cond = 1
  1189. X            iflen = 0
  1190. X        } else if (line ~ /^\.i[ef] !?\\n\(\.\$[<=>][0-9] /) {
  1191. X            # arithmetic comparison on arg count
  1192. X            iflen = length(".if .n(.$=x ") + invert
  1193. X            n = substr(line, iflen-1, 1) + 0
  1194. X            op = substr(line, iflen-2, 1)
  1195. X            if (op == "=" && nargs == n)
  1196. X                cond = 1
  1197. X            else if (op == "<" && nargs < n)
  1198. X                cond = 1
  1199. X            else if (op == ">" && nargs > n)
  1200. X                cond = 1
  1201. X        } else if (line ~ /^\.i[ef] !?'\\\$[0-9]'[^']*' /) {
  1202. X            # string equality on argument
  1203. X            iflen = length(".if '.$n'") + invert
  1204. X            n = substr(line, iflen-1, 1)+0
  1205. X            if (n <= nargs)
  1206. X                s1 = args[n]
  1207. X            else
  1208. X                s1 = ""
  1209. X            i = index(substr(line, iflen+1), "'")
  1210. X            s2 = substr(line, iflen+1, i-1)
  1211. X            iflen += i+1
  1212. X            if (s1 == s2)
  1213. X                cond = 1
  1214. X        } else if (line ~ /^\.i[ef] !?[nt] /) {
  1215. X            # nroff vs troff
  1216. X            iflen = length(".if n ") + invert
  1217. X            if (substr(line, iflen-1, 1) == "n")
  1218. X                cond = 1
  1219. X        } else if (line ~ /^\.el /) {
  1220. X            cond = 1 - prevcond
  1221. X            iflen = length(".el ")
  1222. X        } else {
  1223. X            line = ".tm unknown .if/.ie form: " line
  1224. X            cond = 1
  1225. X            iflen = 0
  1226. X        }
  1227. X        if (invert)
  1228. X            cond = 1 - cond
  1229. X        if (cond && iflen > 0)        # trim true conditional off
  1230. X            line = substr(line, iflen+1)
  1231. X
  1232. X        # do argument substitution, if necessary
  1233. X        if (cond && line ~ /\\\$/) {
  1234. X            orig = line
  1235. X            line = ""
  1236. X            for (pos = index(orig, "\\$"); pos > 0; \
  1237. X                        pos = index(orig, "\\$")) {
  1238. X                if (pos > 1)
  1239. X                    line = line substr(orig, 1, pos-1)
  1240. X                c = substr(orig, pos+2, 1)
  1241. X                if (c ~ /[0-9]/ && c+0 <= nargs)
  1242. X                    line = line args[c+0]
  1243. X                orig = substr(orig, pos+3)
  1244. X            }
  1245. X            line = line orig    # the remnant
  1246. X        }
  1247. X
  1248. X        # is it an nroff command?
  1249. X        if (cond && line ~ /^\./) {
  1250. X            cmd = substr(line, 1, 3)
  1251. X            while (cmd ~ / $/)
  1252. X                cmd = substr(cmd, 1, length(cmd)-1)
  1253. X        } else
  1254. X            cmd = ""
  1255. X
  1256. X        # deal with it
  1257. X        if (!cond)
  1258. X            nop = 0        # nothing
  1259. X        else if (cmd == "" || macros[cmd] == 0)
  1260. X            print line    # not a nested macro
  1261. X        else if (sp >= maxsp)
  1262. X            print ".tm macros nested too deeply (" sp " levels)"
  1263. X        else {            # nesting
  1264. X            # stack old one
  1265. X            sp++
  1266. X            nleftstack[sp] = nleft
  1267. X            ptrstack[sp] = ptr
  1268. X            macrostack[sp] = macro
  1269. X            nargstack[sp] = nargs
  1270. X            condstack[sp] = cond
  1271. X            for (i = 1; i <= nargs; i++)
  1272. X                argstack[sp ":" i] = args[i]
  1273. X
  1274. X            # start new one, mostly pulling arguments apart
  1275. X            macro = cmd
  1276. X            nleft = macrolen[macro]
  1277. X            ptr = macros[macro]
  1278. X            cond = 0
  1279. X            argno = 1
  1280. X            pos = length(macro) + 1
  1281. X            for (;;) {
  1282. X                while (substr(line, pos, 1) ~ /[ \t]/)
  1283. X                    pos++
  1284. X                if (pos > length(line))
  1285. X                    break        # NOTE BREAK OUT
  1286. X                arg = ""
  1287. X                if (substr(line, pos, 1) == "\"") {
  1288. X                    pos++
  1289. X                    while (substr(line, pos, 1) ~ /[^"]/) {
  1290. X                        arg = arg substr(line, pos, 1)
  1291. X                        pos++
  1292. X                    }
  1293. X                    pos++
  1294. X                } else
  1295. X                    while (substr(line, pos, 1) ~ /[^ \t]/) {
  1296. X                        arg = arg substr(line, pos, 1)
  1297. X                        pos++
  1298. X                    }
  1299. X                args[argno++] = arg
  1300. X            }
  1301. X            nargs = argno - 1
  1302. X        }
  1303. X
  1304. X        # clean up any completed macros
  1305. X        while (nleft <= 0 && sp > 0) {
  1306. X            nleft = nleftstack[sp]
  1307. X            ptr = ptrstack[sp]
  1308. X            macro = macrostack[sp]
  1309. X            nargs = nargstack[sp]
  1310. X            cond = condstack[sp]
  1311. X            for (i = 1; i <= nargs; i++)
  1312. X                args[i] = argstack[sp ":" i]
  1313. X            sp--
  1314. X        }
  1315. X
  1316. X        # finally, get next line
  1317. X        if (nleft > 0) {
  1318. X            line = macrotext[ptr++]
  1319. X            nleft--
  1320. X        } else
  1321. X            line = ""    # signal loop to terminate
  1322. X    }
  1323. X
  1324. X    print ".^#", NR - nroffset + 1, inname
  1325. X    next
  1326. X}
  1327. X{
  1328. X    # it's ordinary
  1329. X    print
  1330. X}
  1331. !
  1332. echo 'pass2.base':
  1333. sed 's/^X//' >'pass2.base' <<'!'
  1334. X# second pass:  interpretation of directives
  1335. X# A macro-set-specific portion gets interpolated into this at the "#include"
  1336. X# line.  As a minimum, it must deal with .^b and .^e and with any input traps.
  1337. XBEGIN {
  1338. X    # stuff for output to third pass
  1339. X    nobreak = -1
  1340. X    dobreak = -2
  1341. X    message = -3
  1342. X    OFS = "\t"
  1343. X
  1344. X    # special-character table; this one character needs to be hardcoded
  1345. X    chars[" "] = " " ; charwidths[" "] = 1
  1346. X
  1347. X    debug["e"] = 0        # just to make it an array
  1348. X    strings["a"] = ""    # just to make it an array
  1349. X    numbers["a"] = 0    # just to make it an array
  1350. X    hyphens["a"] = ""    # just to make it an array
  1351. X    hyphenwidths["a"] = ""    # just to make it an array
  1352. X
  1353. X    # stuff for expression decoding
  1354. X    signfactor["+"] = 1
  1355. X    signfactor["-"] = -1
  1356. X    scale["i"] = 240
  1357. X    scale["c"] = 240*50/127
  1358. X    scale["P"] = 240/6
  1359. X    # we get m, n, and v when we see .^r
  1360. X    scale["p"] = 240/72
  1361. X    scale["u"] = 1
  1362. X
  1363. X    # stuff for basic parameters that just get passed to third pass
  1364. X    parms["in"] = 0        # just to make it an array
  1365. X    prevparms["in"] = 0    # just to make it an array
  1366. X    setcmd["ll"] = "linelen"
  1367. X    setcmd["in"] = "indent"
  1368. X    setcmd["ti"] = "tempindent"
  1369. X    setcmd["po"] = "pageoffset"
  1370. X    setcmd["pl"] = "pagelen"
  1371. X
  1372. X    # did last word end with \c ?  (in which case, it's still in "word")
  1373. X    backc = 0
  1374. X
  1375. X    # stuff for error reporting
  1376. X    il = 0            # input line number
  1377. X    lockil = 0        # il is locked, we're inside a macro
  1378. X    inname = "?"        # input filename
  1379. X    msg = message "\t"    # later picks up filename etc.
  1380. X
  1381. X    # current input trap
  1382. X    afternext = ""
  1383. X}
  1384. X{
  1385. X    if (!lockil)
  1386. X        il++
  1387. X    msg = message "\t" inname "," il ": "
  1388. X    # fallthrough
  1389. X}
  1390. X/^[ \t]*$/ {            # empty line
  1391. X    print dobreak, "space"
  1392. X    next
  1393. X}
  1394. X/^[ \t]/ {            # line starting with white space
  1395. X    print dobreak, "flush"
  1396. X    print 0, ""        # empty word
  1397. X    # fallthrough
  1398. X}
  1399. X/^[^.]/ {            # text
  1400. X    # dispose of the easy case
  1401. X    if (font == "R" && $0 !~ /\\|\t|-|  / && !backc && afternext == "") {
  1402. X        for (i = 1; i <= NF; i++)
  1403. X            print length($i), $i
  1404. X        if ($0 ~ /[.!?:][\])'"*]*$/)
  1405. X            print nobreak, "gap", 2
  1406. X        if (centering > 0) {
  1407. X            print dobreak, "center"
  1408. X            centering--
  1409. X        } else if (!fill)
  1410. X            print dobreak, "flush"
  1411. X        next
  1412. X    }
  1413. X
  1414. X    # the hard case, needs a character-by-character scan
  1415. X    s = $0 " "        # the space flushes the last word
  1416. X    n = 1            # current position in s
  1417. X    inword = 0        # have we been processing a word?
  1418. X    period = ""        # "." if this word ended a sentence
  1419. X    nsp = 0            # count of spaces seen so far
  1420. X    tabpos = 0        # which tab position was used last
  1421. X    while (n <= length(s)) {
  1422. X        c = substr(s, n, 1)
  1423. X
  1424. X        # handle state transitions
  1425. X        if (c == " " || c == "\t") {
  1426. X            if (inword) {        # ends word
  1427. X                if (!backc) {
  1428. X                    print wordlen, word
  1429. X                    if (usedhyphen)
  1430. X                        print nobreak, "nohyphen"
  1431. X                }
  1432. X                inword = 0
  1433. X                nsp = 0
  1434. X            }
  1435. X        } else {
  1436. X            if (!inword) {        # begins word
  1437. X                if (!backc) {
  1438. X                    word = ""
  1439. X                    wordlen = 0
  1440. X                    usedhyphen = 0
  1441. X                }
  1442. X                backc = 0
  1443. X                inword = 1
  1444. X                if (nsp > 1)
  1445. X                    print nobreak, "gap", nsp
  1446. X            }
  1447. X        }
  1448. X
  1449. X        # deal with the character
  1450. X        if (c == " ") {
  1451. X            nsp++
  1452. X            if (n != length(s))    # not the trailing flusher
  1453. X                period = ""
  1454. X        } else if (c == "\t") {
  1455. X            # not really right, should be based on input position
  1456. X            # also, one space following tab gets ignored
  1457. X            tabpos++
  1458. X            if (tabpos <= ntabs)
  1459. X                print nobreak, "tabto", tabs[tabpos]
  1460. X            nsp = 0
  1461. X            period = ""
  1462. X        } else if (c == "-" && wordlen > 0) {
  1463. X            # hyphen within word
  1464. X            print wordlen, word, hyphenwidths[font]
  1465. X            print nobreak, "userhyphen", hyphens[font], hyphenwidths[font]
  1466. X            word = ""
  1467. X            wordlen = 0
  1468. X            period = ""
  1469. X            usedhyphen = 1
  1470. X        } else if (c != "\\") {
  1471. X            # ordinary character
  1472. X            if (font == "B")
  1473. X                word = word c "\b" c "\b" c
  1474. X            else if (font == "I" && c ~ /[a-zA-Z0-9]/)
  1475. X                word = word "_\b" c
  1476. X            else
  1477. X                word = word c
  1478. X            wordlen++
  1479. X            if (c ~ /[.!?:]/)
  1480. X                period = "."
  1481. X            else if (c !~ /[\])'"*]/)
  1482. X                period = ""
  1483. X        } else {            # backslash
  1484. X            n++
  1485. X            c = substr(s, n, 1)
  1486. X            if (c == "f") {
  1487. X                # font change
  1488. X                n++
  1489. X                code = substr(s, n, 1)
  1490. X                if (code == "(") {
  1491. X                    n++
  1492. X                    code = substr(s, n, 2)
  1493. X                    n++
  1494. X                }
  1495. X                if (code == "P")
  1496. X                    font = prevfont
  1497. X                else if (fontok[code] == "")
  1498. X                    print msg "unknown font `" code "'"
  1499. X                else {
  1500. X                    prevfont = font
  1501. X                    font = code
  1502. X                }
  1503. X            } else if (c == "n") {
  1504. X                # number-register value
  1505. X                n++
  1506. X                code = substr(s, n, 1)
  1507. X                if (code == "(") {
  1508. X                    n++
  1509. X                    code = substr(s, n, 2)
  1510. X                    n++
  1511. X                }
  1512. X                s = substr(s, 1, n) numbers[code] substr(s, n+1)
  1513. X            } else if (c == "s") {
  1514. X                # size change
  1515. X                n++
  1516. X                if (substr(s, n, 1) ~ /[0-9]/)
  1517. X                    n++
  1518. X                # just ignore it
  1519. X            } else if (c == "c")
  1520. X                # word continuation
  1521. X                backc = 1
  1522. X            else if (c == "*") {
  1523. X                # string-variable value
  1524. X                n++
  1525. X                code = substr(s, n, 1)
  1526. X                if (code == "(") {
  1527. X                    n++
  1528. X                    code = substr(s, n, 2)
  1529. X                    n++
  1530. X                }
  1531. X                s = substr(s, 1, n) strings[code] substr(s, n+1)
  1532. X            } else if (c == "%") {
  1533. X                # discretionary hyphen
  1534. X                if (wordlen > 0) {
  1535. X                    print wordlen, word, hyphenwidths[font]
  1536. X                    print nobreak, "hyphen", hyphens[font], hyphenwidths[font]
  1537. X                    word = ""
  1538. X                    wordlen = 0
  1539. X                    usedhyphen = 1
  1540. X                }
  1541. X            } else if (c == "(" && substr(s, n+1, 2) == "em" && \
  1542. X                            chars["em"] != "") {
  1543. X                # em-dash, special case due to hyphenation
  1544. X                n += 2
  1545. X                emw = charwidths["em"]
  1546. X                print wordlen, word, emw
  1547. X                print nobreak, "userhyphen", chars["em"], emw
  1548. X                word = ""
  1549. X                wordlen = 0
  1550. X                period = ""
  1551. X                usedhyphen = 1
  1552. X            } else {
  1553. X                # special-character name
  1554. X                code = c
  1555. X                if (code == "(") {
  1556. X                    n++
  1557. X                    code = substr(s, n, 2)
  1558. X                    n++
  1559. X                }
  1560. X                word = word chars[code]
  1561. X                wordlen += charwidths[code]
  1562. X                period = ""
  1563. X            }
  1564. X        }
  1565. X
  1566. X        # on to the next character, at last
  1567. X        n++
  1568. X    }
  1569. X
  1570. X    # end-of-line processing
  1571. X    if (!backc) {
  1572. X        if (period == ".")
  1573. X            print nobreak, "gap", 2
  1574. X        if (centering > 0) {
  1575. X            print dobreak, "center"
  1576. X            centering--
  1577. X        } else if (!fill)
  1578. X            print dobreak, "flush"
  1579. X    }
  1580. X
  1581. X    # if no input trap, we're done
  1582. X    if (afternext == "")
  1583. X        next
  1584. X
  1585. X    # if there is an input trap, fall into the macro-dependent section
  1586. X}
  1587. X#
  1588. X#
  1589. X#
  1590. X# at this point we plug in the macro-specific stuff, keyed on the next line
  1591. X#include            note that this is an awk comment
  1592. X#
  1593. X#
  1594. X#
  1595. X/^\.it/ {            # plant an input trap, sort of
  1596. X    if (NF > 1 && $2 != 1)
  1597. X        print msg ".it first argument must be 1"
  1598. X    if (NF > 2)
  1599. X        afternext = afternext "," $3
  1600. X    else
  1601. X        afternext = ""
  1602. X    next
  1603. X}
  1604. X/^\.\^r cpi / {            # set resolutions, in cpi:  .^r cpi hor vert
  1605. X    scale["m"] = 240/$3
  1606. X    scale["n"] = 240/$3
  1607. X    scale["v"] = 240/$4
  1608. X    next
  1609. X}
  1610. X/^\.(ta|ll|in|ti|po|ne|sp|pl|nr)/ {    # expression processing
  1611. X    # sort out default scale factor
  1612. X    if ($1 ~ /^\.(ne|sp|pl)/)
  1613. X        exprscale = "v"
  1614. X    else if ($1 ~ /^\.(nr)/)
  1615. X        exprscale = "u"
  1616. X    else
  1617. X        exprscale = "n"
  1618. X
  1619. X    # which argument should we start with?
  1620. X    offset = length($1) + 1
  1621. X    if ($1 == ".nr")
  1622. X        offset += length($2) + 1
  1623. X
  1624. X    # beginning of debugging message
  1625. X    if (debug["e"])
  1626. X        printf "%s ", msg substr($0, 1, offset)
  1627. X
  1628. X    # do the expressions
  1629. X    s = substr($0, offset+1)
  1630. X    n = 1
  1631. X    while (s != "") {
  1632. X        while (s ~ /^[ \t]/)
  1633. X            s = substr(s, 2)
  1634. X
  1635. X        # an initial sign is magic
  1636. X        ssign = ""
  1637. X        if (s ~ /^[+-]/) {
  1638. X            ssign = substr(s, 1, 1)
  1639. X            s = substr(s, 2)
  1640. X        }
  1641. X        s = "+" s    # this is an un-magic addition operator
  1642. X
  1643. X        # process terms
  1644. X        sval = 0
  1645. X        # there is no portable way to put a slash in a regexp
  1646. X        while (s ~ /^[+*%)-]/ || substr(s, 1, 1) == "/") {
  1647. X            # figure out what it is and what it contributes
  1648. X            if (debug["e"] > 1)
  1649. X                print "s=`" s "'"
  1650. X            termop = substr(s, 1, 1)
  1651. X            s = substr(s, 2)
  1652. X            termscale = exprscale
  1653. X            if (termop == ")") {
  1654. X                if (debug["e"] > 1)
  1655. X                    print "pop " valstack[vsp] " " opstack[vsp] " with " sval
  1656. X                termval = sval
  1657. X                sval = valstack[vsp]
  1658. X                termop = opstack[vsp]
  1659. X                vsp--
  1660. X                termscale = "u"
  1661. X            } else if (s ~ /^\(/) {
  1662. X                if (debug["e"] > 1)
  1663. X                    print "push " sval " " termop
  1664. X                vsp++
  1665. X                valstack[vsp] = sval
  1666. X                opstack[vsp] = termop
  1667. X                sval = 0
  1668. X                termop = "+"    # dummy op and value
  1669. X                termval = 0
  1670. X                s = "+" substr(s, 2)
  1671. X            } else if (s ~ /^\\w/) {
  1672. X                delim = substr(s, 3, 1)
  1673. X                s = substr(s, 4)
  1674. X                endp = index(s, delim)
  1675. X                if (endp == 0)
  1676. X                    endp = length(s) + 1
  1677. X                termval = (endp - 1) * scale["n"]    # crude
  1678. X                s = substr(s, endp+1)
  1679. X            } else if (s ~ /^\\n/) {
  1680. X                if (s ~ /^\\n\(/) {
  1681. X                    code = substr(s, 4, 2)
  1682. X                    s = substr(s, 6)
  1683. X                } else {
  1684. X                    code = substr(s, 3, 1)
  1685. X                    s = substr(s, 4)
  1686. X                }
  1687. X                termval = numbers[code]
  1688. X            } else if (s ~ /^[0-9.]/) {
  1689. X                for (endp = 1; endp <= length(s); endp++)
  1690. X                    if (substr(s, endp, 1) !~ /[0-9.]/)
  1691. X                        break
  1692. X                termval = substr(s, 1, endp-1) + 0
  1693. X                s = substr(s, endp)
  1694. X            }
  1695. X
  1696. X            # add it in, with scaling factor
  1697. X            c = substr(s, 1, 1)
  1698. X            if (scale[c] != "") {
  1699. X                termval *= scale[c]
  1700. X                s = substr(s, 2)
  1701. X            } else
  1702. X                termval *= scale[termscale]
  1703. X            if (termop == "+")
  1704. X                sval += termval
  1705. X            else if (termop == "-")
  1706. X                sval -= termval
  1707. X            else if (termop == "*")
  1708. X                sval *= termval
  1709. X            else if (termop == "/")
  1710. X                sval = int(sval) / int(termval)
  1711. X            else if (termop == "%")
  1712. X                sval = int(sval) % int(termval)
  1713. X        }
  1714. X
  1715. X        # remember the value, print if debugging
  1716. X        expr[n] = sval
  1717. X        exprsign[n] = ssign
  1718. X        iexpr[n] = signfactor[ssign] * sval    # convenience
  1719. X        if (debug["e"])
  1720. X            printf "%s ", ssign "(" sval ")"
  1721. X
  1722. X        # proceed to next, skipping trash if necessary
  1723. X        while (s ~ /^[^ \t]/)
  1724. X            s = substr(s, 2)
  1725. X        n++
  1726. X    }
  1727. X
  1728. X    # final cleanup
  1729. X    nexprs = n - 1
  1730. X    if (debug["e"])
  1731. X        printf "\n"
  1732. X
  1733. X    # fallthrough
  1734. X}
  1735. X/^\.(ll|in|ti|po|pl)/ {        # common code for set-parameter requests
  1736. X    # relies on expression processing, including setting of exprscale
  1737. X    name = substr($1, 2, 2)
  1738. X    n = parms[name]
  1739. X    if (nexprs == 0)
  1740. X        n = prevparms[name]
  1741. X    else if (exprsign[1] == "" || name == "ti")
  1742. X        n = expr[1] / scale[exprscale]
  1743. X    else
  1744. X        n += iexpr[1] / scale[exprscale]
  1745. X    prevparms[name] = parms[name]
  1746. X    parms[name] = int(n)
  1747. X    print dobreak, setcmd[name], parms[name]
  1748. X    next
  1749. X}
  1750. X/^\.nr/ {
  1751. X    # relies on expression processing
  1752. X    n = numbers[$2]
  1753. X    if (exprsign[1] == "")
  1754. X        n = expr[1]
  1755. X    else
  1756. X        n += iexpr[1]
  1757. X    numbers[$2] = int(n)
  1758. X    next
  1759. X}
  1760. X/^\.ne/ {
  1761. X    # relies on expression processing
  1762. X    print dobreak, "need", int(expr[1]/scale["v"] + 0.99)
  1763. X    next
  1764. X}
  1765. X/^\.sp/ {
  1766. X    # relies on expression processing
  1767. X    if (nexprs == 0)
  1768. X        i = 1
  1769. X    else
  1770. X        i = int(expr[1]/scale["v"] + 0.99)
  1771. X    for (; i > 0; i--)
  1772. X        print dobreak, "space"
  1773. X    next
  1774. X}
  1775. X/^\.ta/ {
  1776. X    # relies on expression processing
  1777. X    tabstop = 0
  1778. X    for (n = 1; n <= nexprs; n++) {
  1779. X        if (exprsign[n] == "")
  1780. X            tabstop = expr[n]
  1781. X        else
  1782. X            tabstop += iexpr[n]
  1783. X        tabs[n] = int(tabstop/scale["n"])
  1784. X    }
  1785. X    ntabs = nexprs
  1786. X    next
  1787. X}
  1788. X/^\.ft/ {
  1789. X    if (NF > 1)
  1790. X        code = $2
  1791. X    else
  1792. X        code = "P"
  1793. X
  1794. X    if (code == "P")
  1795. X        font = prevfont
  1796. X    else if (fontok[code] == "")
  1797. X        print msg "unknown font `" code "'"
  1798. X    else {
  1799. X        prevfont = font
  1800. X        font = code
  1801. X    }
  1802. X    next
  1803. X}
  1804. X/^\.br/ {
  1805. X    print dobreak, "flush"
  1806. X    next
  1807. X}
  1808. X/^\.ds/ {
  1809. X    # note, macro-set-specific code often looks at .ds as well
  1810. X    if ($3 !~ /^"/)
  1811. X        strings[$2] = $3
  1812. X    else
  1813. X        strings[$2] = substr($0, index($0, "\"")+1)
  1814. X    next
  1815. X}
  1816. X/^\.ns/ {
  1817. X    print nobreak, "nospace"
  1818. X    next
  1819. X}
  1820. X/^\.rs/ {
  1821. X    print nobreak, "yesspace"
  1822. X    next
  1823. X}
  1824. X/^\.ad/ {
  1825. X    print nobreak, "both"
  1826. X    next
  1827. X}
  1828. X/^\.na/ {
  1829. X    print nobreak, "left"
  1830. X    next
  1831. X}
  1832. X/^\.nf/ {
  1833. X    fill = 0
  1834. X    print dobreak, "flush"
  1835. X    next
  1836. X}
  1837. X/^\.fi/ {
  1838. X    fill = 1
  1839. X    print dobreak, "flush"
  1840. X    next
  1841. X}
  1842. X/^\.\^x/ {            # direct errors to this file:  .^x filename
  1843. X    print nobreak, "errsto", $2
  1844. X    next
  1845. X}
  1846. X/^\.\^c/ {            # define character:  .^c name width text
  1847. X    if ($4 ~ /^"/)
  1848. X        s = substr($0, index($0, "\"")+1)
  1849. X    else
  1850. X        s = $4
  1851. X    ns = ""
  1852. X    while ((n = index(s, "\\")) > 0) {
  1853. X        if (n > 1)
  1854. X            ns = ns substr(s, 1, n-1)
  1855. X        n++
  1856. X        c = substr(s, n, 1)
  1857. X        if (c == "\\")
  1858. X            ns = ns "\\"
  1859. X        else if (c == "b")
  1860. X            ns = ns "\b"
  1861. X        s = substr(s, n+1)
  1862. X    }
  1863. X    ns = ns s
  1864. X    if ($2 == "hy") {
  1865. X        hyphens[font] = ns
  1866. X        hyphenwidths[font] = $3
  1867. X    } else {
  1868. X        chars[$2] = ns
  1869. X        charwidths[$2] = $3
  1870. X    }
  1871. X    next
  1872. X}
  1873. X/^\.\^f/ {            # this font is okay:  .^f fontname
  1874. X    # someday, this might take font-change codes as further arguments
  1875. X    fontok[$2] = "yes"
  1876. X    next
  1877. X}
  1878. X/^\.tm/ {
  1879. X    print msg $0
  1880. X    next
  1881. X}
  1882. X/^\.ps/ {
  1883. X    # ignore
  1884. X    next
  1885. X}
  1886. X/^\.ce/ {
  1887. X    if (NF > 1)
  1888. X        centering = $2
  1889. X    else
  1890. X        centering = 1
  1891. X    next
  1892. X}
  1893. X/^\.bp/ {
  1894. X    print dobreak, "need", 999
  1895. X    next
  1896. X}
  1897. X/^\.\^d/ {            # debug control:  .^d debugvar value
  1898. X    debug[$2] = $3
  1899. X    next
  1900. X}
  1901. X/^\.\^#/ {            # set line number of next line: .^# no file
  1902. X    il = $2 - 1
  1903. X    lockil = 0
  1904. X    inname = $3
  1905. X    next
  1906. X}
  1907. X/^\.\^=/ {            # lock line number to value:  .^= no file
  1908. X    il = $2
  1909. X    lockil = 1
  1910. X    inname = $3
  1911. X    next
  1912. X}
  1913. X/^\.\\"/ {            # comment
  1914. X    next
  1915. X}
  1916. X/^\./ {
  1917. X    print msg "command `" $1 "' unsupported or unknown"
  1918. X}
  1919. XEND {
  1920. X    print dobreak, "need", 999    # flush page
  1921. X}
  1922. !
  1923. echo 'pass2.man':
  1924. sed 's/^X//' >'pass2.man' <<'!'
  1925. X/^\.\^b/ {            # initialization
  1926. X    print nobreak, "fph", 1
  1927. X    next
  1928. X}
  1929. X/^[^.]/ {            # text line -- reached only for input traps
  1930. X    if (afternext ~ /,fP/)
  1931. X        font = prevfont
  1932. X    if (afternext ~ /,tP/)
  1933. X        print dobreak, "toindent"
  1934. X    afternext = ""
  1935. X    next
  1936. X}
  1937. X/^\.ds/ {            # to catch special strings
  1938. X    if ($3 !~ /^"/)
  1939. X        v = $3
  1940. X    else
  1941. X        v = substr($0, index($0, "\"")+1)
  1942. X    if ($2 ~ /^[LCR][HF]$/)
  1943. X        print nobreak, $2, v
  1944. X    # fallthrough to normal .ds processing in macro-independent stuff
  1945. X}
  1946. X/^\.lF/ {
  1947. X    # special footer fiddling
  1948. X    if (strings["by"] != "" && strings["nb"] != "")
  1949. X        lf = strings["by"] "; " strings["nb"]
  1950. X    else
  1951. X        lf = strings["by"] strings["nb"]
  1952. X    print nobreak, "LF", lf
  1953. X    next
  1954. X}
  1955. X/^\.\^e/ {            # finalization
  1956. X    next
  1957. X}
  1958. !
  1959. echo 'pass2.ms':
  1960. sed 's/^X//' >'pass2.ms' <<'!'
  1961. X/^\.\^b/ {            # initialization
  1962. X    nhnos[1] = 0
  1963. X    next
  1964. X}
  1965. X/^[^.]/ {            # text line -- reached only for input traps
  1966. X    if (afternext == ",tP")
  1967. X        print dobreak, "toindent"
  1968. X    afternext = ""
  1969. X    next
  1970. X}
  1971. X/^\.nH/ {            # fooling around for numbered headings
  1972. X    no = 1
  1973. X    if (NF > 1)
  1974. X        no = $2
  1975. X    if (no == 0) {
  1976. X        nhnos[1] = 0
  1977. X        no = 1
  1978. X    }
  1979. X    nhnos[no]++
  1980. X    for (n in nhnos)
  1981. X        if (n > no)
  1982. X            nhnos[n] = 0
  1983. X    s = ""
  1984. X    for (n = 1; n <= no; n++)
  1985. X        s = s nhnos[n] "."
  1986. X    strings["Nh"] = s        # result in string for macro to grab
  1987. X    next
  1988. X}
  1989. X/^\.ds/ {            # to catch special strings
  1990. X    if ($3 !~ /^"/)
  1991. X        v = $3
  1992. X    else
  1993. X        v = substr($0, index($0, "\"")+1)
  1994. X    if ($2 ~ /^[LCR][HF]$/)
  1995. X        print nobreak, $2, v
  1996. X    # fallthrough to normal .ds processing in macro-independent stuff
  1997. X}
  1998. X/^\.\^e/ {            # finalization
  1999. X    next
  2000. X}
  2001. !
  2002. echo 'pass3':
  2003. sed 's/^X//' >'pass3' <<'!'
  2004. X# third pass:  setting lines and pages
  2005. X# The input language of this pass is basically <width, word> pairs, where
  2006. X# "word" may have imbedded strangeness (backspaces, etc.) for font changes
  2007. X# and special characters.  Zero width is not special.  A third field may
  2008. X# appear to indicate that this is a fragment of a word that can be
  2009. X# hyphenated; the third field is the width of the hyphen that would have
  2010. X# to be added if the line broke after this fragment.
  2011. X# Negative widths denote special operations.  -3 is an error message, the
  2012. X# second field being the message.  -1 and -2 are control messages to this
  2013. X# pass, the difference being whether a break is implied or not.  The second
  2014. X# field is a message type string; more fields may appear as arguments.  The
  2015. X# semantics of control messages are often -- but not always! -- similar to
  2016. X# those of troff commands.  For example, "linelen" is .ll, but "center" is
  2017. X# not semantically equivalent to .ce -- it is related but more primitive.
  2018. XBEGIN {
  2019. X    # input and output details
  2020. X    FS = "\t"
  2021. X    nobreak = -1
  2022. X    dobreak = -2
  2023. X    message = -3
  2024. X    errs = "awf.errs"    # default only, normally changed by "errsto"
  2025. X
  2026. X    # page setup -- some are defaults only, normally altered by pass 2
  2027. X    nextlineno = 1
  2028. X    thispageno = 1
  2029. X    topmargin = 5
  2030. X    botmargin = 5
  2031. X    ind = 0            # current indent
  2032. X    tmpind = 0
  2033. X    pageoffset = ""        # string to emit at start of each line
  2034. X    nospacemode = 1
  2035. X    hdrs["CH"] = "- % -"
  2036. X    nop = split("LH,CH,RH,LF,CF,RF", hdrnames, ",")
  2037. X    fph = 0            # print header on first page?
  2038. X    fill = 1
  2039. X    adj = "both"
  2040. X    pagelen = 66
  2041. X    linelen = 78
  2042. X
  2043. X    # line-builder setup
  2044. X    line = ""        # line so far, without padding
  2045. X    paddable = ""        # x means corresp. char in "line" is paddable
  2046. X    thislinelen = -1    # -1 means nothing there
  2047. X    cont = " "        # thing to append to continue line
  2048. X    contlen = 1
  2049. X    eol = ""        # thing to append to break line
  2050. X    eollen = 0
  2051. X    padfrom = "R"        # "L" or "R", alternating for river avoidance
  2052. X
  2053. X    # many spaces, so we can use substr to get any number we need
  2054. X    sps = "                                                     "
  2055. X    sps = sps sps sps sps sps sps sps sps sps sps
  2056. X}
  2057. X{
  2058. X    # process word, if any, causing a break if appropriate
  2059. X    if ($1 >= 0 && thislinelen < 0) {    # word, and first on line
  2060. X        line = $2
  2061. X        paddable = substr(sps, 1, length($2))
  2062. X        thislinelen = $1
  2063. X    } else if ($1 >= 0 && thislinelen+contlen+$1+$3 <= linelen-ind-tmpind) {
  2064. X        # word, and it fits on line
  2065. X        line = line cont $2
  2066. X        if (cont == " ")
  2067. X            paddable = paddable "x"
  2068. X        else
  2069. X            paddable = paddable substr(sps, 1, length(cont))
  2070. X        paddable = paddable substr(sps, 1, length($2))
  2071. X        thislinelen += contlen + $1
  2072. X    } else if ($1 == nobreak || $1 == message)
  2073. X        nop = 0        # no attention (i.e. break) needed here
  2074. X    else if ($1 == dobreak && $2 == "need" && \
  2075. X                nextlineno + $3 < pagelen + 1 - botmargin)
  2076. X        nop = 0        # enough space is available, no action needed
  2077. X    else if ($1 == dobreak && $2 == "toindent" && \
  2078. X                    ind + tmpind + thislinelen < ind) {
  2079. X        # move to indent position within line; there is room
  2080. X        n = ind - (ind + tmpind + thislinelen)
  2081. X        line = line substr(sps, 1, n)
  2082. X        # nothing before this is paddable
  2083. X        paddable = substr(sps, 1, length(line))
  2084. X        thislinelen += n
  2085. X        # prevent padding immediately after this point
  2086. X        cont = ""
  2087. X        contlen = 0
  2088. X    } else if (thislinelen >= 0 || ($1 == dobreak && $2 == "need")) {
  2089. X        # must emit output, either due to break or "need"
  2090. X
  2091. X        # if at top of page, header
  2092. X        if (nextlineno == 1) {
  2093. X            for (i = int((topmargin-1)/2); i > 0; i--) {
  2094. X                print ""
  2095. X                nextlineno++
  2096. X            }
  2097. X            for (hno in hdrnames) {
  2098. X                h = hdrnames[hno]
  2099. X                if (hdrs[h] ~ /%/) {
  2100. X                    n = split(hdrs[h], t, "%")
  2101. X                    thispagehdrs[h] = t[1] thispageno t[2]
  2102. X                } else
  2103. X                    thispagehdrs[h] = hdrs[h]
  2104. X            }
  2105. X            if (fph || thispageno > 1) {
  2106. X                lh = thispagehdrs["LH"]
  2107. X                ch = thispagehdrs["CH"]
  2108. X                rh = thispagehdrs["RH"]
  2109. X                lsp = int((linelen - length(lh ch rh)) / 2)
  2110. X                rsp = linelen - length(lh ch rh) - lsp
  2111. X                print pageoffset lh substr(sps, 1, lsp) ch substr(sps, 1, rsp) rh
  2112. X            } else
  2113. X                print ""
  2114. X            nextlineno++
  2115. X            while (nextlineno <= topmargin) {
  2116. X                print ""
  2117. X                nextlineno++
  2118. X            }
  2119. X        }
  2120. X
  2121. X        # the current line
  2122. X        # first, add a trailing hyphen if any
  2123. X        line = line eol
  2124. X        paddable = paddable substr(sps, 1, length(eol))
  2125. X        thislinelen += eollen
  2126. X
  2127. X        # trim trailing spaces if any
  2128. X        while (line ~ / $/) {
  2129. X            line = substr(line, 1, length(line)-1)
  2130. X            paddable = substr(paddable, 1, length(line))
  2131. X            thislinelen--
  2132. X        }
  2133. X
  2134. X        # print it in a suitable way
  2135. X        if (line == "")        # empty always prints as nothing
  2136. X            print ""
  2137. X        else if ($1 < 0 && $2 == "center") {
  2138. X            # center it
  2139. X            hsp = int((linelen - thislinelen) / 2)
  2140. X            if (hsp < 0)
  2141. X                hsp = 0
  2142. X            print pageoffset substr(sps, 1, ind+tmpind+hsp) line
  2143. X        } else if (adj == "left" || (adj == "both" && \
  2144. X                    ($1 < 0 || index(paddable, "x") == 0)))
  2145. X            # no right-margin adjustment (disabled, inappropriate
  2146. X            # (line ended by break), or impossible)
  2147. X            print pageoffset substr(sps, 1, ind+tmpind) line
  2148. X        else if (adj == "both") {
  2149. X            # hard case -- adjust right margin
  2150. X            # sanity check
  2151. X            if (length(paddable) != length(line))    # aieeeee
  2152. X                printf "awf: %f != %f!\n", length(paddable), \
  2153. X                            length(line) >errs
  2154. X
  2155. X            # compute parameters
  2156. X            textlen = linelen - (ind+tmpind)
  2157. X            mustadd = textlen - thislinelen
  2158. X            npad = 0    # number of paddable spaces
  2159. X            for (tmp = paddable; (i = index(tmp, "x")) > 0; \
  2160. X                            tmp = substr(tmp, i+1))
  2161. X                npad++
  2162. X            addatall = int(mustadd/npad)    # all grow this much
  2163. X            spall = substr(sps, 1, addatall)
  2164. X            nmore = mustadd - addatall*npad    # this many grow more
  2165. X
  2166. X            # build padded output text
  2167. X            out = substr(sps, 1, ind+tmpind)
  2168. X            padno = 0
  2169. X            while ((i = index(paddable, "x")) > 0) {
  2170. X                out = out substr(line, 1, i)
  2171. X                padno++
  2172. X                out = out spall
  2173. X                if (padfrom == "L") {
  2174. X                    if (padno <= nmore)
  2175. X                        out = out " "
  2176. X                } else {
  2177. X                    if (padno > npad-nmore)
  2178. X                        out = out " "
  2179. X                }
  2180. X                line = substr(line, i+1)
  2181. X                paddable = substr(paddable, i+1)
  2182. X            }
  2183. X
  2184. X            # print it, plus remnant not processed by loop
  2185. X            print pageoffset out line
  2186. X
  2187. X            # tidy up
  2188. X            if (padfrom == "L")
  2189. X                padfrom = "R"
  2190. X            else
  2191. X                padfrom = "L"
  2192. X        }
  2193. X
  2194. X        # tidy up after output line
  2195. X        nextlineno++
  2196. X        line = ""
  2197. X        paddable = ""
  2198. X        thislinelen = -1
  2199. X        tmpind = 0
  2200. X        nospacemode = 0
  2201. X
  2202. X        # if we broke from a "need", go to bottom of page
  2203. X        if ($1 == dobreak && $2 == "need")
  2204. X            while (nextlineno < pagelen + 1 - botmargin) {
  2205. X                print ""
  2206. X                nextlineno++
  2207. X            }
  2208. X
  2209. X        # footer, if at bottom of page
  2210. X        if (nextlineno >= pagelen + 1 - botmargin) {
  2211. X            for (i = int((botmargin-1)/2); i > 0; i--) {
  2212. X                print ""
  2213. X                nextlineno++
  2214. X            }
  2215. X            # header code prepared thispagehdrs
  2216. X            lf = thispagehdrs["LF"]
  2217. X            cf = thispagehdrs["CF"]
  2218. X            rf = thispagehdrs["RF"]
  2219. X            lsp = int((linelen - length(lf cf rf)) / 2)
  2220. X            rsp = linelen - length(lf cf rf) - lsp
  2221. X            print pageoffset lf substr(sps, 1, lsp) cf substr(sps, 1, rsp) rf
  2222. X            nextlineno++
  2223. X            while (nextlineno <= pagelen) {
  2224. X                print ""
  2225. X                nextlineno++
  2226. X            }
  2227. X            nextlineno = 1
  2228. X            thispageno++
  2229. X
  2230. X            # after page break, should not space unnecessarily,
  2231. X            # and should pad first line from right
  2232. X            nospacemode = 1
  2233. X            padfrom = "R"
  2234. X        }
  2235. X
  2236. X        # we are finally done with emitting output
  2237. X        # pick up input word, if any
  2238. X        if ($1 >= 0) {
  2239. X            line = $2
  2240. X            paddable = substr(sps, 1, length($2))
  2241. X            thislinelen = $1
  2242. X        }
  2243. X    }
  2244. X
  2245. X    # if we broke, next line should pad from right
  2246. X    if ($1 == dobreak)
  2247. X        padfrom = "R"
  2248. X
  2249. X    # cleanup and post-break command processing
  2250. X    if ($1 >= 0 || $2 == "nohyphen") {
  2251. X        # reset hyphenation trickery after each word (fragment)
  2252. X        cont = " "
  2253. X        contlen = 1
  2254. X        eol = ""
  2255. X        eollen = 0
  2256. X    } else if ($2 == "need" || $2 == "toindent")
  2257. X        nop = 0        # dealt with above
  2258. X    else if ($2 == "flush" || $2 == "center")
  2259. X        nop = 0        # exist only to cause break
  2260. X    else if ($1 == message)
  2261. X        print "awf: " $2 >errs
  2262. X    else if ($2 == "gap") {
  2263. X        # gap between last word and next one should be >= $3
  2264. X        if (thislinelen >= 0) {
  2265. X            line = line substr(sps, 1, $3-1)
  2266. X            paddable = paddable substr(sps, 1, $3-1)
  2267. X            thislinelen += $3-1
  2268. X        }
  2269. X    } else if ($2 == "tabto") {
  2270. X        # move to tab stop at $3
  2271. X        if (thislinelen < 0)
  2272. X            thislinelen = 0        # make line exist
  2273. X        n = $3 - thislinelen
  2274. X        if (n > 0) {            # must emit some space
  2275. X            line = line substr(sps, 1, n)
  2276. X            # nothing before a tab is paddable
  2277. X            paddable = substr(sps, 1, length(line))
  2278. X            thislinelen += n
  2279. X            # suppress space following
  2280. X            cont = ""
  2281. X            contlen = 0
  2282. X        }
  2283. X    } else if ($2 == "errsto")
  2284. X        errs = $3
  2285. X    else if ($2 ~ /^[LCR][HF]$/)
  2286. X        hdrs[$2] = $3
  2287. X    else if ($2 == "fph")
  2288. X        fph = $3
  2289. X    else if ($2 == "space") {
  2290. X        if (!nospacemode) {
  2291. X            # generate an empty line, which will be flushed by
  2292. X            # the next word; NB we know "space" caused a flush
  2293. X            line = ""
  2294. X            paddable = ""
  2295. X            thislinelen = linelen + 1
  2296. X            nospacemode = 0
  2297. X        }
  2298. X    } else if ($2 == "left")
  2299. X        adj = "left"
  2300. X    else if ($2 == "both")
  2301. X        adj = "both"
  2302. X    else if ($2 == "indent")
  2303. X        ind = $3
  2304. X    else if ($2 == "tempindent")
  2305. X        tmpind = $3
  2306. X    else if ($2 == "linelen")
  2307. X        linelen = $3
  2308. X    else if ($2 == "pagelen")
  2309. X        pagelen = $3
  2310. X    else if ($2 == "nospace")
  2311. X        nospacemode = 1
  2312. X    else if ($2 == "yesspace")
  2313. X        nospacemode = 0
  2314. X    else if ($2 == "hyphen") {
  2315. X        # discretionary hyphen at this point
  2316. X        cont = ""
  2317. X        contlen = 0
  2318. X        eol = $3
  2319. X        eollen = $4
  2320. X    } else if ($2 == "userhyphen") {
  2321. X        # user-supplied hyphen at this point
  2322. X        cont = $3
  2323. X        contlen = $4
  2324. X        eol = $3
  2325. X        eollen = $4
  2326. X    } else if ($2 == "pageoffset")
  2327. X        pageoffset = substr(sps, 1, $3)
  2328. X    else
  2329. X        print "awf: URK -- INTERNAL OPCODE `" $2 "' UNKNOWN" >errs
  2330. X}
  2331. XEND {
  2332. X    # second pass is supposed to fake a .ne to flush the last page
  2333. X    if (nextlineno != 1)
  2334. X        print "awf: last page not flushed!" >errs
  2335. X}
  2336. !
  2337. echo done
  2338.  
  2339. exit 0 # Just in case...
  2340. -- 
  2341. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  2342. Use a domain-based address or give alternate paths, or you may lose out.
  2343.