man_term.c revision 1.8.2.2 1 1.8.2.2 yamt /* Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp */
2 1.1 joerg /*
3 1.8.2.2 yamt * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps (at) bsd.lv>
4 1.8.2.2 yamt * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze (at) openbsd.org>
5 1.1 joerg *
6 1.1 joerg * Permission to use, copy, modify, and distribute this software for any
7 1.1 joerg * purpose with or without fee is hereby granted, provided that the above
8 1.1 joerg * copyright notice and this permission notice appear in all copies.
9 1.1 joerg *
10 1.1 joerg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 1.1 joerg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 1.1 joerg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 1.1 joerg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 1.1 joerg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 1.1 joerg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 1.1 joerg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 1.1 joerg */
18 1.2 joerg #ifdef HAVE_CONFIG_H
19 1.2 joerg #include "config.h"
20 1.2 joerg #endif
21 1.2 joerg
22 1.1 joerg #include <sys/types.h>
23 1.1 joerg
24 1.1 joerg #include <assert.h>
25 1.1 joerg #include <ctype.h>
26 1.1 joerg #include <stdio.h>
27 1.1 joerg #include <stdlib.h>
28 1.1 joerg #include <string.h>
29 1.1 joerg
30 1.2 joerg #include "mandoc.h"
31 1.1 joerg #include "out.h"
32 1.1 joerg #include "man.h"
33 1.1 joerg #include "term.h"
34 1.1 joerg #include "main.h"
35 1.1 joerg
36 1.8 joerg #define MAXMARGINS 64 /* maximum number of indented scopes */
37 1.1 joerg
38 1.1 joerg struct mtermp {
39 1.1 joerg int fl;
40 1.1 joerg #define MANT_LITERAL (1 << 0)
41 1.8 joerg size_t lmargin[MAXMARGINS]; /* margins (incl. visible page) */
42 1.8 joerg int lmargincur; /* index of current margin */
43 1.8 joerg int lmarginsz; /* actual number of nested margins */
44 1.8 joerg size_t offset; /* default offset to visible page */
45 1.8.2.2 yamt int pardist; /* vert. space before par., unit: [v] */
46 1.1 joerg };
47 1.1 joerg
48 1.1 joerg #define DECL_ARGS struct termp *p, \
49 1.1 joerg struct mtermp *mt, \
50 1.1 joerg const struct man_node *n, \
51 1.8.2.2 yamt const struct man_meta *meta
52 1.1 joerg
53 1.1 joerg struct termact {
54 1.1 joerg int (*pre)(DECL_ARGS);
55 1.1 joerg void (*post)(DECL_ARGS);
56 1.2 joerg int flags;
57 1.2 joerg #define MAN_NOTEXT (1 << 0) /* Never has text children. */
58 1.1 joerg };
59 1.1 joerg
60 1.4 joerg static int a2width(const struct termp *, const char *);
61 1.4 joerg static size_t a2height(const struct termp *, const char *);
62 1.1 joerg
63 1.2 joerg static void print_man_nodelist(DECL_ARGS);
64 1.2 joerg static void print_man_node(DECL_ARGS);
65 1.3 joerg static void print_man_head(struct termp *, const void *);
66 1.2 joerg static void print_man_foot(struct termp *, const void *);
67 1.1 joerg static void print_bvspace(struct termp *,
68 1.8.2.2 yamt const struct man_node *, int);
69 1.1 joerg
70 1.1 joerg static int pre_B(DECL_ARGS);
71 1.1 joerg static int pre_HP(DECL_ARGS);
72 1.1 joerg static int pre_I(DECL_ARGS);
73 1.1 joerg static int pre_IP(DECL_ARGS);
74 1.8.2.1 yamt static int pre_OP(DECL_ARGS);
75 1.8.2.2 yamt static int pre_PD(DECL_ARGS);
76 1.1 joerg static int pre_PP(DECL_ARGS);
77 1.1 joerg static int pre_RS(DECL_ARGS);
78 1.1 joerg static int pre_SH(DECL_ARGS);
79 1.1 joerg static int pre_SS(DECL_ARGS);
80 1.1 joerg static int pre_TP(DECL_ARGS);
81 1.8.2.2 yamt static int pre_UR(DECL_ARGS);
82 1.8.2.1 yamt static int pre_alternate(DECL_ARGS);
83 1.8.2.1 yamt static int pre_ft(DECL_ARGS);
84 1.1 joerg static int pre_ign(DECL_ARGS);
85 1.5 joerg static int pre_in(DECL_ARGS);
86 1.5 joerg static int pre_literal(DECL_ARGS);
87 1.1 joerg static int pre_sp(DECL_ARGS);
88 1.1 joerg
89 1.1 joerg static void post_IP(DECL_ARGS);
90 1.1 joerg static void post_HP(DECL_ARGS);
91 1.1 joerg static void post_RS(DECL_ARGS);
92 1.1 joerg static void post_SH(DECL_ARGS);
93 1.1 joerg static void post_SS(DECL_ARGS);
94 1.1 joerg static void post_TP(DECL_ARGS);
95 1.8.2.2 yamt static void post_UR(DECL_ARGS);
96 1.1 joerg
97 1.1 joerg static const struct termact termacts[MAN_MAX] = {
98 1.5 joerg { pre_sp, NULL, MAN_NOTEXT }, /* br */
99 1.2 joerg { NULL, NULL, 0 }, /* TH */
100 1.2 joerg { pre_SH, post_SH, 0 }, /* SH */
101 1.2 joerg { pre_SS, post_SS, 0 }, /* SS */
102 1.2 joerg { pre_TP, post_TP, 0 }, /* TP */
103 1.2 joerg { pre_PP, NULL, 0 }, /* LP */
104 1.2 joerg { pre_PP, NULL, 0 }, /* PP */
105 1.2 joerg { pre_PP, NULL, 0 }, /* P */
106 1.2 joerg { pre_IP, post_IP, 0 }, /* IP */
107 1.2 joerg { pre_HP, post_HP, 0 }, /* HP */
108 1.2 joerg { NULL, NULL, 0 }, /* SM */
109 1.2 joerg { pre_B, NULL, 0 }, /* SB */
110 1.6 joerg { pre_alternate, NULL, 0 }, /* BI */
111 1.6 joerg { pre_alternate, NULL, 0 }, /* IB */
112 1.6 joerg { pre_alternate, NULL, 0 }, /* BR */
113 1.6 joerg { pre_alternate, NULL, 0 }, /* RB */
114 1.2 joerg { NULL, NULL, 0 }, /* R */
115 1.2 joerg { pre_B, NULL, 0 }, /* B */
116 1.2 joerg { pre_I, NULL, 0 }, /* I */
117 1.6 joerg { pre_alternate, NULL, 0 }, /* IR */
118 1.6 joerg { pre_alternate, NULL, 0 }, /* RI */
119 1.7 joerg { pre_ign, NULL, MAN_NOTEXT }, /* na */
120 1.2 joerg { pre_sp, NULL, MAN_NOTEXT }, /* sp */
121 1.5 joerg { pre_literal, NULL, 0 }, /* nf */
122 1.5 joerg { pre_literal, NULL, 0 }, /* fi */
123 1.2 joerg { NULL, NULL, 0 }, /* RE */
124 1.2 joerg { pre_RS, post_RS, 0 }, /* RS */
125 1.2 joerg { pre_ign, NULL, 0 }, /* DT */
126 1.2 joerg { pre_ign, NULL, 0 }, /* UC */
127 1.8.2.2 yamt { pre_PD, NULL, MAN_NOTEXT }, /* PD */
128 1.2 joerg { pre_ign, NULL, 0 }, /* AT */
129 1.5 joerg { pre_in, NULL, MAN_NOTEXT }, /* in */
130 1.6 joerg { pre_ft, NULL, MAN_NOTEXT }, /* ft */
131 1.8.2.1 yamt { pre_OP, NULL, 0 }, /* OP */
132 1.8.2.2 yamt { pre_literal, NULL, 0 }, /* EX */
133 1.8.2.2 yamt { pre_literal, NULL, 0 }, /* EE */
134 1.8.2.2 yamt { pre_UR, post_UR, 0 }, /* UR */
135 1.8.2.2 yamt { NULL, NULL, 0 }, /* UE */
136 1.1 joerg };
137 1.1 joerg
138 1.1 joerg
139 1.1 joerg
140 1.1 joerg void
141 1.1 joerg terminal_man(void *arg, const struct man *man)
142 1.1 joerg {
143 1.1 joerg struct termp *p;
144 1.1 joerg const struct man_node *n;
145 1.8.2.2 yamt const struct man_meta *meta;
146 1.1 joerg struct mtermp mt;
147 1.1 joerg
148 1.1 joerg p = (struct termp *)arg;
149 1.1 joerg
150 1.8.2.1 yamt if (0 == p->defindent)
151 1.8.2.1 yamt p->defindent = 7;
152 1.8.2.1 yamt
153 1.2 joerg p->overstep = 0;
154 1.2 joerg p->maxrmargin = p->defrmargin;
155 1.4 joerg p->tabwidth = term_len(p, 5);
156 1.2 joerg
157 1.1 joerg if (NULL == p->symtab)
158 1.8 joerg p->symtab = mchars_alloc();
159 1.1 joerg
160 1.1 joerg n = man_node(man);
161 1.8.2.2 yamt meta = man_meta(man);
162 1.1 joerg
163 1.8.2.2 yamt term_begin(p, print_man_head, print_man_foot, meta);
164 1.1 joerg p->flags |= TERMP_NOSPACE;
165 1.1 joerg
166 1.8 joerg memset(&mt, 0, sizeof(struct mtermp));
167 1.8 joerg
168 1.8.2.1 yamt mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
169 1.8.2.1 yamt mt.offset = term_len(p, p->defindent);
170 1.8.2.2 yamt mt.pardist = 1;
171 1.1 joerg
172 1.1 joerg if (n->child)
173 1.8.2.2 yamt print_man_nodelist(p, &mt, n->child, meta);
174 1.2 joerg
175 1.2 joerg term_end(p);
176 1.1 joerg }
177 1.1 joerg
178 1.1 joerg
179 1.4 joerg static size_t
180 1.4 joerg a2height(const struct termp *p, const char *cp)
181 1.1 joerg {
182 1.1 joerg struct roffsu su;
183 1.1 joerg
184 1.4 joerg if ( ! a2roffsu(cp, &su, SCALE_VS))
185 1.8 joerg SCALE_VS_INIT(&su, atoi(cp));
186 1.1 joerg
187 1.4 joerg return(term_vspan(p, &su));
188 1.1 joerg }
189 1.1 joerg
190 1.1 joerg
191 1.1 joerg static int
192 1.4 joerg a2width(const struct termp *p, const char *cp)
193 1.1 joerg {
194 1.1 joerg struct roffsu su;
195 1.1 joerg
196 1.4 joerg if ( ! a2roffsu(cp, &su, SCALE_BU))
197 1.1 joerg return(-1);
198 1.1 joerg
199 1.4 joerg return((int)term_hspan(p, &su));
200 1.1 joerg }
201 1.1 joerg
202 1.8 joerg /*
203 1.8 joerg * Printing leading vertical space before a block.
204 1.8 joerg * This is used for the paragraph macros.
205 1.8 joerg * The rules are pretty simple, since there's very little nesting going
206 1.8 joerg * on here. Basically, if we're the first within another block (SS/SH),
207 1.8 joerg * then don't emit vertical space. If we are (RS), then do. If not the
208 1.8 joerg * first, print it.
209 1.8 joerg */
210 1.1 joerg static void
211 1.8.2.2 yamt print_bvspace(struct termp *p, const struct man_node *n, int pardist)
212 1.1 joerg {
213 1.8.2.2 yamt int i;
214 1.8 joerg
215 1.1 joerg term_newln(p);
216 1.1 joerg
217 1.8 joerg if (n->body && n->body->child)
218 1.8 joerg if (MAN_TBL == n->body->child->type)
219 1.8 joerg return;
220 1.7 joerg
221 1.8 joerg if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok)
222 1.8 joerg if (NULL == n->prev)
223 1.8 joerg return;
224 1.1 joerg
225 1.8.2.2 yamt for (i = 0; i < pardist; i++)
226 1.8.2.2 yamt term_vspace(p);
227 1.1 joerg }
228 1.1 joerg
229 1.1 joerg /* ARGSUSED */
230 1.1 joerg static int
231 1.1 joerg pre_ign(DECL_ARGS)
232 1.1 joerg {
233 1.1 joerg
234 1.1 joerg return(0);
235 1.1 joerg }
236 1.1 joerg
237 1.1 joerg
238 1.1 joerg /* ARGSUSED */
239 1.1 joerg static int
240 1.1 joerg pre_I(DECL_ARGS)
241 1.1 joerg {
242 1.1 joerg
243 1.2 joerg term_fontrepl(p, TERMFONT_UNDER);
244 1.1 joerg return(1);
245 1.1 joerg }
246 1.1 joerg
247 1.1 joerg
248 1.1 joerg /* ARGSUSED */
249 1.1 joerg static int
250 1.5 joerg pre_literal(DECL_ARGS)
251 1.1 joerg {
252 1.1 joerg
253 1.5 joerg term_newln(p);
254 1.6 joerg
255 1.8.2.2 yamt if (MAN_nf == n->tok || MAN_EX == n->tok)
256 1.5 joerg mt->fl |= MANT_LITERAL;
257 1.6 joerg else
258 1.5 joerg mt->fl &= ~MANT_LITERAL;
259 1.5 joerg
260 1.8 joerg /*
261 1.8 joerg * Unlike .IP and .TP, .HP does not have a HEAD.
262 1.8 joerg * So in case a second call to term_flushln() is needed,
263 1.8 joerg * indentation has to be set up explicitly.
264 1.8 joerg */
265 1.8 joerg if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
266 1.8 joerg p->offset = p->rmargin;
267 1.8 joerg p->rmargin = p->maxrmargin;
268 1.8.2.2 yamt p->trailspace = 0;
269 1.8.2.2 yamt p->flags &= ~TERMP_NOBREAK;
270 1.8 joerg p->flags |= TERMP_NOSPACE;
271 1.8 joerg }
272 1.8 joerg
273 1.7 joerg return(0);
274 1.1 joerg }
275 1.1 joerg
276 1.1 joerg /* ARGSUSED */
277 1.1 joerg static int
278 1.8.2.2 yamt pre_PD(DECL_ARGS)
279 1.8.2.2 yamt {
280 1.8.2.2 yamt
281 1.8.2.2 yamt n = n->child;
282 1.8.2.2 yamt if (0 == n) {
283 1.8.2.2 yamt mt->pardist = 1;
284 1.8.2.2 yamt return(0);
285 1.8.2.2 yamt }
286 1.8.2.2 yamt assert(MAN_TEXT == n->type);
287 1.8.2.2 yamt mt->pardist = atoi(n->string);
288 1.8.2.2 yamt return(0);
289 1.8.2.2 yamt }
290 1.8.2.2 yamt
291 1.8.2.2 yamt /* ARGSUSED */
292 1.8.2.2 yamt static int
293 1.6 joerg pre_alternate(DECL_ARGS)
294 1.1 joerg {
295 1.6 joerg enum termfont font[2];
296 1.6 joerg const struct man_node *nn;
297 1.6 joerg int savelit, i;
298 1.1 joerg
299 1.6 joerg switch (n->tok) {
300 1.6 joerg case (MAN_RB):
301 1.6 joerg font[0] = TERMFONT_NONE;
302 1.6 joerg font[1] = TERMFONT_BOLD;
303 1.6 joerg break;
304 1.6 joerg case (MAN_RI):
305 1.6 joerg font[0] = TERMFONT_NONE;
306 1.6 joerg font[1] = TERMFONT_UNDER;
307 1.6 joerg break;
308 1.6 joerg case (MAN_BR):
309 1.6 joerg font[0] = TERMFONT_BOLD;
310 1.6 joerg font[1] = TERMFONT_NONE;
311 1.6 joerg break;
312 1.6 joerg case (MAN_BI):
313 1.6 joerg font[0] = TERMFONT_BOLD;
314 1.6 joerg font[1] = TERMFONT_UNDER;
315 1.6 joerg break;
316 1.6 joerg case (MAN_IR):
317 1.6 joerg font[0] = TERMFONT_UNDER;
318 1.6 joerg font[1] = TERMFONT_NONE;
319 1.6 joerg break;
320 1.6 joerg case (MAN_IB):
321 1.6 joerg font[0] = TERMFONT_UNDER;
322 1.6 joerg font[1] = TERMFONT_BOLD;
323 1.6 joerg break;
324 1.6 joerg default:
325 1.6 joerg abort();
326 1.6 joerg }
327 1.1 joerg
328 1.6 joerg savelit = MANT_LITERAL & mt->fl;
329 1.6 joerg mt->fl &= ~MANT_LITERAL;
330 1.1 joerg
331 1.6 joerg for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
332 1.6 joerg term_fontrepl(p, font[i]);
333 1.6 joerg if (savelit && NULL == nn->next)
334 1.6 joerg mt->fl |= MANT_LITERAL;
335 1.8.2.2 yamt print_man_node(p, mt, nn, meta);
336 1.6 joerg if (nn->next)
337 1.6 joerg p->flags |= TERMP_NOSPACE;
338 1.1 joerg }
339 1.6 joerg
340 1.1 joerg return(0);
341 1.1 joerg }
342 1.1 joerg
343 1.1 joerg /* ARGSUSED */
344 1.1 joerg static int
345 1.6 joerg pre_B(DECL_ARGS)
346 1.1 joerg {
347 1.1 joerg
348 1.6 joerg term_fontrepl(p, TERMFONT_BOLD);
349 1.6 joerg return(1);
350 1.1 joerg }
351 1.1 joerg
352 1.1 joerg /* ARGSUSED */
353 1.1 joerg static int
354 1.8.2.1 yamt pre_OP(DECL_ARGS)
355 1.8.2.1 yamt {
356 1.8.2.1 yamt
357 1.8.2.1 yamt term_word(p, "[");
358 1.8.2.1 yamt p->flags |= TERMP_NOSPACE;
359 1.8.2.1 yamt
360 1.8.2.1 yamt if (NULL != (n = n->child)) {
361 1.8.2.1 yamt term_fontrepl(p, TERMFONT_BOLD);
362 1.8.2.1 yamt term_word(p, n->string);
363 1.8.2.1 yamt }
364 1.8.2.1 yamt if (NULL != n && NULL != n->next) {
365 1.8.2.1 yamt term_fontrepl(p, TERMFONT_UNDER);
366 1.8.2.1 yamt term_word(p, n->next->string);
367 1.8.2.1 yamt }
368 1.8.2.1 yamt
369 1.8.2.1 yamt term_fontrepl(p, TERMFONT_NONE);
370 1.8.2.1 yamt p->flags |= TERMP_NOSPACE;
371 1.8.2.1 yamt term_word(p, "]");
372 1.8.2.1 yamt return(0);
373 1.8.2.1 yamt }
374 1.8.2.1 yamt
375 1.8.2.1 yamt /* ARGSUSED */
376 1.8.2.1 yamt static int
377 1.6 joerg pre_ft(DECL_ARGS)
378 1.1 joerg {
379 1.6 joerg const char *cp;
380 1.1 joerg
381 1.6 joerg if (NULL == n->child) {
382 1.6 joerg term_fontlast(p);
383 1.6 joerg return(0);
384 1.6 joerg }
385 1.1 joerg
386 1.6 joerg cp = n->child->string;
387 1.6 joerg switch (*cp) {
388 1.6 joerg case ('4'):
389 1.6 joerg /* FALLTHROUGH */
390 1.6 joerg case ('3'):
391 1.6 joerg /* FALLTHROUGH */
392 1.6 joerg case ('B'):
393 1.6 joerg term_fontrepl(p, TERMFONT_BOLD);
394 1.6 joerg break;
395 1.6 joerg case ('2'):
396 1.6 joerg /* FALLTHROUGH */
397 1.6 joerg case ('I'):
398 1.6 joerg term_fontrepl(p, TERMFONT_UNDER);
399 1.6 joerg break;
400 1.6 joerg case ('P'):
401 1.6 joerg term_fontlast(p);
402 1.6 joerg break;
403 1.6 joerg case ('1'):
404 1.6 joerg /* FALLTHROUGH */
405 1.6 joerg case ('C'):
406 1.6 joerg /* FALLTHROUGH */
407 1.6 joerg case ('R'):
408 1.6 joerg term_fontrepl(p, TERMFONT_NONE);
409 1.6 joerg break;
410 1.6 joerg default:
411 1.6 joerg break;
412 1.1 joerg }
413 1.1 joerg return(0);
414 1.1 joerg }
415 1.1 joerg
416 1.1 joerg /* ARGSUSED */
417 1.1 joerg static int
418 1.5 joerg pre_in(DECL_ARGS)
419 1.1 joerg {
420 1.5 joerg int len, less;
421 1.5 joerg size_t v;
422 1.5 joerg const char *cp;
423 1.5 joerg
424 1.5 joerg term_newln(p);
425 1.5 joerg
426 1.5 joerg if (NULL == n->child) {
427 1.5 joerg p->offset = mt->offset;
428 1.5 joerg return(0);
429 1.5 joerg }
430 1.5 joerg
431 1.5 joerg cp = n->child->string;
432 1.5 joerg less = 0;
433 1.5 joerg
434 1.5 joerg if ('-' == *cp)
435 1.5 joerg less = -1;
436 1.5 joerg else if ('+' == *cp)
437 1.5 joerg less = 1;
438 1.5 joerg else
439 1.5 joerg cp--;
440 1.5 joerg
441 1.5 joerg if ((len = a2width(p, ++cp)) < 0)
442 1.5 joerg return(0);
443 1.1 joerg
444 1.5 joerg v = (size_t)len;
445 1.1 joerg
446 1.5 joerg if (less < 0)
447 1.5 joerg p->offset -= p->offset > v ? v : p->offset;
448 1.5 joerg else if (less > 0)
449 1.5 joerg p->offset += v;
450 1.5 joerg else
451 1.5 joerg p->offset = v;
452 1.1 joerg
453 1.7 joerg /* Don't let this creep beyond the right margin. */
454 1.7 joerg
455 1.7 joerg if (p->offset > p->rmargin)
456 1.7 joerg p->offset = p->rmargin;
457 1.7 joerg
458 1.1 joerg return(0);
459 1.1 joerg }
460 1.1 joerg
461 1.1 joerg
462 1.1 joerg /* ARGSUSED */
463 1.1 joerg static int
464 1.5 joerg pre_sp(DECL_ARGS)
465 1.1 joerg {
466 1.8.2.2 yamt char *s;
467 1.5 joerg size_t i, len;
468 1.8.2.2 yamt int neg;
469 1.5 joerg
470 1.8 joerg if ((NULL == n->prev && n->parent)) {
471 1.8.2.2 yamt switch (n->parent->tok) {
472 1.8.2.2 yamt case (MAN_SH):
473 1.8.2.2 yamt /* FALLTHROUGH */
474 1.8.2.2 yamt case (MAN_SS):
475 1.8.2.2 yamt /* FALLTHROUGH */
476 1.8.2.2 yamt case (MAN_PP):
477 1.8.2.2 yamt /* FALLTHROUGH */
478 1.8.2.2 yamt case (MAN_LP):
479 1.8.2.2 yamt /* FALLTHROUGH */
480 1.8.2.2 yamt case (MAN_P):
481 1.8.2.2 yamt /* FALLTHROUGH */
482 1.8 joerg return(0);
483 1.8.2.2 yamt default:
484 1.8.2.2 yamt break;
485 1.8.2.2 yamt }
486 1.8 joerg }
487 1.8 joerg
488 1.8.2.2 yamt neg = 0;
489 1.5 joerg switch (n->tok) {
490 1.5 joerg case (MAN_br):
491 1.5 joerg len = 0;
492 1.5 joerg break;
493 1.5 joerg default:
494 1.8.2.2 yamt if (NULL == n->child) {
495 1.8.2.2 yamt len = 1;
496 1.8.2.2 yamt break;
497 1.8.2.2 yamt }
498 1.8.2.2 yamt s = n->child->string;
499 1.8.2.2 yamt if ('-' == *s) {
500 1.8.2.2 yamt neg = 1;
501 1.8.2.2 yamt s++;
502 1.8.2.2 yamt }
503 1.8.2.2 yamt len = a2height(p, s);
504 1.5 joerg break;
505 1.5 joerg }
506 1.5 joerg
507 1.5 joerg if (0 == len)
508 1.5 joerg term_newln(p);
509 1.8.2.2 yamt else if (neg)
510 1.8.2.2 yamt p->skipvsp += len;
511 1.8.2.2 yamt else
512 1.8.2.2 yamt for (i = 0; i < len; i++)
513 1.8.2.2 yamt term_vspace(p);
514 1.1 joerg
515 1.1 joerg return(0);
516 1.1 joerg }
517 1.1 joerg
518 1.1 joerg
519 1.1 joerg /* ARGSUSED */
520 1.1 joerg static int
521 1.1 joerg pre_HP(DECL_ARGS)
522 1.1 joerg {
523 1.8 joerg size_t len, one;
524 1.1 joerg int ival;
525 1.1 joerg const struct man_node *nn;
526 1.1 joerg
527 1.1 joerg switch (n->type) {
528 1.1 joerg case (MAN_BLOCK):
529 1.8.2.2 yamt print_bvspace(p, n, mt->pardist);
530 1.1 joerg return(1);
531 1.1 joerg case (MAN_BODY):
532 1.1 joerg break;
533 1.1 joerg default:
534 1.1 joerg return(0);
535 1.1 joerg }
536 1.1 joerg
537 1.8.2.2 yamt if ( ! (MANT_LITERAL & mt->fl)) {
538 1.8.2.2 yamt p->flags |= TERMP_NOBREAK;
539 1.8.2.2 yamt p->trailspace = 2;
540 1.8.2.2 yamt }
541 1.8.2.2 yamt
542 1.8 joerg len = mt->lmargin[mt->lmargincur];
543 1.1 joerg ival = -1;
544 1.1 joerg
545 1.1 joerg /* Calculate offset. */
546 1.1 joerg
547 1.1 joerg if (NULL != (nn = n->parent->head->child))
548 1.4 joerg if ((ival = a2width(p, nn->string)) >= 0)
549 1.1 joerg len = (size_t)ival;
550 1.1 joerg
551 1.8 joerg one = term_len(p, 1);
552 1.8 joerg if (len < one)
553 1.8 joerg len = one;
554 1.1 joerg
555 1.1 joerg p->offset = mt->offset;
556 1.1 joerg p->rmargin = mt->offset + len;
557 1.1 joerg
558 1.1 joerg if (ival >= 0)
559 1.8 joerg mt->lmargin[mt->lmargincur] = (size_t)ival;
560 1.1 joerg
561 1.1 joerg return(1);
562 1.1 joerg }
563 1.1 joerg
564 1.1 joerg
565 1.1 joerg /* ARGSUSED */
566 1.1 joerg static void
567 1.1 joerg post_HP(DECL_ARGS)
568 1.1 joerg {
569 1.1 joerg
570 1.1 joerg switch (n->type) {
571 1.1 joerg case (MAN_BODY):
572 1.8.2.2 yamt term_newln(p);
573 1.1 joerg p->flags &= ~TERMP_NOBREAK;
574 1.8.2.2 yamt p->trailspace = 0;
575 1.1 joerg p->offset = mt->offset;
576 1.1 joerg p->rmargin = p->maxrmargin;
577 1.1 joerg break;
578 1.1 joerg default:
579 1.1 joerg break;
580 1.1 joerg }
581 1.1 joerg }
582 1.1 joerg
583 1.1 joerg
584 1.1 joerg /* ARGSUSED */
585 1.1 joerg static int
586 1.1 joerg pre_PP(DECL_ARGS)
587 1.1 joerg {
588 1.1 joerg
589 1.1 joerg switch (n->type) {
590 1.1 joerg case (MAN_BLOCK):
591 1.8.2.1 yamt mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
592 1.8.2.2 yamt print_bvspace(p, n, mt->pardist);
593 1.1 joerg break;
594 1.1 joerg default:
595 1.1 joerg p->offset = mt->offset;
596 1.1 joerg break;
597 1.1 joerg }
598 1.1 joerg
599 1.6 joerg return(MAN_HEAD != n->type);
600 1.1 joerg }
601 1.1 joerg
602 1.1 joerg
603 1.1 joerg /* ARGSUSED */
604 1.1 joerg static int
605 1.1 joerg pre_IP(DECL_ARGS)
606 1.1 joerg {
607 1.1 joerg const struct man_node *nn;
608 1.1 joerg size_t len;
609 1.6 joerg int savelit, ival;
610 1.1 joerg
611 1.1 joerg switch (n->type) {
612 1.1 joerg case (MAN_BODY):
613 1.1 joerg p->flags |= TERMP_NOSPACE;
614 1.1 joerg break;
615 1.1 joerg case (MAN_HEAD):
616 1.1 joerg p->flags |= TERMP_NOBREAK;
617 1.8.2.2 yamt p->trailspace = 1;
618 1.1 joerg break;
619 1.1 joerg case (MAN_BLOCK):
620 1.8.2.2 yamt print_bvspace(p, n, mt->pardist);
621 1.1 joerg /* FALLTHROUGH */
622 1.1 joerg default:
623 1.1 joerg return(1);
624 1.1 joerg }
625 1.1 joerg
626 1.8 joerg len = mt->lmargin[mt->lmargincur];
627 1.1 joerg ival = -1;
628 1.1 joerg
629 1.6 joerg /* Calculate the offset from the optional second argument. */
630 1.1 joerg if (NULL != (nn = n->parent->head->child))
631 1.6 joerg if (NULL != (nn = nn->next))
632 1.4 joerg if ((ival = a2width(p, nn->string)) >= 0)
633 1.1 joerg len = (size_t)ival;
634 1.1 joerg
635 1.1 joerg switch (n->type) {
636 1.1 joerg case (MAN_HEAD):
637 1.1 joerg /* Handle zero-width lengths. */
638 1.1 joerg if (0 == len)
639 1.4 joerg len = term_len(p, 1);
640 1.1 joerg
641 1.1 joerg p->offset = mt->offset;
642 1.1 joerg p->rmargin = mt->offset + len;
643 1.1 joerg if (ival < 0)
644 1.1 joerg break;
645 1.1 joerg
646 1.1 joerg /* Set the saved left-margin. */
647 1.8 joerg mt->lmargin[mt->lmargincur] = (size_t)ival;
648 1.1 joerg
649 1.6 joerg savelit = MANT_LITERAL & mt->fl;
650 1.6 joerg mt->fl &= ~MANT_LITERAL;
651 1.6 joerg
652 1.6 joerg if (n->child)
653 1.8.2.2 yamt print_man_node(p, mt, n->child, meta);
654 1.6 joerg
655 1.6 joerg if (savelit)
656 1.6 joerg mt->fl |= MANT_LITERAL;
657 1.6 joerg
658 1.1 joerg return(0);
659 1.1 joerg case (MAN_BODY):
660 1.1 joerg p->offset = mt->offset + len;
661 1.1 joerg p->rmargin = p->maxrmargin;
662 1.1 joerg break;
663 1.1 joerg default:
664 1.1 joerg break;
665 1.1 joerg }
666 1.1 joerg
667 1.1 joerg return(1);
668 1.1 joerg }
669 1.1 joerg
670 1.1 joerg
671 1.1 joerg /* ARGSUSED */
672 1.1 joerg static void
673 1.1 joerg post_IP(DECL_ARGS)
674 1.1 joerg {
675 1.1 joerg
676 1.1 joerg switch (n->type) {
677 1.1 joerg case (MAN_HEAD):
678 1.1 joerg term_flushln(p);
679 1.1 joerg p->flags &= ~TERMP_NOBREAK;
680 1.8.2.2 yamt p->trailspace = 0;
681 1.1 joerg p->rmargin = p->maxrmargin;
682 1.1 joerg break;
683 1.1 joerg case (MAN_BODY):
684 1.6 joerg term_newln(p);
685 1.8.2.2 yamt p->offset = mt->offset;
686 1.1 joerg break;
687 1.1 joerg default:
688 1.1 joerg break;
689 1.1 joerg }
690 1.1 joerg }
691 1.1 joerg
692 1.1 joerg
693 1.1 joerg /* ARGSUSED */
694 1.1 joerg static int
695 1.1 joerg pre_TP(DECL_ARGS)
696 1.1 joerg {
697 1.1 joerg const struct man_node *nn;
698 1.1 joerg size_t len;
699 1.6 joerg int savelit, ival;
700 1.1 joerg
701 1.1 joerg switch (n->type) {
702 1.1 joerg case (MAN_HEAD):
703 1.1 joerg p->flags |= TERMP_NOBREAK;
704 1.8.2.2 yamt p->trailspace = 1;
705 1.1 joerg break;
706 1.1 joerg case (MAN_BODY):
707 1.1 joerg p->flags |= TERMP_NOSPACE;
708 1.1 joerg break;
709 1.1 joerg case (MAN_BLOCK):
710 1.8.2.2 yamt print_bvspace(p, n, mt->pardist);
711 1.1 joerg /* FALLTHROUGH */
712 1.1 joerg default:
713 1.1 joerg return(1);
714 1.1 joerg }
715 1.1 joerg
716 1.8 joerg len = (size_t)mt->lmargin[mt->lmargincur];
717 1.1 joerg ival = -1;
718 1.1 joerg
719 1.1 joerg /* Calculate offset. */
720 1.1 joerg
721 1.8 joerg if (NULL != (nn = n->parent->head->child))
722 1.8 joerg if (nn->string && nn->parent->line == nn->line)
723 1.4 joerg if ((ival = a2width(p, nn->string)) >= 0)
724 1.1 joerg len = (size_t)ival;
725 1.1 joerg
726 1.1 joerg switch (n->type) {
727 1.1 joerg case (MAN_HEAD):
728 1.1 joerg /* Handle zero-length properly. */
729 1.1 joerg if (0 == len)
730 1.4 joerg len = term_len(p, 1);
731 1.1 joerg
732 1.1 joerg p->offset = mt->offset;
733 1.1 joerg p->rmargin = mt->offset + len;
734 1.1 joerg
735 1.6 joerg savelit = MANT_LITERAL & mt->fl;
736 1.6 joerg mt->fl &= ~MANT_LITERAL;
737 1.6 joerg
738 1.1 joerg /* Don't print same-line elements. */
739 1.6 joerg for (nn = n->child; nn; nn = nn->next)
740 1.1 joerg if (nn->line > n->line)
741 1.8.2.2 yamt print_man_node(p, mt, nn, meta);
742 1.1 joerg
743 1.6 joerg if (savelit)
744 1.6 joerg mt->fl |= MANT_LITERAL;
745 1.1 joerg if (ival >= 0)
746 1.8 joerg mt->lmargin[mt->lmargincur] = (size_t)ival;
747 1.1 joerg
748 1.1 joerg return(0);
749 1.1 joerg case (MAN_BODY):
750 1.1 joerg p->offset = mt->offset + len;
751 1.1 joerg p->rmargin = p->maxrmargin;
752 1.8.2.2 yamt p->trailspace = 0;
753 1.8.2.2 yamt p->flags &= ~TERMP_NOBREAK;
754 1.1 joerg break;
755 1.1 joerg default:
756 1.1 joerg break;
757 1.1 joerg }
758 1.1 joerg
759 1.1 joerg return(1);
760 1.1 joerg }
761 1.1 joerg
762 1.1 joerg
763 1.1 joerg /* ARGSUSED */
764 1.1 joerg static void
765 1.1 joerg post_TP(DECL_ARGS)
766 1.1 joerg {
767 1.1 joerg
768 1.1 joerg switch (n->type) {
769 1.1 joerg case (MAN_HEAD):
770 1.1 joerg term_flushln(p);
771 1.1 joerg break;
772 1.1 joerg case (MAN_BODY):
773 1.6 joerg term_newln(p);
774 1.8.2.2 yamt p->offset = mt->offset;
775 1.1 joerg break;
776 1.1 joerg default:
777 1.1 joerg break;
778 1.1 joerg }
779 1.1 joerg }
780 1.1 joerg
781 1.1 joerg
782 1.1 joerg /* ARGSUSED */
783 1.1 joerg static int
784 1.1 joerg pre_SS(DECL_ARGS)
785 1.1 joerg {
786 1.8.2.2 yamt int i;
787 1.1 joerg
788 1.1 joerg switch (n->type) {
789 1.1 joerg case (MAN_BLOCK):
790 1.8 joerg mt->fl &= ~MANT_LITERAL;
791 1.8.2.1 yamt mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
792 1.8.2.1 yamt mt->offset = term_len(p, p->defindent);
793 1.1 joerg /* If following a prior empty `SS', no vspace. */
794 1.1 joerg if (n->prev && MAN_SS == n->prev->tok)
795 1.1 joerg if (NULL == n->prev->body->child)
796 1.1 joerg break;
797 1.1 joerg if (NULL == n->prev)
798 1.1 joerg break;
799 1.8.2.2 yamt for (i = 0; i < mt->pardist; i++)
800 1.8.2.2 yamt term_vspace(p);
801 1.1 joerg break;
802 1.1 joerg case (MAN_HEAD):
803 1.2 joerg term_fontrepl(p, TERMFONT_BOLD);
804 1.8.2.2 yamt p->offset = term_len(p, 3);
805 1.1 joerg break;
806 1.1 joerg case (MAN_BODY):
807 1.1 joerg p->offset = mt->offset;
808 1.1 joerg break;
809 1.1 joerg default:
810 1.1 joerg break;
811 1.1 joerg }
812 1.1 joerg
813 1.1 joerg return(1);
814 1.1 joerg }
815 1.1 joerg
816 1.1 joerg
817 1.1 joerg /* ARGSUSED */
818 1.1 joerg static void
819 1.1 joerg post_SS(DECL_ARGS)
820 1.1 joerg {
821 1.1 joerg
822 1.1 joerg switch (n->type) {
823 1.1 joerg case (MAN_HEAD):
824 1.1 joerg term_newln(p);
825 1.1 joerg break;
826 1.1 joerg case (MAN_BODY):
827 1.1 joerg term_newln(p);
828 1.1 joerg break;
829 1.1 joerg default:
830 1.1 joerg break;
831 1.1 joerg }
832 1.1 joerg }
833 1.1 joerg
834 1.1 joerg
835 1.1 joerg /* ARGSUSED */
836 1.1 joerg static int
837 1.1 joerg pre_SH(DECL_ARGS)
838 1.1 joerg {
839 1.8.2.2 yamt int i;
840 1.1 joerg
841 1.1 joerg switch (n->type) {
842 1.1 joerg case (MAN_BLOCK):
843 1.8 joerg mt->fl &= ~MANT_LITERAL;
844 1.8.2.1 yamt mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
845 1.8.2.1 yamt mt->offset = term_len(p, p->defindent);
846 1.1 joerg /* If following a prior empty `SH', no vspace. */
847 1.1 joerg if (n->prev && MAN_SH == n->prev->tok)
848 1.1 joerg if (NULL == n->prev->body->child)
849 1.1 joerg break;
850 1.2 joerg /* If the first macro, no vspae. */
851 1.2 joerg if (NULL == n->prev)
852 1.2 joerg break;
853 1.8.2.2 yamt for (i = 0; i < mt->pardist; i++)
854 1.8.2.2 yamt term_vspace(p);
855 1.1 joerg break;
856 1.1 joerg case (MAN_HEAD):
857 1.2 joerg term_fontrepl(p, TERMFONT_BOLD);
858 1.1 joerg p->offset = 0;
859 1.1 joerg break;
860 1.1 joerg case (MAN_BODY):
861 1.1 joerg p->offset = mt->offset;
862 1.1 joerg break;
863 1.1 joerg default:
864 1.1 joerg break;
865 1.1 joerg }
866 1.1 joerg
867 1.1 joerg return(1);
868 1.1 joerg }
869 1.1 joerg
870 1.1 joerg
871 1.1 joerg /* ARGSUSED */
872 1.1 joerg static void
873 1.1 joerg post_SH(DECL_ARGS)
874 1.1 joerg {
875 1.1 joerg
876 1.1 joerg switch (n->type) {
877 1.1 joerg case (MAN_HEAD):
878 1.1 joerg term_newln(p);
879 1.1 joerg break;
880 1.1 joerg case (MAN_BODY):
881 1.1 joerg term_newln(p);
882 1.1 joerg break;
883 1.1 joerg default:
884 1.1 joerg break;
885 1.1 joerg }
886 1.1 joerg }
887 1.1 joerg
888 1.1 joerg /* ARGSUSED */
889 1.1 joerg static int
890 1.1 joerg pre_RS(DECL_ARGS)
891 1.1 joerg {
892 1.8 joerg int ival;
893 1.8 joerg size_t sz;
894 1.1 joerg
895 1.1 joerg switch (n->type) {
896 1.1 joerg case (MAN_BLOCK):
897 1.1 joerg term_newln(p);
898 1.1 joerg return(1);
899 1.1 joerg case (MAN_HEAD):
900 1.1 joerg return(0);
901 1.1 joerg default:
902 1.1 joerg break;
903 1.1 joerg }
904 1.1 joerg
905 1.8.2.1 yamt sz = term_len(p, p->defindent);
906 1.8 joerg
907 1.8 joerg if (NULL != (n = n->parent->head->child))
908 1.8 joerg if ((ival = a2width(p, n->string)) >= 0)
909 1.8 joerg sz = (size_t)ival;
910 1.1 joerg
911 1.8 joerg mt->offset += sz;
912 1.8 joerg p->rmargin = p->maxrmargin;
913 1.8 joerg p->offset = mt->offset < p->rmargin ? mt->offset : p->rmargin;
914 1.1 joerg
915 1.8 joerg if (++mt->lmarginsz < MAXMARGINS)
916 1.8 joerg mt->lmargincur = mt->lmarginsz;
917 1.1 joerg
918 1.8 joerg mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1];
919 1.1 joerg return(1);
920 1.1 joerg }
921 1.1 joerg
922 1.1 joerg /* ARGSUSED */
923 1.1 joerg static void
924 1.1 joerg post_RS(DECL_ARGS)
925 1.1 joerg {
926 1.8 joerg int ival;
927 1.8 joerg size_t sz;
928 1.1 joerg
929 1.1 joerg switch (n->type) {
930 1.1 joerg case (MAN_BLOCK):
931 1.8 joerg return;
932 1.2 joerg case (MAN_HEAD):
933 1.8 joerg return;
934 1.1 joerg default:
935 1.1 joerg term_newln(p);
936 1.1 joerg break;
937 1.1 joerg }
938 1.8 joerg
939 1.8.2.1 yamt sz = term_len(p, p->defindent);
940 1.8 joerg
941 1.8 joerg if (NULL != (n = n->parent->head->child))
942 1.8 joerg if ((ival = a2width(p, n->string)) >= 0)
943 1.8 joerg sz = (size_t)ival;
944 1.8 joerg
945 1.8 joerg mt->offset = mt->offset < sz ? 0 : mt->offset - sz;
946 1.8 joerg p->offset = mt->offset;
947 1.8 joerg
948 1.8 joerg if (--mt->lmarginsz < MAXMARGINS)
949 1.8 joerg mt->lmargincur = mt->lmarginsz;
950 1.1 joerg }
951 1.1 joerg
952 1.8.2.2 yamt /* ARGSUSED */
953 1.8.2.2 yamt static int
954 1.8.2.2 yamt pre_UR(DECL_ARGS)
955 1.8.2.2 yamt {
956 1.8.2.2 yamt
957 1.8.2.2 yamt return (MAN_HEAD != n->type);
958 1.8.2.2 yamt }
959 1.8.2.2 yamt
960 1.8.2.2 yamt /* ARGSUSED */
961 1.8.2.2 yamt static void
962 1.8.2.2 yamt post_UR(DECL_ARGS)
963 1.8.2.2 yamt {
964 1.8.2.2 yamt
965 1.8.2.2 yamt if (MAN_BLOCK != n->type)
966 1.8.2.2 yamt return;
967 1.8.2.2 yamt
968 1.8.2.2 yamt term_word(p, "<");
969 1.8.2.2 yamt p->flags |= TERMP_NOSPACE;
970 1.8.2.2 yamt
971 1.8.2.2 yamt if (NULL != n->child->child)
972 1.8.2.2 yamt print_man_node(p, mt, n->child->child, meta);
973 1.8.2.2 yamt
974 1.8.2.2 yamt p->flags |= TERMP_NOSPACE;
975 1.8.2.2 yamt term_word(p, ">");
976 1.8.2.2 yamt }
977 1.8.2.2 yamt
978 1.1 joerg static void
979 1.2 joerg print_man_node(DECL_ARGS)
980 1.1 joerg {
981 1.2 joerg size_t rm, rmax;
982 1.2 joerg int c;
983 1.1 joerg
984 1.1 joerg switch (n->type) {
985 1.1 joerg case(MAN_TEXT):
986 1.7 joerg /*
987 1.7 joerg * If we have a blank line, output a vertical space.
988 1.7 joerg * If we have a space as the first character, break
989 1.7 joerg * before printing the line's data.
990 1.7 joerg */
991 1.7 joerg if ('\0' == *n->string) {
992 1.1 joerg term_vspace(p);
993 1.7 joerg return;
994 1.7 joerg } else if (' ' == *n->string && MAN_LINE & n->flags)
995 1.7 joerg term_newln(p);
996 1.2 joerg
997 1.1 joerg term_word(p, n->string);
998 1.8.2.2 yamt goto out;
999 1.2 joerg
1000 1.7 joerg case (MAN_EQN):
1001 1.8 joerg term_eqn(p, n->eqn);
1002 1.7 joerg return;
1003 1.6 joerg case (MAN_TBL):
1004 1.7 joerg /*
1005 1.7 joerg * Tables are preceded by a newline. Then process a
1006 1.7 joerg * table line, which will cause line termination,
1007 1.7 joerg */
1008 1.6 joerg if (TBL_SPAN_FIRST & n->span->flags)
1009 1.6 joerg term_newln(p);
1010 1.6 joerg term_tbl(p, n->span);
1011 1.7 joerg return;
1012 1.1 joerg default:
1013 1.1 joerg break;
1014 1.1 joerg }
1015 1.1 joerg
1016 1.7 joerg if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
1017 1.7 joerg term_fontrepl(p, TERMFONT_NONE);
1018 1.7 joerg
1019 1.7 joerg c = 1;
1020 1.7 joerg if (termacts[n->tok].pre)
1021 1.8.2.2 yamt c = (*termacts[n->tok].pre)(p, mt, n, meta);
1022 1.7 joerg
1023 1.1 joerg if (c && n->child)
1024 1.8.2.2 yamt print_man_nodelist(p, mt, n->child, meta);
1025 1.1 joerg
1026 1.7 joerg if (termacts[n->tok].post)
1027 1.8.2.2 yamt (*termacts[n->tok].post)(p, mt, n, meta);
1028 1.7 joerg if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
1029 1.7 joerg term_fontrepl(p, TERMFONT_NONE);
1030 1.2 joerg
1031 1.8.2.2 yamt out:
1032 1.8.2.2 yamt /*
1033 1.8.2.2 yamt * If we're in a literal context, make sure that words
1034 1.8.2.2 yamt * together on the same line stay together. This is a
1035 1.8.2.2 yamt * POST-printing call, so we check the NEXT word. Since
1036 1.8.2.2 yamt * -man doesn't have nested macros, we don't need to be
1037 1.8.2.2 yamt * more specific than this.
1038 1.8.2.2 yamt */
1039 1.8.2.2 yamt if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
1040 1.8.2.2 yamt (NULL == n->next || n->next->line > n->line)) {
1041 1.8.2.2 yamt rm = p->rmargin;
1042 1.8.2.2 yamt rmax = p->maxrmargin;
1043 1.8.2.2 yamt p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1044 1.8.2.2 yamt p->flags |= TERMP_NOSPACE;
1045 1.8.2.2 yamt if (NULL != n->string && '\0' != *n->string)
1046 1.8.2.2 yamt term_flushln(p);
1047 1.8.2.2 yamt else
1048 1.8.2.2 yamt term_newln(p);
1049 1.8.2.2 yamt if (rm < rmax && n->parent->tok == MAN_HP) {
1050 1.8.2.2 yamt p->offset = rm;
1051 1.8.2.2 yamt p->rmargin = rmax;
1052 1.8.2.2 yamt } else
1053 1.8.2.2 yamt p->rmargin = rm;
1054 1.8.2.2 yamt p->maxrmargin = rmax;
1055 1.8.2.2 yamt }
1056 1.2 joerg if (MAN_EOS & n->flags)
1057 1.2 joerg p->flags |= TERMP_SENTENCE;
1058 1.1 joerg }
1059 1.1 joerg
1060 1.1 joerg
1061 1.1 joerg static void
1062 1.2 joerg print_man_nodelist(DECL_ARGS)
1063 1.1 joerg {
1064 1.1 joerg
1065 1.8.2.2 yamt print_man_node(p, mt, n, meta);
1066 1.1 joerg if ( ! n->next)
1067 1.1 joerg return;
1068 1.8.2.2 yamt print_man_nodelist(p, mt, n->next, meta);
1069 1.1 joerg }
1070 1.1 joerg
1071 1.1 joerg
1072 1.1 joerg static void
1073 1.2 joerg print_man_foot(struct termp *p, const void *arg)
1074 1.1 joerg {
1075 1.8.2.1 yamt char title[BUFSIZ];
1076 1.8.2.1 yamt size_t datelen;
1077 1.2 joerg const struct man_meta *meta;
1078 1.2 joerg
1079 1.2 joerg meta = (const struct man_meta *)arg;
1080 1.8.2.1 yamt assert(meta->title);
1081 1.8.2.1 yamt assert(meta->msec);
1082 1.8.2.1 yamt assert(meta->date);
1083 1.1 joerg
1084 1.2 joerg term_fontrepl(p, TERMFONT_NONE);
1085 1.1 joerg
1086 1.1 joerg term_vspace(p);
1087 1.8.2.1 yamt
1088 1.8.2.1 yamt /*
1089 1.8.2.1 yamt * Temporary, undocumented option to imitate mdoc(7) output.
1090 1.8.2.1 yamt * In the bottom right corner, use the source instead of
1091 1.8.2.1 yamt * the title.
1092 1.8.2.1 yamt */
1093 1.8.2.1 yamt
1094 1.8.2.1 yamt if ( ! p->mdocstyle) {
1095 1.8.2.1 yamt term_vspace(p);
1096 1.8.2.1 yamt term_vspace(p);
1097 1.8.2.1 yamt snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
1098 1.8.2.1 yamt } else if (meta->source) {
1099 1.8.2.1 yamt strlcpy(title, meta->source, BUFSIZ);
1100 1.8.2.1 yamt } else {
1101 1.8.2.1 yamt title[0] = '\0';
1102 1.8.2.1 yamt }
1103 1.8.2.1 yamt datelen = term_strlen(p, meta->date);
1104 1.8.2.1 yamt
1105 1.8.2.1 yamt /* Bottom left corner: manual source. */
1106 1.1 joerg
1107 1.1 joerg p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1108 1.8.2.2 yamt p->trailspace = 1;
1109 1.1 joerg p->offset = 0;
1110 1.8.2.1 yamt p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
1111 1.6 joerg
1112 1.1 joerg if (meta->source)
1113 1.1 joerg term_word(p, meta->source);
1114 1.1 joerg term_flushln(p);
1115 1.1 joerg
1116 1.8.2.1 yamt /* At the bottom in the middle: manual date. */
1117 1.8.2.1 yamt
1118 1.8 joerg p->flags |= TERMP_NOSPACE;
1119 1.1 joerg p->offset = p->rmargin;
1120 1.8.2.1 yamt p->rmargin = p->maxrmargin - term_strlen(p, title);
1121 1.8.2.1 yamt if (p->offset + datelen >= p->rmargin)
1122 1.8.2.1 yamt p->rmargin = p->offset + datelen;
1123 1.1 joerg
1124 1.7 joerg term_word(p, meta->date);
1125 1.1 joerg term_flushln(p);
1126 1.8.2.1 yamt
1127 1.8.2.1 yamt /* Bottom right corner: manual title and section. */
1128 1.8.2.1 yamt
1129 1.8.2.1 yamt p->flags &= ~TERMP_NOBREAK;
1130 1.8.2.1 yamt p->flags |= TERMP_NOSPACE;
1131 1.8.2.2 yamt p->trailspace = 0;
1132 1.8.2.1 yamt p->offset = p->rmargin;
1133 1.8.2.1 yamt p->rmargin = p->maxrmargin;
1134 1.8.2.1 yamt
1135 1.8.2.1 yamt term_word(p, title);
1136 1.8.2.1 yamt term_flushln(p);
1137 1.1 joerg }
1138 1.1 joerg
1139 1.1 joerg
1140 1.1 joerg static void
1141 1.2 joerg print_man_head(struct termp *p, const void *arg)
1142 1.1 joerg {
1143 1.2 joerg char buf[BUFSIZ], title[BUFSIZ];
1144 1.2 joerg size_t buflen, titlen;
1145 1.8.2.2 yamt const struct man_meta *meta;
1146 1.2 joerg
1147 1.8.2.2 yamt meta = (const struct man_meta *)arg;
1148 1.8.2.2 yamt assert(meta->title);
1149 1.8.2.2 yamt assert(meta->msec);
1150 1.1 joerg
1151 1.8.2.2 yamt if (meta->vol)
1152 1.8.2.2 yamt strlcpy(buf, meta->vol, BUFSIZ);
1153 1.8.2.1 yamt else
1154 1.8.2.1 yamt buf[0] = '\0';
1155 1.4 joerg buflen = term_strlen(p, buf);
1156 1.1 joerg
1157 1.8.2.1 yamt /* Top left corner: manual title and section. */
1158 1.8.2.1 yamt
1159 1.8.2.2 yamt snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
1160 1.4 joerg titlen = term_strlen(p, title);
1161 1.1 joerg
1162 1.8 joerg p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1163 1.8.2.2 yamt p->trailspace = 1;
1164 1.1 joerg p->offset = 0;
1165 1.2 joerg p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
1166 1.4 joerg (p->maxrmargin -
1167 1.4 joerg term_strlen(p, buf) + term_len(p, 1)) / 2 :
1168 1.2 joerg p->maxrmargin - buflen;
1169 1.1 joerg
1170 1.1 joerg term_word(p, title);
1171 1.1 joerg term_flushln(p);
1172 1.1 joerg
1173 1.8.2.1 yamt /* At the top in the middle: manual volume. */
1174 1.8.2.1 yamt
1175 1.8 joerg p->flags |= TERMP_NOSPACE;
1176 1.1 joerg p->offset = p->rmargin;
1177 1.2 joerg p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
1178 1.2 joerg p->maxrmargin - titlen : p->maxrmargin;
1179 1.1 joerg
1180 1.1 joerg term_word(p, buf);
1181 1.1 joerg term_flushln(p);
1182 1.1 joerg
1183 1.8.2.1 yamt /* Top right corner: title and section, again. */
1184 1.8.2.1 yamt
1185 1.1 joerg p->flags &= ~TERMP_NOBREAK;
1186 1.8.2.2 yamt p->trailspace = 0;
1187 1.2 joerg if (p->rmargin + titlen <= p->maxrmargin) {
1188 1.8 joerg p->flags |= TERMP_NOSPACE;
1189 1.2 joerg p->offset = p->rmargin;
1190 1.2 joerg p->rmargin = p->maxrmargin;
1191 1.2 joerg term_word(p, title);
1192 1.2 joerg term_flushln(p);
1193 1.2 joerg }
1194 1.1 joerg
1195 1.8 joerg p->flags &= ~TERMP_NOSPACE;
1196 1.8 joerg p->offset = 0;
1197 1.1 joerg p->rmargin = p->maxrmargin;
1198 1.1 joerg
1199 1.2 joerg /*
1200 1.8.2.1 yamt * Groff prints three blank lines before the content.
1201 1.8.2.1 yamt * Do the same, except in the temporary, undocumented
1202 1.8.2.1 yamt * mode imitating mdoc(7) output.
1203 1.2 joerg */
1204 1.2 joerg
1205 1.2 joerg term_vspace(p);
1206 1.8.2.1 yamt if ( ! p->mdocstyle) {
1207 1.8.2.1 yamt term_vspace(p);
1208 1.8.2.1 yamt term_vspace(p);
1209 1.8.2.1 yamt }
1210 1.1 joerg }
1211