1;;;; -*-Scheme-*-
2;;;;
3;;;; $Revision: 1.14 $
4;;;;
5;;;; `me' specific definitions for HTML output format
6;;;; Hacked from ms version by G. Helffrich/U. Bristol
7
8
9;;; --------------------------------------------------------------------------
10;;; Options.
11
12(define-option 'signature          'string    "")
13(define-option 'split              'integer   0)
14(define-option 'toc                'boolean   #t)
15(define-option 'toc-header         'string    "Table of Contents")
16(define-option 'pp-indent          'integer   3)
17(define-option 'footnotes-header   'string    "Footnotes")
18(define-option 'footnote-reference 'string    "<b>[%1%]</b>")
19(define-option 'footnote-anchor    'string    "")
20
21
22
23;;; --------------------------------------------------------------------------
24;;; Predefined strings and number registers.
25
26(defstring 'lq  "``")
27(defstring 'rq  "''")
28(defstring '-  "--")    ; em-dash
29(defstring 'mo (substitute "%monthname+%"))
30(defstring 'dw (substitute "%weekday+%"))
31(defstring 'dy (substitute "%day%"))
32(defstring 'td (substitute "%monthname+% %day%, %year%"))
33
34(defnumreg '$c #\1)
35(defnumreg '$f #\1)
36(defnumreg '$m #\2)
37(defnumreg '$n #\2)
38(defnumreg '$0 "")
39(defnumreg '$1 "")
40(defnumreg '$2 "")
41(defnumreg '$3 "")
42(defnumreg '$4 "")
43(defnumreg '$5 "")
44(defnumreg '$6 "")
45(defstring '$n "")
46
47
48;;; --------------------------------------------------------------------------
49;;; General bookkeeping.
50
51
52(define para-number 0)         ; numbered paragraph number
53(define split-sections? #f)    ; #t if `split' option is positive
54
55
56(define-pair abstract   abstract?   ""               "<hr>\n")
57(define-pair title      title?      "<h1>\n"         "</h1>\n")
58(define-pair secthdr    secthdr?    "<h2>\n"         "</h2>\n")
59(define-pair tag-para   tag-para?   "<dl compact>\n" "</dl>\n")
60(define-pair list-para  list-para?  "<ul>\n"         "</ul>\n")
61(define-pair quoted     quoted?     "<blockquote>\n" "</blockquote>\n")
62
63(define (reset-everything)
64  (set! para-number 0)
65  (emit
66    (reset-font)
67    (center 0)
68    (quoted #f)
69    (secthdr #f)
70    (preform #f)
71    (tag-para #f)
72    (list-para #f)
73    (reset-title-features)))
74
75(define-nested-pair indent  indent-level  "<dl><dt><dd>" "</dl>\n")
76
77
78
79;;; --------------------------------------------------------------------------
80;;; Manage HTML output files.
81
82(define HTML-streams '())
83
84(define (push-HTML-stream file-suffix title-suffix)
85  (let* ((docname (option 'document))
86	 (title (option 'title))
87	 (t (concat (if title title docname) title-suffix))
88	 (fn (if file-suffix (concat docname file-suffix ".html") #f))
89	 (s (if fn (open-output-stream fn) #f)))
90    (close-stream (set-output-stream! #f))
91    (set-output-stream! s)
92    (list-push! HTML-streams fn)
93    (emit-HTML-prolog)
94    (emit "<title>" (translate t) "</title>\n</head><body>\n")))
95
96(define (pop-HTML-stream)
97  (if (not (eqv? (option 'signature) ""))
98      (emit "<p><hr>\n" (substitute (option 'signature))) #\newline)
99  (emit "</body>\n</html>\n")
100  (list-pop! HTML-streams)
101  (close-stream (set-output-stream! #f))
102  (if (and (not (null? HTML-streams)) (car HTML-streams))
103      (set-output-stream! (append-output-stream (car HTML-streams)))))
104
105
106
107;;; --------------------------------------------------------------------------
108;;; Callback procedure called by hyper.scm when creating hypertext anchor.
109
110(define (query-anchor request label)
111  (lambda (op)
112    (case op
113      (allowed?       #t)
114      (emit-anchor?   #t)
115      (filename
116	(if (not (stream-file? (output-stream)))
117	    (car HTML-streams)
118	    (stream-target (output-stream)))))))
119
120
121
122;;; --------------------------------------------------------------------------
123;;; Generate hypertext reference and anchor.
124
125(define (make-href type index contents)
126  (let* ((docname (option 'document))
127	 (file
128	   (case type
129	   ((section toc) (car HTML-streams))
130	   (footnote (if split-sections? (concat docname "-notes.html") "")))))
131    (format #f "<a href=\"~a#~a~a\">~a" file type index
132	       (if contents (concat contents "</a>") ""))))
133
134(define (make-anchor type index contents)
135  (format #f "<a name=\"~a~a\">~a</a>" type index contents))
136
137
138
139;;; --------------------------------------------------------------------------
140;;; Automatically generated TOC.
141
142(define auto-toc-entry
143  (let ((last-level 0))
144    (lambda (anchor entry level labelnum)
145      (with-output-appended-to-stream "[autotoc]"
146	(emit (repeat-string (- level last-level) "<ul>")
147	      (repeat-string (- last-level level) "</ul>"))
148	(set! last-level level)
149	(if (positive? level)
150	    (emit "<li>" (make-href 'section labelnum anchor) entry))))))
151
152(define (auto-toc-spill)
153  (auto-toc-entry "" "" 0 0)
154  (let ((toc (stream->string "[autotoc]")))
155    (if (not (eqv? toc ""))
156	(emit "<h2>" (substitute (option 'toc-header)) "</h2>\n" toc))))
157
158
159
160;;; --------------------------------------------------------------------------
161;;; Start and exit event functions.
162
163(defevent 'start 10
164  (lambda _
165    (set! split-sections? (not (zero? (option 'split))))
166    (let ((docname (option 'document)))
167      (if (not (or docname (option 'title)))
168	  (quit "you must set either document= or title="))
169      (if (and split-sections? (not docname))
170	  (quit "you must set document= for non-zero `split'"))
171      (push-HTML-stream (if docname "" #f) ""))))
172
173(defevent 'exit 10
174  (lambda _
175    (reset-everything)
176    (emit (indent 0))
177    (footnote-processor footnotes 'spill)
178    (do () ((null? (cdr HTML-streams))) (pop-HTML-stream))
179    (if (option 'toc)
180        (auto-toc-spill))
181    (pop-HTML-stream)))
182
183
184
185;;; --------------------------------------------------------------------------
186;;; Title features, abstract.
187
188(define got-title? #f)
189
190(define (reset-title-features)
191  (concat (title #f)
192	  (begin1 (if got-title? "<hr>\n" "") (set! got-title? #f))))
193
194(define in-section #f)
195
196(defmacro '+c
197  (lambda (_ . hdr)
198    (if (not (null? hdr))
199      (cond
200	((not in-section) (parse (car hdr)))
201	((string=? in-section "P")
202	   (concat (title #t) (parse (car hdr)) (title #f)))
203	((string=? in-section "AB")
204	   (concat (abstract #t) (parse (car hdr)) nbsp))
205	((or (string=? in-section "A")
206	     (string=? in-section "B")
207	     (string=? in-section "C")
208	     (string=? in-section "RC")
209	     (string=? in-section "RA"))
210		(concat (secthdr #t) (parse (car hdr)) (secthdr #f)))
211	(else (begin (warn ".+c unknown section ~a" in-section) (parse hdr))))
212      "")))
213
214(defmacro '++
215  (lambda (_ section . arg)
216    (if (not (member (parse section) '("C" "A" "P" "AB" "B" "RC" "RA")))
217      (warn ".++ ~a ignored" section)
218      (set! in-section (parse section)))
219      (if abstract? (abstract #f) "")))
220
221
222;;; --------------------------------------------------------------------------
223;;; Sections.
224
225;; If splitting sections, only prefix the header text with the section number
226;; if dealing with sections > 0.
227(define header-processor
228  (let ((seq 0))
229    (lambda (hdr depth)
230    (cond
231      ((and split-sections? (option 'toc))
232	  (++ seq)
233	  (auto-toc-entry hdr "" depth (stringdef '$n))
234	  (emit "<h2>"
235		(make-anchor 'section seq (stringdef '$n))))
236      (else
237        (if (macrodef '$0)
238	  (emit (parse-line
239		  (format #f ".$0 \"~a\" ~a ~a" hdr (stringdef '$n) depth))))
240	  (emit "<h2>")))
241    (emit hdr "</h2>\n")
242      "")))
243
244;;; @d from -me macros
245;;;   1st param is level, next (up to) 6 are the level values to set
246(define (@d . args)
247    (if (and (not (null? args)) (string->number (car args)))
248      (defnumreg '$0 (car args)))
249    (if (and (positive? (string->number (numregdef '$0))) (not (null? (cdr args))))
250      (let ((reg (format #f "$~a" (numregdef '$0))))
251	(defnumreg reg
252	  (number->string (if (and (numregdef reg)
253				   (string->number (numregdef reg)))
254				   (1+ (string->number (numregdef reg)))
255				   1)))))
256    (let (($n ""))
257      (if (>= (string->number (numregdef '$0)) 1)
258	(begin
259	  (if (or (not (numregdef '$1)) (string=? "" (numregdef '$1)))
260	    (defnumreg '$1 "1"))
261	  (if (and (>= (length args) 3) (not (string=? "-" (list-ref args 2))))
262	    (defnumreg '$1 (list-ref args 2)))
263	  (set! $n (format #f "~a" (numregdef '$1))))
264	(defnumreg '$1 ""))
265      (do
266	((i 2 (+ i 1)))
267	((> i 6))
268	 (let ((reg (format #f "$~a" i)))
269	   (if (>= (string->number (numregdef '$0)) i)
270	     (begin
271	       (if (or (not (numregdef reg)) (string=? "" (numregdef reg)))
272	         (defnumreg reg "1"))
273	       (if (and (>= (length args) (+ i 2)) (not (string=? "-" (list-ref args (1+ i)))))
274	         (defnumreg reg (list-ref args (1+ i))))
275	     (set! $n (format #f "~a.~a" $n (numregdef reg))))
276	   (defnumreg reg ""))))
277      (defstring '$n $n)))
278
279;; .uh headings are considered level zero, and are split if split<0.
280(defmacro 'uh
281  (lambda (uh . args)
282    (let ((hdr (if (> 1 (length args)) (parse (cadr args)) '())))
283      (reset-everything)
284      (header-processor hdr 0))))
285
286(defmacro 'sh
287  (lambda (sh . args)
288    (let ((level (if (null? args) args (parse (car args))))
289	  (hdr (if (> (length args) 1) (parse (cadr args)) '()))
290	  (rest  (if (> (length args) 2) (parse (cddr args)) '())))
291      (reset-everything)
292      (apply @d (append (list level '+ ) rest))
293      (header-processor hdr (if (null? level) 0 (string->number level))))))
294
295
296;;; --------------------------------------------------------------------------
297;;; Font switching and related requests.
298
299(define (with-font font . args)
300  (let ((old current-font))
301  (cond
302    ((null? args)
303       (concat (change-font font) #\newline))
304    ((null? (cdr args))
305       (concat (change-font font) (parse (car args) #\newline)
306	       (change-font old)))
307    (else
308       (concat (change-font font) (parse (car args)) (change-font old)
309	       (parse (cadr args) #\newline))))))
310
311(defmacro 'i (lambda (i . args)
312   (apply with-font (cons "I" args))))
313(defmacro 'b (lambda (b . args)
314   (apply with-font (cons "B" args))))
315(defmacro 'r (lambda (r . args)
316   (apply with-font (cons "R" args))))
317(defmacro 'rb (lambda (rb . args)
318   (apply with-font (cons "R" args))
319   (change-font "B")))
320
321(defmacro 'bi (requestdef 'rb))
322
323(defmacro 'u (lambda (u) (with-font "I")))    ; <u> doesn't work
324
325(defmacro 'q
326  (lambda (q . args)
327    (let ((old current-font))
328    (if (null? args) ""
329      (concat "``" (parse (car args)) "''" (if (null? (cdr args)) "" (parse (cadr args))) #\newline)))))
330
331(defmacro 'bx
332  (lambda (bx word)
333    (parse word #\newline)))
334
335(defmacro 'sz "")
336
337;;; --------------------------------------------------------------------------
338;;; Indented paragraph with optional label.
339
340(define (indented-paragraph op . arg)
341  (define (non-tagged? s)
342    (or (null? s) (member (car s) '("\\(bu" "\\(sq" "\\-"))))
343  (if (equal? op "np")
344    (begin
345      (++ para-number)
346      (indented-paragraph "ip" (number->string para-number)))
347    (begin
348    (emit (reset-font) (preform #f) (secthdr #f) (reset-title-features))
349    (cond
350      (tag-para?
351        (if (null? arg)
352	  "<dt><dd>"
353	  (concat "<dt>" (parse (car arg)) "<dd>")))
354      (list-para?
355        (cond
356	  ((non-tagged? arg)
357	    "<li>")
358	  (else
359            (warn ".~a `arg' in a list that was begun as non-tagged" op)
360            (concat "<li>" (parse (car arg)) "<br>\n"))))
361      ((non-tagged? arg)
362        (concat (list-para #t) (indented-paragraph op)))
363      (else
364        (concat (tag-para #t) (indented-paragraph op (car arg))))))))
365
366(defmacro 'ip indented-paragraph)
367
368(defmacro 'np indented-paragraph)
369
370
371;;; --------------------------------------------------------------------------
372;;; Displays.
373;;;
374;;; **.(z .)z problem - .(q and .(c should be nestable inside these.
375;;; **should be treated more like a footnote or delayed text rather than a
376;;; **block.
377
378(define left-paren-b "(b")
379(define right-paren-b ")b")
380(define left-paren-q "(q")
381(define right-paren-q ")q")
382(define left-paren-c "(c")
383(define right-paren-c ")c")
384(define left-paren-l "(l")
385(define right-paren-l ")l")
386(define left-paren-z "(z")
387(define right-paren-z ")z")
388(define display-saved-font #f)
389(define inside-display? #f)
390(define indented-display? #f)
391
392(define (display-start type fill)
393  (cond
394    ((or (not (= (string-length type) 1))
395	 (not (memq (string-ref type 0) '(#\I #\L #\C #\M))))
396      (warn "illegal display type `~a'" type))
397    (inside-display?
398      (warn "nested display ignored"))
399    (preform?
400      (warn "display inside .nf/.fi ignored"))
401    (else
402      (set! display-saved-font current-font)
403      (emit (reset-font))
404      (set! indented-display? (string=? type "I"))
405      (if indented-display?
406          (emit (indent '+))
407	  (emit "<br>"))
408      (if (string=? type "C") (emit (center 999)))
409      (set! inside-display? #t)
410      (if (not (string=? fill "F")) (emit (preform #t)))))
411  "")
412
413(defmacro left-paren-b
414  (lambda (_ . args)
415    (apply display-start
416      (cond
417        ((null? args) '("I" "U"))
418	((null? (cdr args)) (if (string=? (car args) "F") '("I" "F") (list (car args) "U")))
419	(else args)))
420    ""))
421
422(defmacro left-paren-l (macrodef left-paren-b))
423(defmacro left-paren-z
424  (lambda (_ . args)
425    (apply display-start
426      (cond
427        ((null? args) '("M" "U"))
428	((null? (cdr args)) (if (string=? (car args) "F") '("M" "F") (list (car args) "U")))
429	(else args)))
430    ""))
431
432(define (display-end what)
433   (cond
434     ((not inside-display?)
435	(warn ".~a without matching display start" what))
436      (else
437	(set! inside-display? #f)
438	(emit
439	  (with-font-preserved
440	    (preform #f)
441	    (if indented-display? (indent '-) "")
442	    (center 0))
443	  (change-font display-saved-font)))))
444
445(defmacro right-paren-b
446  (lambda _ (display-end right-paren-b)))
447
448(defmacro right-paren-l
449  (lambda _ (display-end right-paren-l)))
450
451(defmacro right-paren-z
452  (lambda _ (display-end right-paren-z)))
453
454(defmacro left-paren-c         ; can't center in a block like troff
455  (lambda (_ . args)
456    (concat (preform #t) (center 999))))
457
458(defmacro right-paren-c
459  (lambda (_ . args)
460    (concat (center 0) (preform #f))))
461
462(defmacro left-paren-q
463  (lambda (_ . args)
464    (emit
465      (reset-font)
466      (center 0)
467      (quoted #f)
468      (preform #f)
469      (quoted #t))))
470
471(defmacro right-paren-q
472  (lambda (_ . args)
473    (emit (quoted #f))))
474
475
476;;; --------------------------------------------------------------------------
477;;; Footnotes and delayed text.
478
479;; Generating \[***] for \** allows us to defer creating the anchor from
480;; string expansion time to output time.  Otherwise we couldn't use <...>.
481
482(defstring '* "\\[***]")
483
484(define **-count (cons 1 #f))
485
486(defspecial '***
487  (lambda _
488    (let ((inside? (cadr footnotes))
489	  (anchor (substitute (option 'footnote-reference)
490				 (number->string (car **-count)))))
491      (set-cdr! **-count #t)
492      (if inside? anchor (footnote-anchor anchor (car **-count))))))
493
494(define (footnote-anchor sym num)
495  (with-font-preserved
496    (concat (change-font 1) (make-href 'footnote num sym))))
497
498
499;; Both footnotes and delayed text are processed here.  Delayed text never gets
500;; split off into another document, but waits for .pd for inclusion.
501
502(define footnotes (list '".(f" '#f '#f '"[footnotes]"))
503(define delayed   (list '".(d" '#f '#f '"[delayed-text%1%]"))
504(define delayed-number 0)
505
506(define footnote-processor
507   (lambda (what op . arg)
508     (let  ((stream-name (substitute (cadddr what) (number->string delayed-number)))
509	    (inside? (cadr what))
510	    (stream (caddr what))
511	    (req (car what))
512	    (footnotes? (eq? what footnotes)))
513     (case op
514     (begin
515        (cond
516	  (inside?
517	    (warn "nested ~a" req))
518	  (else
519	    (set! inside? #t) (set-car! (cdr what) #t)
520	    (if footnotes? (set-cdr! **-count #f))
521	    (set! stream (set-output-stream!
522			   (append-output-stream stream-name)))
523	    (set-car! (cddr what) stream)
524	    (emit "<br>\n")
525	    (let ((anchor
526		    (cond ((not (null? arg))
527			    (parse (car arg)))
528			  ((positive? (car **-count))
529			    (substitute (option 'footnote-anchor)
530					(number->string (car **-count))))
531			  (else #f))))
532	      (if anchor
533		  (emit (make-anchor 'footnote (car **-count) anchor)))))))
534      (end
535	(cond
536	  (inside?
537	    (set! inside? #f) (set-car! (cdr what) #f)
538	    (close-stream (set-output-stream! stream))
539	    (set-car! (cddr what) #f)
540	    (if (and footnotes? (cdr **-count)) (set-car! **-count (1+ (car **-count)))))
541	  (else (warn ".)~a without matching ~a" (string-ref req 2) req))))
542      (spill
543	(if inside? (quit "unterminated ~a at end of document" req))
544	(let ((contents (stream->string stream-name))
545	      (hdr (substitute (if footnotes? (option 'footnotes-header) ""))))
546	  (close-stream stream) (set! stream #f) (set-car! (cddr what) #f)
547	  (cond
548	    ((not (eqv? contents ""))
549	       (if (and split-sections? footnotes?)
550		   (push-HTML-stream "-notes" ", footnotes"))
551	       (cond ((and split-sections? footnotes? (option 'toc))
552		       (auto-toc-entry hdr "" 1 0)
553		       (emit "<h2>" (make-anchor 'section 0 hdr) "</h2>\n"))
554		     (else (if (not (eq? hdr "")) (emit "<h2>" hdr "</h2>\n"))))
555	       (emit contents "<br>\n"))
556	    ((and footnotes? (cdr **-count))
557	      (warn "footnote anchor used, but no .(f"))))))
558    "")))
559
560(define left-paren-f "(f")
561(define right-paren-f ")f")
562(define left-paren-d "(d")
563(define right-paren-d ")d")
564
565(defmacro left-paren-f
566  (lambda (left-paren-f . arg)
567    (apply footnote-processor footnotes 'begin arg)))
568
569(defmacro right-paren-f
570  (lambda _ (footnote-processor footnotes 'end)))
571
572(define delayed-# 1)
573(define delayed-#-refs 0)
574(define delayed-#-refs-save 0)
575(defnumreg '$d
576  (lambda _
577    (number->string delayed-#)))
578
579(defstring '\#
580  (lambda _
581    (++ delayed-#-refs)
582    (number->string delayed-#)))
583
584(defmacro left-paren-d
585  (lambda (left-paren-d . arg)
586    (set! delayed-#-refs-save delayed-#-refs)
587    (apply footnote-processor delayed 'begin arg)))
588
589(defmacro right-paren-d
590  (lambda _
591    (footnote-processor delayed 'end)
592    (if (not (eq? delayed-#-refs-save delayed-#-refs)) (++ delayed-#))
593    ""))
594
595(defmacro 'pd
596  (lambda _
597     (footnote-processor delayed 'spill)
598     (++ delayed-number)
599     ""))
600
601
602
603;;; --------------------------------------------------------------------------
604;;; TOC macros.
605
606
607(define toc-keys
608   (lambda new
609      (list (cons 'name new) (cons 'stream #f) (cons 'inside? #f))))
610
611(define toc-list (list (cons "toc" (toc-keys "toc"))))
612
613(define toc-processor
614  (let ((seq 0))
615  (lambda (op . arg)
616  (define (toc-stream x) (string-append "[" x "]"))
617  (define (toc-field x y) (if y (cdr (assq x y)) #f))
618  (define (toc-field-set x y z) (set-cdr! (assq x y) z))
619    (let* ((x (string-append "toc" (parse (car arg))))
620	   (toc (assoc x toc-list)))
621      (if (not toc) (begin
622	(set! toc-list (append toc-list (list (cons x (toc-keys x)))))
623	(set! toc (assoc x toc-list))))
624      (case op
625      (begin
626        (cond
627	  ((toc-field 'inside? toc)
628	    (warn "nested .~a" left-paren-x))
629	  (else
630	    (toc-field-set 'inside? toc #t)
631	    (emit (make-anchor 'toc seq "&#160;") #\newline)
632	    (toc-field-set 'stream toc
633	       (set-output-stream! (append-output-stream (toc-stream x))))
634	    (if (option 'document)
635	        (emit (make-href 'toc seq #f)))
636	    (++ seq))))
637      (end
638	(cond
639	  ((toc-field 'inside? toc)
640	    (toc-field-set 'inside? toc #f)
641	    (if (option 'document) (emit "</a>\n"))
642	    (emit "<br>\n")
643	    (close-stream (set-output-stream! (toc-field 'stream toc))))
644	  (else (warn ".~a without matching .~a" right-paren-x left-paren-x))))
645      (spill
646	(if (toc-field 'inside? toc) (warn "unterminated .~a" right-paren-x))
647	(emit (stream->string (toc-stream x)))))
648      )
649    "")))
650
651(define left-paren-x "(x")
652(define right-paren-x ")x")
653(define toc-active "x")
654
655(defmacro left-paren-x
656  (lambda (_ . arg)
657    (let ((this (if (null? arg) toc-active (parse (car arg)))))
658      (apply toc-processor 'begin this (if (null? arg) '() (cdr arg)))
659      (set! toc-active this)
660      "")))
661
662(defmacro right-paren-x
663  (lambda (_ . arg)
664    (apply toc-processor 'end toc-active arg)))
665
666(defmacro 'xp
667  (lambda (xp . arg)
668    (reset-everything)
669    (apply toc-processor 'spill (if (null? arg) '(x) arg))))
670
671
672;;; --------------------------------------------------------------------------
673;;; Paragraphs of various kinds.
674
675(define-macro (define-paragraph request . body)
676  `(defmacro ,request (lambda _ (reset-everything) ,@body)))
677
678(define-paragraph 'lp "<p>\n")
679(define-paragraph 'pp (concat "<p>\n"
680			      (repeat-string (option 'pp-indent) nbsp)))
681
682(defmacro 'hl "<hr>\n") ; horizontal line across page
683
684;;; Base indent applies to paragraphs, everything except titles & footnotes
685;;; so it persists even across sections.  Only .ba 0 shuts it off.
686(defmacro 'ba
687  (lambda (ba . arg)
688    (cond
689      ((null? arg) (indent '-))
690      ((and (string? (car arg)) (zero? (string->number (car arg)))) (indent 0))
691      (else (indent '+)))))
692
693
694;;; --------------------------------------------------------------------------
695;;; Requests that must be ignored, either because the function cannot
696;;; be expressed in HTML or because they assume a page structure.
697
698(defmacro 're "")    ; reset tabs
699(defmacro 'll "")    ; line length
700(defmacro 'xl "")    ; line length
701(defmacro 'lh "")    ; letterhead
702(defmacro 'he "")    ; header
703(defmacro 'fo "")    ; footer
704(defmacro 'eh "")    ; even header
705(defmacro 'oh "")    ; odd header
706(defmacro 'ef "")    ; even footer
707(defmacro 'of "")    ; odd footer
708(defmacro 'hx "")    ; suppress headers & footers on next page
709(defmacro 'm1 "")    ; top of page spacing
710(defmacro 'm2 "")    ; header to first line spacing
711(defmacro 'm3 "")    ; footer to last line spacing
712(defmacro 'm4 "")    ; footer to bottom of page spacint
713(defmacro '$h "")    ; print header
714(defmacro '$f "")    ; print footer
715(defmacro '$H "")    ; top-of-page macro
716(defmacro 'th "")    ; UCB thesis mode
717(defmacro 'ac "")    ; ACM mode
718(defmacro 'sk "")    ; skip page
719(defmacro 'ro "")    ; roman page number
720(defmacro 'ar "")    ; arabic page number
721(defmacro 'pa "")    ; begin page N
722
723(define (multi-column-ignored request . _)
724  (warn "multi-column request .~a not supported" request))
725
726(defmacro '1c multi-column-ignored)
727(defmacro '2c multi-column-ignored)
728(defmacro 'bc multi-column-ignored)
729
730(define (section-ignored request . _)
731  (warn "section heading request .~a not supported" request))
732
733(defmacro 'tp section-ignored)
734(defmacro 'sx section-ignored)
735(defmacro '$p section-ignored)
736(defmacro '$0 section-ignored)
737(defmacro '$1 section-ignored)
738(defmacro '$2 section-ignored)
739(defmacro '$3 section-ignored)
740(defmacro '$4 section-ignored)
741(defmacro '$5 section-ignored)
742(defmacro '$6 section-ignored)
743