mandoc 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +7 -0
  3. data/COPYING +674 -0
  4. data/README.md +117 -0
  5. data/ext/mandoc/extconf.rb +59 -0
  6. data/ext/mandoc/rb_mandoc.c +548 -0
  7. data/ext/mandoc/rb_mandoc.h +22 -0
  8. data/lib/mandoc/version.rb +19 -0
  9. data/lib/mandoc.rb +26 -0
  10. data/mandoc-1.14.6/LICENSE +55 -0
  11. data/mandoc-1.14.6/arch.c +54 -0
  12. data/mandoc-1.14.6/att.c +49 -0
  13. data/mandoc-1.14.6/catman.c +260 -0
  14. data/mandoc-1.14.6/cgi.c +1279 -0
  15. data/mandoc-1.14.6/chars.c +507 -0
  16. data/mandoc-1.14.6/compat_err.c +103 -0
  17. data/mandoc-1.14.6/compat_fts.c +696 -0
  18. data/mandoc-1.14.6/compat_fts.h +106 -0
  19. data/mandoc-1.14.6/compat_getline.c +59 -0
  20. data/mandoc-1.14.6/compat_getsubopt.c +87 -0
  21. data/mandoc-1.14.6/compat_isblank.c +23 -0
  22. data/mandoc-1.14.6/compat_mkdtemp.c +50 -0
  23. data/mandoc-1.14.6/compat_mkstemps.c +63 -0
  24. data/mandoc-1.14.6/compat_ohash.c +330 -0
  25. data/mandoc-1.14.6/compat_ohash.h +72 -0
  26. data/mandoc-1.14.6/compat_progname.c +31 -0
  27. data/mandoc-1.14.6/compat_reallocarray.c +40 -0
  28. data/mandoc-1.14.6/compat_recallocarray.c +99 -0
  29. data/mandoc-1.14.6/compat_strcasestr.c +64 -0
  30. data/mandoc-1.14.6/compat_stringlist.c +135 -0
  31. data/mandoc-1.14.6/compat_stringlist.h +48 -0
  32. data/mandoc-1.14.6/compat_strlcat.c +57 -0
  33. data/mandoc-1.14.6/compat_strlcpy.c +52 -0
  34. data/mandoc-1.14.6/compat_strndup.c +42 -0
  35. data/mandoc-1.14.6/compat_strsep.c +70 -0
  36. data/mandoc-1.14.6/compat_strtonum.c +67 -0
  37. data/mandoc-1.14.6/compat_vasprintf.c +47 -0
  38. data/mandoc-1.14.6/config.h +52 -0
  39. data/mandoc-1.14.6/dba.c +508 -0
  40. data/mandoc-1.14.6/dba.h +50 -0
  41. data/mandoc-1.14.6/dba_array.c +190 -0
  42. data/mandoc-1.14.6/dba_array.h +47 -0
  43. data/mandoc-1.14.6/dba_read.c +74 -0
  44. data/mandoc-1.14.6/dba_write.c +127 -0
  45. data/mandoc-1.14.6/dba_write.h +30 -0
  46. data/mandoc-1.14.6/dbm.c +480 -0
  47. data/mandoc-1.14.6/dbm.h +68 -0
  48. data/mandoc-1.14.6/dbm_map.c +194 -0
  49. data/mandoc-1.14.6/dbm_map.h +29 -0
  50. data/mandoc-1.14.6/demandoc.c +260 -0
  51. data/mandoc-1.14.6/eqn.c +1132 -0
  52. data/mandoc-1.14.6/eqn.h +72 -0
  53. data/mandoc-1.14.6/eqn_html.c +246 -0
  54. data/mandoc-1.14.6/eqn_parse.h +48 -0
  55. data/mandoc-1.14.6/eqn_term.c +174 -0
  56. data/mandoc-1.14.6/html.c +1102 -0
  57. data/mandoc-1.14.6/html.h +142 -0
  58. data/mandoc-1.14.6/lib.c +35 -0
  59. data/mandoc-1.14.6/libman.h +42 -0
  60. data/mandoc-1.14.6/libmandoc.h +85 -0
  61. data/mandoc-1.14.6/libmdoc.h +87 -0
  62. data/mandoc-1.14.6/main.c +1375 -0
  63. data/mandoc-1.14.6/main.h +53 -0
  64. data/mandoc-1.14.6/man.c +345 -0
  65. data/mandoc-1.14.6/man.h +21 -0
  66. data/mandoc-1.14.6/man_html.c +640 -0
  67. data/mandoc-1.14.6/man_macro.c +470 -0
  68. data/mandoc-1.14.6/man_term.c +1143 -0
  69. data/mandoc-1.14.6/man_validate.c +660 -0
  70. data/mandoc-1.14.6/manconf.h +58 -0
  71. data/mandoc-1.14.6/mandoc.c +669 -0
  72. data/mandoc-1.14.6/mandoc.h +329 -0
  73. data/mandoc-1.14.6/mandoc_aux.c +118 -0
  74. data/mandoc-1.14.6/mandoc_aux.h +27 -0
  75. data/mandoc-1.14.6/mandoc_msg.c +375 -0
  76. data/mandoc-1.14.6/mandoc_ohash.c +65 -0
  77. data/mandoc-1.14.6/mandoc_ohash.h +23 -0
  78. data/mandoc-1.14.6/mandoc_parse.h +44 -0
  79. data/mandoc-1.14.6/mandoc_xr.c +123 -0
  80. data/mandoc-1.14.6/mandoc_xr.h +31 -0
  81. data/mandoc-1.14.6/mandocd.c +282 -0
  82. data/mandoc-1.14.6/mandocdb.c +2448 -0
  83. data/mandoc-1.14.6/manpath.c +363 -0
  84. data/mandoc-1.14.6/mansearch.c +851 -0
  85. data/mandoc-1.14.6/mansearch.h +118 -0
  86. data/mandoc-1.14.6/mdoc.c +433 -0
  87. data/mandoc-1.14.6/mdoc.h +158 -0
  88. data/mandoc-1.14.6/mdoc_argv.c +682 -0
  89. data/mandoc-1.14.6/mdoc_html.c +1762 -0
  90. data/mandoc-1.14.6/mdoc_macro.c +1600 -0
  91. data/mandoc-1.14.6/mdoc_man.c +1850 -0
  92. data/mandoc-1.14.6/mdoc_markdown.c +1610 -0
  93. data/mandoc-1.14.6/mdoc_state.c +256 -0
  94. data/mandoc-1.14.6/mdoc_term.c +1964 -0
  95. data/mandoc-1.14.6/mdoc_validate.c +3062 -0
  96. data/mandoc-1.14.6/msec.c +37 -0
  97. data/mandoc-1.14.6/out.c +544 -0
  98. data/mandoc-1.14.6/out.h +70 -0
  99. data/mandoc-1.14.6/preconv.c +179 -0
  100. data/mandoc-1.14.6/read.c +732 -0
  101. data/mandoc-1.14.6/roff.c +4390 -0
  102. data/mandoc-1.14.6/roff.h +561 -0
  103. data/mandoc-1.14.6/roff_html.c +119 -0
  104. data/mandoc-1.14.6/roff_int.h +94 -0
  105. data/mandoc-1.14.6/roff_term.c +266 -0
  106. data/mandoc-1.14.6/roff_validate.c +151 -0
  107. data/mandoc-1.14.6/soelim.c +182 -0
  108. data/mandoc-1.14.6/st.c +82 -0
  109. data/mandoc-1.14.6/tag.c +327 -0
  110. data/mandoc-1.14.6/tag.h +35 -0
  111. data/mandoc-1.14.6/tbl.c +183 -0
  112. data/mandoc-1.14.6/tbl.h +121 -0
  113. data/mandoc-1.14.6/tbl_data.c +323 -0
  114. data/mandoc-1.14.6/tbl_html.c +293 -0
  115. data/mandoc-1.14.6/tbl_int.h +47 -0
  116. data/mandoc-1.14.6/tbl_layout.c +376 -0
  117. data/mandoc-1.14.6/tbl_opts.c +173 -0
  118. data/mandoc-1.14.6/tbl_parse.h +30 -0
  119. data/mandoc-1.14.6/tbl_term.c +948 -0
  120. data/mandoc-1.14.6/term.c +1113 -0
  121. data/mandoc-1.14.6/term.h +158 -0
  122. data/mandoc-1.14.6/term_ascii.c +424 -0
  123. data/mandoc-1.14.6/term_ps.c +1362 -0
  124. data/mandoc-1.14.6/term_tab.c +130 -0
  125. data/mandoc-1.14.6/term_tag.c +227 -0
  126. data/mandoc-1.14.6/term_tag.h +34 -0
  127. data/mandoc-1.14.6/tree.c +536 -0
  128. metadata +170 -0
@@ -0,0 +1,1143 @@
1
+ /* $Id: man_term.c,v 1.236 2021/06/28 19:50:15 schwarze Exp $ */
2
+ /*
3
+ * Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
4
+ * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ *
18
+ * Plain text formatter for man(7), used by mandoc(1)
19
+ * for ASCII, UTF-8, PostScript, and PDF output.
20
+ */
21
+ #include "config.h"
22
+
23
+ #include <sys/types.h>
24
+
25
+ #include <assert.h>
26
+ #include <ctype.h>
27
+ #include <limits.h>
28
+ #include <stdio.h>
29
+ #include <stdlib.h>
30
+ #include <string.h>
31
+
32
+ #include "mandoc_aux.h"
33
+ #include "mandoc.h"
34
+ #include "roff.h"
35
+ #include "man.h"
36
+ #include "out.h"
37
+ #include "term.h"
38
+ #include "term_tag.h"
39
+ #include "main.h"
40
+
41
+ #define MAXMARGINS 64 /* maximum number of indented scopes */
42
+
43
+ struct mtermp {
44
+ int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
45
+ int lmargincur; /* index of current margin */
46
+ int lmarginsz; /* actual number of nested margins */
47
+ size_t offset; /* default offset to visible page */
48
+ int pardist; /* vert. space before par., unit: [v] */
49
+ };
50
+
51
+ #define DECL_ARGS struct termp *p, \
52
+ struct mtermp *mt, \
53
+ struct roff_node *n, \
54
+ const struct roff_meta *meta
55
+
56
+ struct man_term_act {
57
+ int (*pre)(DECL_ARGS);
58
+ void (*post)(DECL_ARGS);
59
+ int flags;
60
+ #define MAN_NOTEXT (1 << 0) /* Never has text children. */
61
+ };
62
+
63
+ static void print_man_nodelist(DECL_ARGS);
64
+ static void print_man_node(DECL_ARGS);
65
+ static void print_man_head(struct termp *,
66
+ const struct roff_meta *);
67
+ static void print_man_foot(struct termp *,
68
+ const struct roff_meta *);
69
+ static void print_bvspace(struct termp *,
70
+ struct roff_node *, int);
71
+
72
+ static int pre_B(DECL_ARGS);
73
+ static int pre_DT(DECL_ARGS);
74
+ static int pre_HP(DECL_ARGS);
75
+ static int pre_I(DECL_ARGS);
76
+ static int pre_IP(DECL_ARGS);
77
+ static int pre_OP(DECL_ARGS);
78
+ static int pre_PD(DECL_ARGS);
79
+ static int pre_PP(DECL_ARGS);
80
+ static int pre_RS(DECL_ARGS);
81
+ static int pre_SH(DECL_ARGS);
82
+ static int pre_SS(DECL_ARGS);
83
+ static int pre_SY(DECL_ARGS);
84
+ static int pre_TP(DECL_ARGS);
85
+ static int pre_UR(DECL_ARGS);
86
+ static int pre_abort(DECL_ARGS);
87
+ static int pre_alternate(DECL_ARGS);
88
+ static int pre_ign(DECL_ARGS);
89
+ static int pre_in(DECL_ARGS);
90
+ static int pre_literal(DECL_ARGS);
91
+
92
+ static void post_IP(DECL_ARGS);
93
+ static void post_HP(DECL_ARGS);
94
+ static void post_RS(DECL_ARGS);
95
+ static void post_SH(DECL_ARGS);
96
+ static void post_SY(DECL_ARGS);
97
+ static void post_TP(DECL_ARGS);
98
+ static void post_UR(DECL_ARGS);
99
+
100
+ static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
101
+ { NULL, NULL, 0 }, /* TH */
102
+ { pre_SH, post_SH, 0 }, /* SH */
103
+ { pre_SS, post_SH, 0 }, /* SS */
104
+ { pre_TP, post_TP, 0 }, /* TP */
105
+ { pre_TP, post_TP, 0 }, /* TQ */
106
+ { pre_abort, NULL, 0 }, /* LP */
107
+ { pre_PP, NULL, 0 }, /* PP */
108
+ { pre_abort, NULL, 0 }, /* P */
109
+ { pre_IP, post_IP, 0 }, /* IP */
110
+ { pre_HP, post_HP, 0 }, /* HP */
111
+ { NULL, NULL, 0 }, /* SM */
112
+ { pre_B, NULL, 0 }, /* SB */
113
+ { pre_alternate, NULL, 0 }, /* BI */
114
+ { pre_alternate, NULL, 0 }, /* IB */
115
+ { pre_alternate, NULL, 0 }, /* BR */
116
+ { pre_alternate, NULL, 0 }, /* RB */
117
+ { NULL, NULL, 0 }, /* R */
118
+ { pre_B, NULL, 0 }, /* B */
119
+ { pre_I, NULL, 0 }, /* I */
120
+ { pre_alternate, NULL, 0 }, /* IR */
121
+ { pre_alternate, NULL, 0 }, /* RI */
122
+ { NULL, NULL, 0 }, /* RE */
123
+ { pre_RS, post_RS, 0 }, /* RS */
124
+ { pre_DT, NULL, 0 }, /* DT */
125
+ { pre_ign, NULL, MAN_NOTEXT }, /* UC */
126
+ { pre_PD, NULL, MAN_NOTEXT }, /* PD */
127
+ { pre_ign, NULL, 0 }, /* AT */
128
+ { pre_in, NULL, MAN_NOTEXT }, /* in */
129
+ { pre_SY, post_SY, 0 }, /* SY */
130
+ { NULL, NULL, 0 }, /* YS */
131
+ { pre_OP, NULL, 0 }, /* OP */
132
+ { pre_literal, NULL, 0 }, /* EX */
133
+ { pre_literal, NULL, 0 }, /* EE */
134
+ { pre_UR, post_UR, 0 }, /* UR */
135
+ { NULL, NULL, 0 }, /* UE */
136
+ { pre_UR, post_UR, 0 }, /* MT */
137
+ { NULL, NULL, 0 }, /* ME */
138
+ };
139
+ static const struct man_term_act *man_term_act(enum roff_tok);
140
+
141
+
142
+ static const struct man_term_act *
143
+ man_term_act(enum roff_tok tok)
144
+ {
145
+ assert(tok >= MAN_TH && tok <= MAN_MAX);
146
+ return man_term_acts + (tok - MAN_TH);
147
+ }
148
+
149
+ void
150
+ terminal_man(void *arg, const struct roff_meta *man)
151
+ {
152
+ struct mtermp mt;
153
+ struct termp *p;
154
+ struct roff_node *n, *nc, *nn;
155
+ size_t save_defindent;
156
+
157
+ p = (struct termp *)arg;
158
+ save_defindent = p->defindent;
159
+ if (p->synopsisonly == 0 && p->defindent == 0)
160
+ p->defindent = 7;
161
+ p->tcol->rmargin = p->maxrmargin = p->defrmargin;
162
+ term_tab_set(p, NULL);
163
+ term_tab_set(p, "T");
164
+ term_tab_set(p, ".5i");
165
+
166
+ memset(&mt, 0, sizeof(mt));
167
+ mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
168
+ mt.offset = term_len(p, p->defindent);
169
+ mt.pardist = 1;
170
+
171
+ n = man->first->child;
172
+ if (p->synopsisonly) {
173
+ for (nn = NULL; n != NULL; n = n->next) {
174
+ if (n->tok != MAN_SH)
175
+ continue;
176
+ nc = n->child->child;
177
+ if (nc->type != ROFFT_TEXT)
178
+ continue;
179
+ if (strcmp(nc->string, "SYNOPSIS") == 0)
180
+ break;
181
+ if (nn == NULL && strcmp(nc->string, "NAME") == 0)
182
+ nn = n;
183
+ }
184
+ if (n == NULL)
185
+ n = nn;
186
+ p->flags |= TERMP_NOSPACE;
187
+ if (n != NULL && (n = n->child->next->child) != NULL)
188
+ print_man_nodelist(p, &mt, n, man);
189
+ term_newln(p);
190
+ } else {
191
+ term_begin(p, print_man_head, print_man_foot, man);
192
+ p->flags |= TERMP_NOSPACE;
193
+ if (n != NULL)
194
+ print_man_nodelist(p, &mt, n, man);
195
+ term_end(p);
196
+ }
197
+ p->defindent = save_defindent;
198
+ }
199
+
200
+ /*
201
+ * Printing leading vertical space before a block.
202
+ * This is used for the paragraph macros.
203
+ * The rules are pretty simple, since there's very little nesting going
204
+ * on here. Basically, if we're the first within another block (SS/SH),
205
+ * then don't emit vertical space. If we are (RS), then do. If not the
206
+ * first, print it.
207
+ */
208
+ static void
209
+ print_bvspace(struct termp *p, struct roff_node *n, int pardist)
210
+ {
211
+ struct roff_node *nch;
212
+ int i;
213
+
214
+ term_newln(p);
215
+
216
+ if (n->body != NULL &&
217
+ (nch = roff_node_child(n->body)) != NULL &&
218
+ nch->type == ROFFT_TBL)
219
+ return;
220
+
221
+ if (n->parent->tok != MAN_RS && roff_node_prev(n) == NULL)
222
+ return;
223
+
224
+ for (i = 0; i < pardist; i++)
225
+ term_vspace(p);
226
+ }
227
+
228
+
229
+ static int
230
+ pre_abort(DECL_ARGS)
231
+ {
232
+ abort();
233
+ }
234
+
235
+ static int
236
+ pre_ign(DECL_ARGS)
237
+ {
238
+ return 0;
239
+ }
240
+
241
+ static int
242
+ pre_I(DECL_ARGS)
243
+ {
244
+ term_fontrepl(p, TERMFONT_UNDER);
245
+ return 1;
246
+ }
247
+
248
+ static int
249
+ pre_literal(DECL_ARGS)
250
+ {
251
+ term_newln(p);
252
+
253
+ /*
254
+ * Unlike .IP and .TP, .HP does not have a HEAD.
255
+ * So in case a second call to term_flushln() is needed,
256
+ * indentation has to be set up explicitly.
257
+ */
258
+ if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) {
259
+ p->tcol->offset = p->tcol->rmargin;
260
+ p->tcol->rmargin = p->maxrmargin;
261
+ p->trailspace = 0;
262
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
263
+ p->flags |= TERMP_NOSPACE;
264
+ }
265
+ return 0;
266
+ }
267
+
268
+ static int
269
+ pre_PD(DECL_ARGS)
270
+ {
271
+ struct roffsu su;
272
+
273
+ n = n->child;
274
+ if (n == NULL) {
275
+ mt->pardist = 1;
276
+ return 0;
277
+ }
278
+ assert(n->type == ROFFT_TEXT);
279
+ if (a2roffsu(n->string, &su, SCALE_VS) != NULL)
280
+ mt->pardist = term_vspan(p, &su);
281
+ return 0;
282
+ }
283
+
284
+ static int
285
+ pre_alternate(DECL_ARGS)
286
+ {
287
+ enum termfont font[2];
288
+ struct roff_node *nn;
289
+ int i;
290
+
291
+ switch (n->tok) {
292
+ case MAN_RB:
293
+ font[0] = TERMFONT_NONE;
294
+ font[1] = TERMFONT_BOLD;
295
+ break;
296
+ case MAN_RI:
297
+ font[0] = TERMFONT_NONE;
298
+ font[1] = TERMFONT_UNDER;
299
+ break;
300
+ case MAN_BR:
301
+ font[0] = TERMFONT_BOLD;
302
+ font[1] = TERMFONT_NONE;
303
+ break;
304
+ case MAN_BI:
305
+ font[0] = TERMFONT_BOLD;
306
+ font[1] = TERMFONT_UNDER;
307
+ break;
308
+ case MAN_IR:
309
+ font[0] = TERMFONT_UNDER;
310
+ font[1] = TERMFONT_NONE;
311
+ break;
312
+ case MAN_IB:
313
+ font[0] = TERMFONT_UNDER;
314
+ font[1] = TERMFONT_BOLD;
315
+ break;
316
+ default:
317
+ abort();
318
+ }
319
+ for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) {
320
+ term_fontrepl(p, font[i]);
321
+ assert(nn->type == ROFFT_TEXT);
322
+ term_word(p, nn->string);
323
+ if (nn->flags & NODE_EOS)
324
+ p->flags |= TERMP_SENTENCE;
325
+ if (nn->next != NULL)
326
+ p->flags |= TERMP_NOSPACE;
327
+ }
328
+ return 0;
329
+ }
330
+
331
+ static int
332
+ pre_B(DECL_ARGS)
333
+ {
334
+ term_fontrepl(p, TERMFONT_BOLD);
335
+ return 1;
336
+ }
337
+
338
+ static int
339
+ pre_OP(DECL_ARGS)
340
+ {
341
+ term_word(p, "[");
342
+ p->flags |= TERMP_KEEP | TERMP_NOSPACE;
343
+
344
+ if ((n = n->child) != NULL) {
345
+ term_fontrepl(p, TERMFONT_BOLD);
346
+ term_word(p, n->string);
347
+ }
348
+ if (n != NULL && n->next != NULL) {
349
+ term_fontrepl(p, TERMFONT_UNDER);
350
+ term_word(p, n->next->string);
351
+ }
352
+ term_fontrepl(p, TERMFONT_NONE);
353
+ p->flags &= ~TERMP_KEEP;
354
+ p->flags |= TERMP_NOSPACE;
355
+ term_word(p, "]");
356
+ return 0;
357
+ }
358
+
359
+ static int
360
+ pre_in(DECL_ARGS)
361
+ {
362
+ struct roffsu su;
363
+ const char *cp;
364
+ size_t v;
365
+ int less;
366
+
367
+ term_newln(p);
368
+
369
+ if (n->child == NULL) {
370
+ p->tcol->offset = mt->offset;
371
+ return 0;
372
+ }
373
+
374
+ cp = n->child->string;
375
+ less = 0;
376
+
377
+ if (*cp == '-')
378
+ less = -1;
379
+ else if (*cp == '+')
380
+ less = 1;
381
+ else
382
+ cp--;
383
+
384
+ if (a2roffsu(++cp, &su, SCALE_EN) == NULL)
385
+ return 0;
386
+
387
+ v = term_hen(p, &su);
388
+
389
+ if (less < 0)
390
+ p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset;
391
+ else if (less > 0)
392
+ p->tcol->offset += v;
393
+ else
394
+ p->tcol->offset = v;
395
+ if (p->tcol->offset > SHRT_MAX)
396
+ p->tcol->offset = term_len(p, p->defindent);
397
+
398
+ return 0;
399
+ }
400
+
401
+ static int
402
+ pre_DT(DECL_ARGS)
403
+ {
404
+ term_tab_set(p, NULL);
405
+ term_tab_set(p, "T");
406
+ term_tab_set(p, ".5i");
407
+ return 0;
408
+ }
409
+
410
+ static int
411
+ pre_HP(DECL_ARGS)
412
+ {
413
+ struct roffsu su;
414
+ const struct roff_node *nn;
415
+ int len;
416
+
417
+ switch (n->type) {
418
+ case ROFFT_BLOCK:
419
+ print_bvspace(p, n, mt->pardist);
420
+ return 1;
421
+ case ROFFT_HEAD:
422
+ return 0;
423
+ case ROFFT_BODY:
424
+ break;
425
+ default:
426
+ abort();
427
+ }
428
+
429
+ if (n->child == NULL)
430
+ return 0;
431
+
432
+ if ((n->child->flags & NODE_NOFILL) == 0) {
433
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
434
+ p->trailspace = 2;
435
+ }
436
+
437
+ /* Calculate offset. */
438
+
439
+ if ((nn = n->parent->head->child) != NULL &&
440
+ a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
441
+ len = term_hen(p, &su);
442
+ if (len < 0 && (size_t)(-len) > mt->offset)
443
+ len = -mt->offset;
444
+ else if (len > SHRT_MAX)
445
+ len = term_len(p, p->defindent);
446
+ mt->lmargin[mt->lmargincur] = len;
447
+ } else
448
+ len = mt->lmargin[mt->lmargincur];
449
+
450
+ p->tcol->offset = mt->offset;
451
+ p->tcol->rmargin = mt->offset + len;
452
+ return 1;
453
+ }
454
+
455
+ static void
456
+ post_HP(DECL_ARGS)
457
+ {
458
+ switch (n->type) {
459
+ case ROFFT_BLOCK:
460
+ case ROFFT_HEAD:
461
+ break;
462
+ case ROFFT_BODY:
463
+ term_newln(p);
464
+
465
+ /*
466
+ * Compatibility with a groff bug.
467
+ * The .HP macro uses the undocumented .tag request
468
+ * which causes a line break and cancels no-space
469
+ * mode even if there isn't any output.
470
+ */
471
+
472
+ if (n->child == NULL)
473
+ term_vspace(p);
474
+
475
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
476
+ p->trailspace = 0;
477
+ p->tcol->offset = mt->offset;
478
+ p->tcol->rmargin = p->maxrmargin;
479
+ break;
480
+ default:
481
+ abort();
482
+ }
483
+ }
484
+
485
+ static int
486
+ pre_PP(DECL_ARGS)
487
+ {
488
+ switch (n->type) {
489
+ case ROFFT_BLOCK:
490
+ mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
491
+ print_bvspace(p, n, mt->pardist);
492
+ break;
493
+ case ROFFT_HEAD:
494
+ return 0;
495
+ case ROFFT_BODY:
496
+ p->tcol->offset = mt->offset;
497
+ break;
498
+ default:
499
+ abort();
500
+ }
501
+ return 1;
502
+ }
503
+
504
+ static int
505
+ pre_IP(DECL_ARGS)
506
+ {
507
+ struct roffsu su;
508
+ const struct roff_node *nn;
509
+ int len;
510
+
511
+ switch (n->type) {
512
+ case ROFFT_BLOCK:
513
+ print_bvspace(p, n, mt->pardist);
514
+ return 1;
515
+ case ROFFT_HEAD:
516
+ p->flags |= TERMP_NOBREAK;
517
+ p->trailspace = 1;
518
+ break;
519
+ case ROFFT_BODY:
520
+ p->flags |= TERMP_NOSPACE;
521
+ break;
522
+ default:
523
+ abort();
524
+ }
525
+
526
+ /* Calculate the offset from the optional second argument. */
527
+ if ((nn = n->parent->head->child) != NULL &&
528
+ (nn = nn->next) != NULL &&
529
+ a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
530
+ len = term_hen(p, &su);
531
+ if (len < 0 && (size_t)(-len) > mt->offset)
532
+ len = -mt->offset;
533
+ else if (len > SHRT_MAX)
534
+ len = term_len(p, p->defindent);
535
+ mt->lmargin[mt->lmargincur] = len;
536
+ } else
537
+ len = mt->lmargin[mt->lmargincur];
538
+
539
+ switch (n->type) {
540
+ case ROFFT_HEAD:
541
+ p->tcol->offset = mt->offset;
542
+ p->tcol->rmargin = mt->offset + len;
543
+ if (n->child != NULL)
544
+ print_man_node(p, mt, n->child, meta);
545
+ return 0;
546
+ case ROFFT_BODY:
547
+ p->tcol->offset = mt->offset + len;
548
+ p->tcol->rmargin = p->maxrmargin;
549
+ break;
550
+ default:
551
+ abort();
552
+ }
553
+ return 1;
554
+ }
555
+
556
+ static void
557
+ post_IP(DECL_ARGS)
558
+ {
559
+ switch (n->type) {
560
+ case ROFFT_BLOCK:
561
+ break;
562
+ case ROFFT_HEAD:
563
+ term_flushln(p);
564
+ p->flags &= ~TERMP_NOBREAK;
565
+ p->trailspace = 0;
566
+ p->tcol->rmargin = p->maxrmargin;
567
+ break;
568
+ case ROFFT_BODY:
569
+ term_newln(p);
570
+ p->tcol->offset = mt->offset;
571
+ break;
572
+ default:
573
+ abort();
574
+ }
575
+ }
576
+
577
+ static int
578
+ pre_TP(DECL_ARGS)
579
+ {
580
+ struct roffsu su;
581
+ struct roff_node *nn;
582
+ int len;
583
+
584
+ switch (n->type) {
585
+ case ROFFT_BLOCK:
586
+ if (n->tok == MAN_TP)
587
+ print_bvspace(p, n, mt->pardist);
588
+ return 1;
589
+ case ROFFT_HEAD:
590
+ p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
591
+ p->trailspace = 1;
592
+ break;
593
+ case ROFFT_BODY:
594
+ p->flags |= TERMP_NOSPACE;
595
+ break;
596
+ default:
597
+ abort();
598
+ }
599
+
600
+ /* Calculate offset. */
601
+
602
+ if ((nn = n->parent->head->child) != NULL &&
603
+ nn->string != NULL && ! (NODE_LINE & nn->flags) &&
604
+ a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
605
+ len = term_hen(p, &su);
606
+ if (len < 0 && (size_t)(-len) > mt->offset)
607
+ len = -mt->offset;
608
+ else if (len > SHRT_MAX)
609
+ len = term_len(p, p->defindent);
610
+ mt->lmargin[mt->lmargincur] = len;
611
+ } else
612
+ len = mt->lmargin[mt->lmargincur];
613
+
614
+ switch (n->type) {
615
+ case ROFFT_HEAD:
616
+ p->tcol->offset = mt->offset;
617
+ p->tcol->rmargin = mt->offset + len;
618
+
619
+ /* Don't print same-line elements. */
620
+ nn = n->child;
621
+ while (nn != NULL && (nn->flags & NODE_LINE) == 0)
622
+ nn = nn->next;
623
+
624
+ while (nn != NULL) {
625
+ print_man_node(p, mt, nn, meta);
626
+ nn = nn->next;
627
+ }
628
+ return 0;
629
+ case ROFFT_BODY:
630
+ p->tcol->offset = mt->offset + len;
631
+ p->tcol->rmargin = p->maxrmargin;
632
+ p->trailspace = 0;
633
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
634
+ break;
635
+ default:
636
+ abort();
637
+ }
638
+ return 1;
639
+ }
640
+
641
+ static void
642
+ post_TP(DECL_ARGS)
643
+ {
644
+ switch (n->type) {
645
+ case ROFFT_BLOCK:
646
+ break;
647
+ case ROFFT_HEAD:
648
+ term_flushln(p);
649
+ break;
650
+ case ROFFT_BODY:
651
+ term_newln(p);
652
+ p->tcol->offset = mt->offset;
653
+ break;
654
+ default:
655
+ abort();
656
+ }
657
+ }
658
+
659
+ static int
660
+ pre_SS(DECL_ARGS)
661
+ {
662
+ int i;
663
+
664
+ switch (n->type) {
665
+ case ROFFT_BLOCK:
666
+ mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
667
+ mt->offset = term_len(p, p->defindent);
668
+
669
+ /*
670
+ * No vertical space before the first subsection
671
+ * and after an empty subsection.
672
+ */
673
+
674
+ if ((n = roff_node_prev(n)) == NULL ||
675
+ (n->tok == MAN_SS && roff_node_child(n->body) == NULL))
676
+ break;
677
+
678
+ for (i = 0; i < mt->pardist; i++)
679
+ term_vspace(p);
680
+ break;
681
+ case ROFFT_HEAD:
682
+ term_fontrepl(p, TERMFONT_BOLD);
683
+ p->tcol->offset = term_len(p, 3);
684
+ p->tcol->rmargin = mt->offset;
685
+ p->trailspace = mt->offset;
686
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
687
+ break;
688
+ case ROFFT_BODY:
689
+ p->tcol->offset = mt->offset;
690
+ p->tcol->rmargin = p->maxrmargin;
691
+ p->trailspace = 0;
692
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
693
+ break;
694
+ default:
695
+ break;
696
+ }
697
+ return 1;
698
+ }
699
+
700
+ static int
701
+ pre_SH(DECL_ARGS)
702
+ {
703
+ int i;
704
+
705
+ switch (n->type) {
706
+ case ROFFT_BLOCK:
707
+ mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
708
+ mt->offset = term_len(p, p->defindent);
709
+
710
+ /*
711
+ * No vertical space before the first section
712
+ * and after an empty section.
713
+ */
714
+
715
+ if ((n = roff_node_prev(n)) == NULL ||
716
+ (n->tok == MAN_SH && roff_node_child(n->body) == NULL))
717
+ break;
718
+
719
+ for (i = 0; i < mt->pardist; i++)
720
+ term_vspace(p);
721
+ break;
722
+ case ROFFT_HEAD:
723
+ term_fontrepl(p, TERMFONT_BOLD);
724
+ p->tcol->offset = 0;
725
+ p->tcol->rmargin = mt->offset;
726
+ p->trailspace = mt->offset;
727
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
728
+ break;
729
+ case ROFFT_BODY:
730
+ p->tcol->offset = mt->offset;
731
+ p->tcol->rmargin = p->maxrmargin;
732
+ p->trailspace = 0;
733
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
734
+ break;
735
+ default:
736
+ abort();
737
+ }
738
+ return 1;
739
+ }
740
+
741
+ static void
742
+ post_SH(DECL_ARGS)
743
+ {
744
+ switch (n->type) {
745
+ case ROFFT_BLOCK:
746
+ break;
747
+ case ROFFT_HEAD:
748
+ case ROFFT_BODY:
749
+ term_newln(p);
750
+ break;
751
+ default:
752
+ abort();
753
+ }
754
+ }
755
+
756
+ static int
757
+ pre_RS(DECL_ARGS)
758
+ {
759
+ struct roffsu su;
760
+
761
+ switch (n->type) {
762
+ case ROFFT_BLOCK:
763
+ term_newln(p);
764
+ return 1;
765
+ case ROFFT_HEAD:
766
+ return 0;
767
+ case ROFFT_BODY:
768
+ break;
769
+ default:
770
+ abort();
771
+ }
772
+
773
+ n = n->parent->head;
774
+ n->aux = SHRT_MAX + 1;
775
+ if (n->child == NULL)
776
+ n->aux = mt->lmargin[mt->lmargincur];
777
+ else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL)
778
+ n->aux = term_hen(p, &su);
779
+ if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
780
+ n->aux = -mt->offset;
781
+ else if (n->aux > SHRT_MAX)
782
+ n->aux = term_len(p, p->defindent);
783
+
784
+ mt->offset += n->aux;
785
+ p->tcol->offset = mt->offset;
786
+ p->tcol->rmargin = p->maxrmargin;
787
+
788
+ if (++mt->lmarginsz < MAXMARGINS)
789
+ mt->lmargincur = mt->lmarginsz;
790
+
791
+ mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
792
+ return 1;
793
+ }
794
+
795
+ static void
796
+ post_RS(DECL_ARGS)
797
+ {
798
+ switch (n->type) {
799
+ case ROFFT_BLOCK:
800
+ case ROFFT_HEAD:
801
+ return;
802
+ case ROFFT_BODY:
803
+ break;
804
+ default:
805
+ abort();
806
+ }
807
+ term_newln(p);
808
+ mt->offset -= n->parent->head->aux;
809
+ p->tcol->offset = mt->offset;
810
+ if (--mt->lmarginsz < MAXMARGINS)
811
+ mt->lmargincur = mt->lmarginsz;
812
+ }
813
+
814
+ static int
815
+ pre_SY(DECL_ARGS)
816
+ {
817
+ const struct roff_node *nn;
818
+ int len;
819
+
820
+ switch (n->type) {
821
+ case ROFFT_BLOCK:
822
+ if ((nn = roff_node_prev(n)) == NULL || nn->tok != MAN_SY)
823
+ print_bvspace(p, n, mt->pardist);
824
+ return 1;
825
+ case ROFFT_HEAD:
826
+ case ROFFT_BODY:
827
+ break;
828
+ default:
829
+ abort();
830
+ }
831
+
832
+ nn = n->parent->head->child;
833
+ len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1;
834
+
835
+ switch (n->type) {
836
+ case ROFFT_HEAD:
837
+ p->tcol->offset = mt->offset;
838
+ p->tcol->rmargin = mt->offset + len;
839
+ if (n->next->child == NULL ||
840
+ (n->next->child->flags & NODE_NOFILL) == 0)
841
+ p->flags |= TERMP_NOBREAK;
842
+ term_fontrepl(p, TERMFONT_BOLD);
843
+ break;
844
+ case ROFFT_BODY:
845
+ mt->lmargin[mt->lmargincur] = len;
846
+ p->tcol->offset = mt->offset + len;
847
+ p->tcol->rmargin = p->maxrmargin;
848
+ p->flags |= TERMP_NOSPACE;
849
+ break;
850
+ default:
851
+ abort();
852
+ }
853
+ return 1;
854
+ }
855
+
856
+ static void
857
+ post_SY(DECL_ARGS)
858
+ {
859
+ switch (n->type) {
860
+ case ROFFT_BLOCK:
861
+ break;
862
+ case ROFFT_HEAD:
863
+ term_flushln(p);
864
+ p->flags &= ~TERMP_NOBREAK;
865
+ break;
866
+ case ROFFT_BODY:
867
+ term_newln(p);
868
+ p->tcol->offset = mt->offset;
869
+ break;
870
+ default:
871
+ abort();
872
+ }
873
+ }
874
+
875
+ static int
876
+ pre_UR(DECL_ARGS)
877
+ {
878
+ return n->type != ROFFT_HEAD;
879
+ }
880
+
881
+ static void
882
+ post_UR(DECL_ARGS)
883
+ {
884
+ if (n->type != ROFFT_BLOCK)
885
+ return;
886
+
887
+ term_word(p, "<");
888
+ p->flags |= TERMP_NOSPACE;
889
+
890
+ if (n->child->child != NULL)
891
+ print_man_node(p, mt, n->child->child, meta);
892
+
893
+ p->flags |= TERMP_NOSPACE;
894
+ term_word(p, ">");
895
+ }
896
+
897
+ static void
898
+ print_man_node(DECL_ARGS)
899
+ {
900
+ const struct man_term_act *act;
901
+ int c;
902
+
903
+ if (n->flags & NODE_ID)
904
+ term_tag_write(n, p->line);
905
+
906
+ switch (n->type) {
907
+ case ROFFT_TEXT:
908
+ /*
909
+ * If we have a blank line, output a vertical space.
910
+ * If we have a space as the first character, break
911
+ * before printing the line's data.
912
+ */
913
+ if (*n->string == '\0') {
914
+ if (p->flags & TERMP_NONEWLINE)
915
+ term_newln(p);
916
+ else
917
+ term_vspace(p);
918
+ return;
919
+ } else if (*n->string == ' ' && n->flags & NODE_LINE &&
920
+ (p->flags & TERMP_NONEWLINE) == 0)
921
+ term_newln(p);
922
+ else if (n->flags & NODE_DELIMC)
923
+ p->flags |= TERMP_NOSPACE;
924
+
925
+ term_word(p, n->string);
926
+ goto out;
927
+ case ROFFT_COMMENT:
928
+ return;
929
+ case ROFFT_EQN:
930
+ if ( ! (n->flags & NODE_LINE))
931
+ p->flags |= TERMP_NOSPACE;
932
+ term_eqn(p, n->eqn);
933
+ if (n->next != NULL && ! (n->next->flags & NODE_LINE))
934
+ p->flags |= TERMP_NOSPACE;
935
+ return;
936
+ case ROFFT_TBL:
937
+ if (p->tbl.cols == NULL)
938
+ term_vspace(p);
939
+ term_tbl(p, n->span);
940
+ return;
941
+ default:
942
+ break;
943
+ }
944
+
945
+ if (n->tok < ROFF_MAX) {
946
+ roff_term_pre(p, n);
947
+ return;
948
+ }
949
+
950
+ act = man_term_act(n->tok);
951
+ if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
952
+ term_fontrepl(p, TERMFONT_NONE);
953
+
954
+ c = 1;
955
+ if (act->pre != NULL)
956
+ c = (*act->pre)(p, mt, n, meta);
957
+
958
+ if (c && n->child != NULL)
959
+ print_man_nodelist(p, mt, n->child, meta);
960
+
961
+ if (act->post != NULL)
962
+ (*act->post)(p, mt, n, meta);
963
+ if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
964
+ term_fontrepl(p, TERMFONT_NONE);
965
+
966
+ out:
967
+ /*
968
+ * If we're in a literal context, make sure that words
969
+ * together on the same line stay together. This is a
970
+ * POST-printing call, so we check the NEXT word. Since
971
+ * -man doesn't have nested macros, we don't need to be
972
+ * more specific than this.
973
+ */
974
+ if (n->flags & NODE_NOFILL &&
975
+ ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
976
+ (n->next == NULL || n->next->flags & NODE_LINE)) {
977
+ p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
978
+ if (n->string != NULL && *n->string != '\0')
979
+ term_flushln(p);
980
+ else
981
+ term_newln(p);
982
+ p->flags &= ~TERMP_BRNEVER;
983
+ if (p->tcol->rmargin < p->maxrmargin &&
984
+ n->parent->tok == MAN_HP) {
985
+ p->tcol->offset = p->tcol->rmargin;
986
+ p->tcol->rmargin = p->maxrmargin;
987
+ }
988
+ }
989
+ if (n->flags & NODE_EOS)
990
+ p->flags |= TERMP_SENTENCE;
991
+ }
992
+
993
+ static void
994
+ print_man_nodelist(DECL_ARGS)
995
+ {
996
+ while (n != NULL) {
997
+ print_man_node(p, mt, n, meta);
998
+ n = n->next;
999
+ }
1000
+ }
1001
+
1002
+ static void
1003
+ print_man_foot(struct termp *p, const struct roff_meta *meta)
1004
+ {
1005
+ char *title;
1006
+ size_t datelen, titlen;
1007
+
1008
+ assert(meta->title);
1009
+ assert(meta->msec);
1010
+ assert(meta->date);
1011
+
1012
+ term_fontrepl(p, TERMFONT_NONE);
1013
+
1014
+ if (meta->hasbody)
1015
+ term_vspace(p);
1016
+
1017
+ /*
1018
+ * Temporary, undocumented option to imitate mdoc(7) output.
1019
+ * In the bottom right corner, use the operating system
1020
+ * instead of the title.
1021
+ */
1022
+
1023
+ if ( ! p->mdocstyle) {
1024
+ mandoc_asprintf(&title, "%s(%s)",
1025
+ meta->title, meta->msec);
1026
+ } else if (meta->os != NULL) {
1027
+ title = mandoc_strdup(meta->os);
1028
+ } else {
1029
+ title = mandoc_strdup("");
1030
+ }
1031
+ datelen = term_strlen(p, meta->date);
1032
+
1033
+ /* Bottom left corner: operating system. */
1034
+
1035
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1036
+ p->trailspace = 1;
1037
+ p->tcol->offset = 0;
1038
+ p->tcol->rmargin = p->maxrmargin > datelen ?
1039
+ (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
1040
+
1041
+ if (meta->os)
1042
+ term_word(p, meta->os);
1043
+ term_flushln(p);
1044
+
1045
+ /* At the bottom in the middle: manual date. */
1046
+
1047
+ p->tcol->offset = p->tcol->rmargin;
1048
+ titlen = term_strlen(p, title);
1049
+ p->tcol->rmargin = p->maxrmargin > titlen ?
1050
+ p->maxrmargin - titlen : 0;
1051
+ p->flags |= TERMP_NOSPACE;
1052
+
1053
+ term_word(p, meta->date);
1054
+ term_flushln(p);
1055
+
1056
+ /* Bottom right corner: manual title and section. */
1057
+
1058
+ p->flags &= ~TERMP_NOBREAK;
1059
+ p->flags |= TERMP_NOSPACE;
1060
+ p->trailspace = 0;
1061
+ p->tcol->offset = p->tcol->rmargin;
1062
+ p->tcol->rmargin = p->maxrmargin;
1063
+
1064
+ term_word(p, title);
1065
+ term_flushln(p);
1066
+
1067
+ /*
1068
+ * Reset the terminal state for more output after the footer:
1069
+ * Some output modes, in particular PostScript and PDF, print
1070
+ * the header and the footer into a buffer such that it can be
1071
+ * reused for multiple output pages, then go on to format the
1072
+ * main text.
1073
+ */
1074
+
1075
+ p->tcol->offset = 0;
1076
+ p->flags = 0;
1077
+
1078
+ free(title);
1079
+ }
1080
+
1081
+ static void
1082
+ print_man_head(struct termp *p, const struct roff_meta *meta)
1083
+ {
1084
+ const char *volume;
1085
+ char *title;
1086
+ size_t vollen, titlen;
1087
+
1088
+ assert(meta->title);
1089
+ assert(meta->msec);
1090
+
1091
+ volume = NULL == meta->vol ? "" : meta->vol;
1092
+ vollen = term_strlen(p, volume);
1093
+
1094
+ /* Top left corner: manual title and section. */
1095
+
1096
+ mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
1097
+ titlen = term_strlen(p, title);
1098
+
1099
+ p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
1100
+ p->trailspace = 1;
1101
+ p->tcol->offset = 0;
1102
+ p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
1103
+ (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
1104
+ vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
1105
+
1106
+ term_word(p, title);
1107
+ term_flushln(p);
1108
+
1109
+ /* At the top in the middle: manual volume. */
1110
+
1111
+ p->flags |= TERMP_NOSPACE;
1112
+ p->tcol->offset = p->tcol->rmargin;
1113
+ p->tcol->rmargin = p->tcol->offset + vollen + titlen <
1114
+ p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
1115
+
1116
+ term_word(p, volume);
1117
+ term_flushln(p);
1118
+
1119
+ /* Top right corner: title and section, again. */
1120
+
1121
+ p->flags &= ~TERMP_NOBREAK;
1122
+ p->trailspace = 0;
1123
+ if (p->tcol->rmargin + titlen <= p->maxrmargin) {
1124
+ p->flags |= TERMP_NOSPACE;
1125
+ p->tcol->offset = p->tcol->rmargin;
1126
+ p->tcol->rmargin = p->maxrmargin;
1127
+ term_word(p, title);
1128
+ term_flushln(p);
1129
+ }
1130
+
1131
+ p->flags &= ~TERMP_NOSPACE;
1132
+ p->tcol->offset = 0;
1133
+ p->tcol->rmargin = p->maxrmargin;
1134
+
1135
+ /*
1136
+ * Groff prints three blank lines before the content.
1137
+ * Do the same, except in the temporary, undocumented
1138
+ * mode imitating mdoc(7) output.
1139
+ */
1140
+
1141
+ term_vspace(p);
1142
+ free(title);
1143
+ }