home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / alt / sources / 2838 < prev    next >
Encoding:
Text File  |  1992-12-21  |  54.0 KB  |  2,336 lines

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