home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume23 / awf next >
Encoding:
Internet Message Format  |  1990-10-09  |  53.8 KB

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