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,1964 @@
1
+ /* $Id: mdoc_term.c,v 1.380 2020/04/06 10:16:17 schwarze Exp $ */
2
+ /*
3
+ * Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org>
4
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
5
+ * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
6
+ *
7
+ * Permission to use, copy, modify, and distribute this software for any
8
+ * purpose with or without fee is hereby granted, provided that the above
9
+ * copyright notice and this permission notice appear in all copies.
10
+ *
11
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
12
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
14
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+ *
19
+ * Plain text formatter for mdoc(7), used by mandoc(1)
20
+ * for ASCII, UTF-8, PostScript, and PDF output.
21
+ */
22
+ #include "config.h"
23
+
24
+ #include <sys/types.h>
25
+
26
+ #include <assert.h>
27
+ #include <ctype.h>
28
+ #include <limits.h>
29
+ #include <stdint.h>
30
+ #include <stdio.h>
31
+ #include <stdlib.h>
32
+ #include <string.h>
33
+
34
+ #include "mandoc_aux.h"
35
+ #include "roff.h"
36
+ #include "mdoc.h"
37
+ #include "out.h"
38
+ #include "term.h"
39
+ #include "term_tag.h"
40
+ #include "main.h"
41
+
42
+ struct termpair {
43
+ struct termpair *ppair;
44
+ int count;
45
+ };
46
+
47
+ #define DECL_ARGS struct termp *p, \
48
+ struct termpair *pair, \
49
+ const struct roff_meta *meta, \
50
+ struct roff_node *n
51
+
52
+ struct mdoc_term_act {
53
+ int (*pre)(DECL_ARGS);
54
+ void (*post)(DECL_ARGS);
55
+ };
56
+
57
+ static int a2width(const struct termp *, const char *);
58
+
59
+ static void print_bvspace(struct termp *,
60
+ struct roff_node *, struct roff_node *);
61
+ static void print_mdoc_node(DECL_ARGS);
62
+ static void print_mdoc_nodelist(DECL_ARGS);
63
+ static void print_mdoc_head(struct termp *, const struct roff_meta *);
64
+ static void print_mdoc_foot(struct termp *, const struct roff_meta *);
65
+ static void synopsis_pre(struct termp *, struct roff_node *);
66
+
67
+ static void termp____post(DECL_ARGS);
68
+ static void termp__t_post(DECL_ARGS);
69
+ static void termp_bd_post(DECL_ARGS);
70
+ static void termp_bk_post(DECL_ARGS);
71
+ static void termp_bl_post(DECL_ARGS);
72
+ static void termp_eo_post(DECL_ARGS);
73
+ static void termp_fd_post(DECL_ARGS);
74
+ static void termp_fo_post(DECL_ARGS);
75
+ static void termp_in_post(DECL_ARGS);
76
+ static void termp_it_post(DECL_ARGS);
77
+ static void termp_lb_post(DECL_ARGS);
78
+ static void termp_nm_post(DECL_ARGS);
79
+ static void termp_pf_post(DECL_ARGS);
80
+ static void termp_quote_post(DECL_ARGS);
81
+ static void termp_sh_post(DECL_ARGS);
82
+ static void termp_ss_post(DECL_ARGS);
83
+ static void termp_xx_post(DECL_ARGS);
84
+
85
+ static int termp__a_pre(DECL_ARGS);
86
+ static int termp__t_pre(DECL_ARGS);
87
+ static int termp_abort_pre(DECL_ARGS);
88
+ static int termp_an_pre(DECL_ARGS);
89
+ static int termp_ap_pre(DECL_ARGS);
90
+ static int termp_bd_pre(DECL_ARGS);
91
+ static int termp_bf_pre(DECL_ARGS);
92
+ static int termp_bk_pre(DECL_ARGS);
93
+ static int termp_bl_pre(DECL_ARGS);
94
+ static int termp_bold_pre(DECL_ARGS);
95
+ static int termp_d1_pre(DECL_ARGS);
96
+ static int termp_eo_pre(DECL_ARGS);
97
+ static int termp_ex_pre(DECL_ARGS);
98
+ static int termp_fa_pre(DECL_ARGS);
99
+ static int termp_fd_pre(DECL_ARGS);
100
+ static int termp_fl_pre(DECL_ARGS);
101
+ static int termp_fn_pre(DECL_ARGS);
102
+ static int termp_fo_pre(DECL_ARGS);
103
+ static int termp_ft_pre(DECL_ARGS);
104
+ static int termp_in_pre(DECL_ARGS);
105
+ static int termp_it_pre(DECL_ARGS);
106
+ static int termp_li_pre(DECL_ARGS);
107
+ static int termp_lk_pre(DECL_ARGS);
108
+ static int termp_nd_pre(DECL_ARGS);
109
+ static int termp_nm_pre(DECL_ARGS);
110
+ static int termp_ns_pre(DECL_ARGS);
111
+ static int termp_quote_pre(DECL_ARGS);
112
+ static int termp_rs_pre(DECL_ARGS);
113
+ static int termp_sh_pre(DECL_ARGS);
114
+ static int termp_skip_pre(DECL_ARGS);
115
+ static int termp_sm_pre(DECL_ARGS);
116
+ static int termp_pp_pre(DECL_ARGS);
117
+ static int termp_ss_pre(DECL_ARGS);
118
+ static int termp_under_pre(DECL_ARGS);
119
+ static int termp_vt_pre(DECL_ARGS);
120
+ static int termp_xr_pre(DECL_ARGS);
121
+ static int termp_xx_pre(DECL_ARGS);
122
+
123
+ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
124
+ { NULL, NULL }, /* Dd */
125
+ { NULL, NULL }, /* Dt */
126
+ { NULL, NULL }, /* Os */
127
+ { termp_sh_pre, termp_sh_post }, /* Sh */
128
+ { termp_ss_pre, termp_ss_post }, /* Ss */
129
+ { termp_pp_pre, NULL }, /* Pp */
130
+ { termp_d1_pre, termp_bl_post }, /* D1 */
131
+ { termp_d1_pre, termp_bl_post }, /* Dl */
132
+ { termp_bd_pre, termp_bd_post }, /* Bd */
133
+ { NULL, NULL }, /* Ed */
134
+ { termp_bl_pre, termp_bl_post }, /* Bl */
135
+ { NULL, NULL }, /* El */
136
+ { termp_it_pre, termp_it_post }, /* It */
137
+ { termp_under_pre, NULL }, /* Ad */
138
+ { termp_an_pre, NULL }, /* An */
139
+ { termp_ap_pre, NULL }, /* Ap */
140
+ { termp_under_pre, NULL }, /* Ar */
141
+ { termp_fd_pre, NULL }, /* Cd */
142
+ { termp_bold_pre, NULL }, /* Cm */
143
+ { termp_li_pre, NULL }, /* Dv */
144
+ { NULL, NULL }, /* Er */
145
+ { NULL, NULL }, /* Ev */
146
+ { termp_ex_pre, NULL }, /* Ex */
147
+ { termp_fa_pre, NULL }, /* Fa */
148
+ { termp_fd_pre, termp_fd_post }, /* Fd */
149
+ { termp_fl_pre, NULL }, /* Fl */
150
+ { termp_fn_pre, NULL }, /* Fn */
151
+ { termp_ft_pre, NULL }, /* Ft */
152
+ { termp_bold_pre, NULL }, /* Ic */
153
+ { termp_in_pre, termp_in_post }, /* In */
154
+ { termp_li_pre, NULL }, /* Li */
155
+ { termp_nd_pre, NULL }, /* Nd */
156
+ { termp_nm_pre, termp_nm_post }, /* Nm */
157
+ { termp_quote_pre, termp_quote_post }, /* Op */
158
+ { termp_abort_pre, NULL }, /* Ot */
159
+ { termp_under_pre, NULL }, /* Pa */
160
+ { termp_ex_pre, NULL }, /* Rv */
161
+ { NULL, NULL }, /* St */
162
+ { termp_under_pre, NULL }, /* Va */
163
+ { termp_vt_pre, NULL }, /* Vt */
164
+ { termp_xr_pre, NULL }, /* Xr */
165
+ { termp__a_pre, termp____post }, /* %A */
166
+ { termp_under_pre, termp____post }, /* %B */
167
+ { NULL, termp____post }, /* %D */
168
+ { termp_under_pre, termp____post }, /* %I */
169
+ { termp_under_pre, termp____post }, /* %J */
170
+ { NULL, termp____post }, /* %N */
171
+ { NULL, termp____post }, /* %O */
172
+ { NULL, termp____post }, /* %P */
173
+ { NULL, termp____post }, /* %R */
174
+ { termp__t_pre, termp__t_post }, /* %T */
175
+ { NULL, termp____post }, /* %V */
176
+ { NULL, NULL }, /* Ac */
177
+ { termp_quote_pre, termp_quote_post }, /* Ao */
178
+ { termp_quote_pre, termp_quote_post }, /* Aq */
179
+ { NULL, NULL }, /* At */
180
+ { NULL, NULL }, /* Bc */
181
+ { termp_bf_pre, NULL }, /* Bf */
182
+ { termp_quote_pre, termp_quote_post }, /* Bo */
183
+ { termp_quote_pre, termp_quote_post }, /* Bq */
184
+ { termp_xx_pre, termp_xx_post }, /* Bsx */
185
+ { NULL, NULL }, /* Bx */
186
+ { termp_skip_pre, NULL }, /* Db */
187
+ { NULL, NULL }, /* Dc */
188
+ { termp_quote_pre, termp_quote_post }, /* Do */
189
+ { termp_quote_pre, termp_quote_post }, /* Dq */
190
+ { NULL, NULL }, /* Ec */ /* FIXME: no space */
191
+ { NULL, NULL }, /* Ef */
192
+ { termp_under_pre, NULL }, /* Em */
193
+ { termp_eo_pre, termp_eo_post }, /* Eo */
194
+ { termp_xx_pre, termp_xx_post }, /* Fx */
195
+ { termp_bold_pre, NULL }, /* Ms */
196
+ { termp_li_pre, NULL }, /* No */
197
+ { termp_ns_pre, NULL }, /* Ns */
198
+ { termp_xx_pre, termp_xx_post }, /* Nx */
199
+ { termp_xx_pre, termp_xx_post }, /* Ox */
200
+ { NULL, NULL }, /* Pc */
201
+ { NULL, termp_pf_post }, /* Pf */
202
+ { termp_quote_pre, termp_quote_post }, /* Po */
203
+ { termp_quote_pre, termp_quote_post }, /* Pq */
204
+ { NULL, NULL }, /* Qc */
205
+ { termp_quote_pre, termp_quote_post }, /* Ql */
206
+ { termp_quote_pre, termp_quote_post }, /* Qo */
207
+ { termp_quote_pre, termp_quote_post }, /* Qq */
208
+ { NULL, NULL }, /* Re */
209
+ { termp_rs_pre, NULL }, /* Rs */
210
+ { NULL, NULL }, /* Sc */
211
+ { termp_quote_pre, termp_quote_post }, /* So */
212
+ { termp_quote_pre, termp_quote_post }, /* Sq */
213
+ { termp_sm_pre, NULL }, /* Sm */
214
+ { termp_under_pre, NULL }, /* Sx */
215
+ { termp_bold_pre, NULL }, /* Sy */
216
+ { NULL, NULL }, /* Tn */
217
+ { termp_xx_pre, termp_xx_post }, /* Ux */
218
+ { NULL, NULL }, /* Xc */
219
+ { NULL, NULL }, /* Xo */
220
+ { termp_fo_pre, termp_fo_post }, /* Fo */
221
+ { NULL, NULL }, /* Fc */
222
+ { termp_quote_pre, termp_quote_post }, /* Oo */
223
+ { NULL, NULL }, /* Oc */
224
+ { termp_bk_pre, termp_bk_post }, /* Bk */
225
+ { NULL, NULL }, /* Ek */
226
+ { NULL, NULL }, /* Bt */
227
+ { NULL, NULL }, /* Hf */
228
+ { termp_under_pre, NULL }, /* Fr */
229
+ { NULL, NULL }, /* Ud */
230
+ { NULL, termp_lb_post }, /* Lb */
231
+ { termp_abort_pre, NULL }, /* Lp */
232
+ { termp_lk_pre, NULL }, /* Lk */
233
+ { termp_under_pre, NULL }, /* Mt */
234
+ { termp_quote_pre, termp_quote_post }, /* Brq */
235
+ { termp_quote_pre, termp_quote_post }, /* Bro */
236
+ { NULL, NULL }, /* Brc */
237
+ { NULL, termp____post }, /* %C */
238
+ { termp_skip_pre, NULL }, /* Es */
239
+ { termp_quote_pre, termp_quote_post }, /* En */
240
+ { termp_xx_pre, termp_xx_post }, /* Dx */
241
+ { NULL, termp____post }, /* %Q */
242
+ { NULL, termp____post }, /* %U */
243
+ { NULL, NULL }, /* Ta */
244
+ { termp_skip_pre, NULL }, /* Tg */
245
+ };
246
+
247
+
248
+ void
249
+ terminal_mdoc(void *arg, const struct roff_meta *mdoc)
250
+ {
251
+ struct roff_node *n, *nn;
252
+ struct termp *p;
253
+ size_t save_defindent;
254
+
255
+ p = (struct termp *)arg;
256
+ p->tcol->rmargin = p->maxrmargin = p->defrmargin;
257
+ term_tab_set(p, NULL);
258
+ term_tab_set(p, "T");
259
+ term_tab_set(p, ".5i");
260
+
261
+ n = mdoc->first->child;
262
+ if (p->synopsisonly) {
263
+ for (nn = NULL; n != NULL; n = n->next) {
264
+ if (n->tok != MDOC_Sh)
265
+ continue;
266
+ if (n->sec == SEC_SYNOPSIS)
267
+ break;
268
+ if (nn == NULL && n->sec == SEC_NAME)
269
+ nn = n;
270
+ }
271
+ if (n == NULL)
272
+ n = nn;
273
+ p->flags |= TERMP_NOSPACE;
274
+ if (n != NULL && (n = n->child->next->child) != NULL)
275
+ print_mdoc_nodelist(p, NULL, mdoc, n);
276
+ term_newln(p);
277
+ } else {
278
+ save_defindent = p->defindent;
279
+ if (p->defindent == 0)
280
+ p->defindent = 5;
281
+ term_begin(p, print_mdoc_head, print_mdoc_foot, mdoc);
282
+ while (n != NULL &&
283
+ (n->type == ROFFT_COMMENT ||
284
+ n->flags & NODE_NOPRT))
285
+ n = n->next;
286
+ if (n != NULL) {
287
+ if (n->tok != MDOC_Sh)
288
+ term_vspace(p);
289
+ print_mdoc_nodelist(p, NULL, mdoc, n);
290
+ }
291
+ term_end(p);
292
+ p->defindent = save_defindent;
293
+ }
294
+ }
295
+
296
+ static void
297
+ print_mdoc_nodelist(DECL_ARGS)
298
+ {
299
+ while (n != NULL) {
300
+ print_mdoc_node(p, pair, meta, n);
301
+ n = n->next;
302
+ }
303
+ }
304
+
305
+ static void
306
+ print_mdoc_node(DECL_ARGS)
307
+ {
308
+ const struct mdoc_term_act *act;
309
+ struct termpair npair;
310
+ size_t offset, rmargin;
311
+ int chld;
312
+
313
+ /*
314
+ * In no-fill mode, break the output line at the beginning
315
+ * of new input lines except after \c, and nowhere else.
316
+ */
317
+
318
+ if (n->flags & NODE_NOFILL) {
319
+ if (n->flags & NODE_LINE &&
320
+ (p->flags & TERMP_NONEWLINE) == 0)
321
+ term_newln(p);
322
+ p->flags |= TERMP_BRNEVER;
323
+ } else
324
+ p->flags &= ~TERMP_BRNEVER;
325
+
326
+ if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
327
+ return;
328
+
329
+ chld = 1;
330
+ offset = p->tcol->offset;
331
+ rmargin = p->tcol->rmargin;
332
+ n->flags &= ~NODE_ENDED;
333
+ n->prev_font = p->fonti;
334
+
335
+ memset(&npair, 0, sizeof(struct termpair));
336
+ npair.ppair = pair;
337
+
338
+ if (n->flags & NODE_ID && n->tok != MDOC_Pp &&
339
+ (n->tok != MDOC_It || n->type != ROFFT_BLOCK))
340
+ term_tag_write(n, p->line);
341
+
342
+ /*
343
+ * Keeps only work until the end of a line. If a keep was
344
+ * invoked in a prior line, revert it to PREKEEP.
345
+ */
346
+
347
+ if (p->flags & TERMP_KEEP && n->flags & NODE_LINE) {
348
+ p->flags &= ~TERMP_KEEP;
349
+ p->flags |= TERMP_PREKEEP;
350
+ }
351
+
352
+ /*
353
+ * After the keep flags have been set up, we may now
354
+ * produce output. Note that some pre-handlers do so.
355
+ */
356
+
357
+ act = NULL;
358
+ switch (n->type) {
359
+ case ROFFT_TEXT:
360
+ if (n->flags & NODE_LINE) {
361
+ switch (*n->string) {
362
+ case '\0':
363
+ if (p->flags & TERMP_NONEWLINE)
364
+ term_newln(p);
365
+ else
366
+ term_vspace(p);
367
+ return;
368
+ case ' ':
369
+ if ((p->flags & TERMP_NONEWLINE) == 0)
370
+ term_newln(p);
371
+ break;
372
+ default:
373
+ break;
374
+ }
375
+ }
376
+ if (NODE_DELIMC & n->flags)
377
+ p->flags |= TERMP_NOSPACE;
378
+ term_word(p, n->string);
379
+ if (NODE_DELIMO & n->flags)
380
+ p->flags |= TERMP_NOSPACE;
381
+ break;
382
+ case ROFFT_EQN:
383
+ if ( ! (n->flags & NODE_LINE))
384
+ p->flags |= TERMP_NOSPACE;
385
+ term_eqn(p, n->eqn);
386
+ if (n->next != NULL && ! (n->next->flags & NODE_LINE))
387
+ p->flags |= TERMP_NOSPACE;
388
+ break;
389
+ case ROFFT_TBL:
390
+ if (p->tbl.cols == NULL)
391
+ term_newln(p);
392
+ term_tbl(p, n->span);
393
+ break;
394
+ default:
395
+ if (n->tok < ROFF_MAX) {
396
+ roff_term_pre(p, n);
397
+ return;
398
+ }
399
+ assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
400
+ act = mdoc_term_acts + (n->tok - MDOC_Dd);
401
+ if (act->pre != NULL &&
402
+ (n->end == ENDBODY_NOT || n->child != NULL))
403
+ chld = (*act->pre)(p, &npair, meta, n);
404
+ break;
405
+ }
406
+
407
+ if (chld && n->child)
408
+ print_mdoc_nodelist(p, &npair, meta, n->child);
409
+
410
+ term_fontpopq(p,
411
+ (ENDBODY_NOT == n->end ? n : n->body)->prev_font);
412
+
413
+ switch (n->type) {
414
+ case ROFFT_TEXT:
415
+ break;
416
+ case ROFFT_TBL:
417
+ break;
418
+ case ROFFT_EQN:
419
+ break;
420
+ default:
421
+ if (act->post == NULL || n->flags & NODE_ENDED)
422
+ break;
423
+ (void)(*act->post)(p, &npair, meta, n);
424
+
425
+ /*
426
+ * Explicit end tokens not only call the post
427
+ * handler, but also tell the respective block
428
+ * that it must not call the post handler again.
429
+ */
430
+ if (ENDBODY_NOT != n->end)
431
+ n->body->flags |= NODE_ENDED;
432
+ break;
433
+ }
434
+
435
+ if (NODE_EOS & n->flags)
436
+ p->flags |= TERMP_SENTENCE;
437
+
438
+ if (n->type != ROFFT_TEXT)
439
+ p->tcol->offset = offset;
440
+ p->tcol->rmargin = rmargin;
441
+ }
442
+
443
+ static void
444
+ print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
445
+ {
446
+ size_t sz;
447
+
448
+ term_fontrepl(p, TERMFONT_NONE);
449
+
450
+ /*
451
+ * Output the footer in new-groff style, that is, three columns
452
+ * with the middle being the manual date and flanking columns
453
+ * being the operating system:
454
+ *
455
+ * SYSTEM DATE SYSTEM
456
+ */
457
+
458
+ term_vspace(p);
459
+
460
+ p->tcol->offset = 0;
461
+ sz = term_strlen(p, meta->date);
462
+ p->tcol->rmargin = p->maxrmargin > sz ?
463
+ (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
464
+ p->trailspace = 1;
465
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
466
+
467
+ term_word(p, meta->os);
468
+ term_flushln(p);
469
+
470
+ p->tcol->offset = p->tcol->rmargin;
471
+ sz = term_strlen(p, meta->os);
472
+ p->tcol->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
473
+ p->flags |= TERMP_NOSPACE;
474
+
475
+ term_word(p, meta->date);
476
+ term_flushln(p);
477
+
478
+ p->tcol->offset = p->tcol->rmargin;
479
+ p->tcol->rmargin = p->maxrmargin;
480
+ p->trailspace = 0;
481
+ p->flags &= ~TERMP_NOBREAK;
482
+ p->flags |= TERMP_NOSPACE;
483
+
484
+ term_word(p, meta->os);
485
+ term_flushln(p);
486
+
487
+ p->tcol->offset = 0;
488
+ p->tcol->rmargin = p->maxrmargin;
489
+ p->flags = 0;
490
+ }
491
+
492
+ static void
493
+ print_mdoc_head(struct termp *p, const struct roff_meta *meta)
494
+ {
495
+ char *volume, *title;
496
+ size_t vollen, titlen;
497
+
498
+ /*
499
+ * The header is strange. It has three components, which are
500
+ * really two with the first duplicated. It goes like this:
501
+ *
502
+ * IDENTIFIER TITLE IDENTIFIER
503
+ *
504
+ * The IDENTIFIER is NAME(SECTION), which is the command-name
505
+ * (if given, or "unknown" if not) followed by the manual page
506
+ * section. These are given in `Dt'. The TITLE is a free-form
507
+ * string depending on the manual volume. If not specified, it
508
+ * switches on the manual section.
509
+ */
510
+
511
+ assert(meta->vol);
512
+ if (NULL == meta->arch)
513
+ volume = mandoc_strdup(meta->vol);
514
+ else
515
+ mandoc_asprintf(&volume, "%s (%s)",
516
+ meta->vol, meta->arch);
517
+ vollen = term_strlen(p, volume);
518
+
519
+ if (NULL == meta->msec)
520
+ title = mandoc_strdup(meta->title);
521
+ else
522
+ mandoc_asprintf(&title, "%s(%s)",
523
+ meta->title, meta->msec);
524
+ titlen = term_strlen(p, title);
525
+
526
+ p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
527
+ p->trailspace = 1;
528
+ p->tcol->offset = 0;
529
+ p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
530
+ (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
531
+ vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
532
+
533
+ term_word(p, title);
534
+ term_flushln(p);
535
+
536
+ p->flags |= TERMP_NOSPACE;
537
+ p->tcol->offset = p->tcol->rmargin;
538
+ p->tcol->rmargin = p->tcol->offset + vollen + titlen <
539
+ p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
540
+
541
+ term_word(p, volume);
542
+ term_flushln(p);
543
+
544
+ p->flags &= ~TERMP_NOBREAK;
545
+ p->trailspace = 0;
546
+ if (p->tcol->rmargin + titlen <= p->maxrmargin) {
547
+ p->flags |= TERMP_NOSPACE;
548
+ p->tcol->offset = p->tcol->rmargin;
549
+ p->tcol->rmargin = p->maxrmargin;
550
+ term_word(p, title);
551
+ term_flushln(p);
552
+ }
553
+
554
+ p->flags &= ~TERMP_NOSPACE;
555
+ p->tcol->offset = 0;
556
+ p->tcol->rmargin = p->maxrmargin;
557
+ free(title);
558
+ free(volume);
559
+ }
560
+
561
+ static int
562
+ a2width(const struct termp *p, const char *v)
563
+ {
564
+ struct roffsu su;
565
+ const char *end;
566
+
567
+ end = a2roffsu(v, &su, SCALE_MAX);
568
+ if (end == NULL || *end != '\0') {
569
+ SCALE_HS_INIT(&su, term_strlen(p, v));
570
+ su.scale /= term_strlen(p, "0");
571
+ }
572
+ return term_hen(p, &su);
573
+ }
574
+
575
+ /*
576
+ * Determine how much space to print out before block elements of `It'
577
+ * (and thus `Bl') and `Bd'. And then go ahead and print that space,
578
+ * too.
579
+ */
580
+ static void
581
+ print_bvspace(struct termp *p, struct roff_node *bl, struct roff_node *n)
582
+ {
583
+ struct roff_node *nn;
584
+
585
+ term_newln(p);
586
+
587
+ if ((bl->tok == MDOC_Bd && bl->norm->Bd.comp) ||
588
+ (bl->tok == MDOC_Bl && bl->norm->Bl.comp))
589
+ return;
590
+
591
+ /* Do not vspace directly after Ss/Sh. */
592
+
593
+ nn = n;
594
+ while (roff_node_prev(nn) == NULL) {
595
+ do {
596
+ nn = nn->parent;
597
+ if (nn->type == ROFFT_ROOT)
598
+ return;
599
+ } while (nn->type != ROFFT_BLOCK);
600
+ if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
601
+ return;
602
+ if (nn->tok == MDOC_It &&
603
+ nn->parent->parent->norm->Bl.type != LIST_item)
604
+ break;
605
+ }
606
+
607
+ /*
608
+ * No vertical space after:
609
+ * items in .Bl -column
610
+ * items without a body in .Bl -diag
611
+ */
612
+
613
+ if (bl->tok != MDOC_Bl ||
614
+ n->prev == NULL || n->prev->tok != MDOC_It ||
615
+ (bl->norm->Bl.type != LIST_column &&
616
+ (bl->norm->Bl.type != LIST_diag ||
617
+ n->prev->body->child != NULL)))
618
+ term_vspace(p);
619
+ }
620
+
621
+
622
+ static int
623
+ termp_it_pre(DECL_ARGS)
624
+ {
625
+ struct roffsu su;
626
+ char buf[24];
627
+ const struct roff_node *bl, *nn;
628
+ size_t ncols, dcol;
629
+ int i, offset, width;
630
+ enum mdoc_list type;
631
+
632
+ if (n->type == ROFFT_BLOCK) {
633
+ print_bvspace(p, n->parent->parent, n);
634
+ if (n->flags & NODE_ID)
635
+ term_tag_write(n, p->line);
636
+ return 1;
637
+ }
638
+
639
+ bl = n->parent->parent->parent;
640
+ type = bl->norm->Bl.type;
641
+
642
+ /*
643
+ * Defaults for specific list types.
644
+ */
645
+
646
+ switch (type) {
647
+ case LIST_bullet:
648
+ case LIST_dash:
649
+ case LIST_hyphen:
650
+ case LIST_enum:
651
+ width = term_len(p, 2);
652
+ break;
653
+ case LIST_hang:
654
+ case LIST_tag:
655
+ width = term_len(p, 8);
656
+ break;
657
+ case LIST_column:
658
+ width = term_len(p, 10);
659
+ break;
660
+ default:
661
+ width = 0;
662
+ break;
663
+ }
664
+ offset = 0;
665
+
666
+ /*
667
+ * First calculate width and offset. This is pretty easy unless
668
+ * we're a -column list, in which case all prior columns must
669
+ * be accounted for.
670
+ */
671
+
672
+ if (bl->norm->Bl.offs != NULL) {
673
+ offset = a2width(p, bl->norm->Bl.offs);
674
+ if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
675
+ offset = -p->tcol->offset;
676
+ else if (offset > SHRT_MAX)
677
+ offset = 0;
678
+ }
679
+
680
+ switch (type) {
681
+ case LIST_column:
682
+ if (n->type == ROFFT_HEAD)
683
+ break;
684
+
685
+ /*
686
+ * Imitate groff's column handling:
687
+ * - For each earlier column, add its width.
688
+ * - For less than 5 columns, add four more blanks per
689
+ * column.
690
+ * - For exactly 5 columns, add three more blank per
691
+ * column.
692
+ * - For more than 5 columns, add only one column.
693
+ */
694
+ ncols = bl->norm->Bl.ncols;
695
+ dcol = ncols < 5 ? term_len(p, 4) :
696
+ ncols == 5 ? term_len(p, 3) : term_len(p, 1);
697
+
698
+ /*
699
+ * Calculate the offset by applying all prior ROFFT_BODY,
700
+ * so we stop at the ROFFT_HEAD (nn->prev == NULL).
701
+ */
702
+
703
+ for (i = 0, nn = n->prev;
704
+ nn->prev && i < (int)ncols;
705
+ nn = nn->prev, i++) {
706
+ SCALE_HS_INIT(&su,
707
+ term_strlen(p, bl->norm->Bl.cols[i]));
708
+ su.scale /= term_strlen(p, "0");
709
+ offset += term_hen(p, &su) + dcol;
710
+ }
711
+
712
+ /*
713
+ * When exceeding the declared number of columns, leave
714
+ * the remaining widths at 0. This will later be
715
+ * adjusted to the default width of 10, or, for the last
716
+ * column, stretched to the right margin.
717
+ */
718
+ if (i >= (int)ncols)
719
+ break;
720
+
721
+ /*
722
+ * Use the declared column widths, extended as explained
723
+ * in the preceding paragraph.
724
+ */
725
+ SCALE_HS_INIT(&su, term_strlen(p, bl->norm->Bl.cols[i]));
726
+ su.scale /= term_strlen(p, "0");
727
+ width = term_hen(p, &su) + dcol;
728
+ break;
729
+ default:
730
+ if (NULL == bl->norm->Bl.width)
731
+ break;
732
+
733
+ /*
734
+ * Note: buffer the width by 2, which is groff's magic
735
+ * number for buffering single arguments. See the above
736
+ * handling for column for how this changes.
737
+ */
738
+ width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
739
+ if (width < 0 && (size_t)(-width) > p->tcol->offset)
740
+ width = -p->tcol->offset;
741
+ else if (width > SHRT_MAX)
742
+ width = 0;
743
+ break;
744
+ }
745
+
746
+ /*
747
+ * Whitespace control. Inset bodies need an initial space,
748
+ * while diagonal bodies need two.
749
+ */
750
+
751
+ p->flags |= TERMP_NOSPACE;
752
+
753
+ switch (type) {
754
+ case LIST_diag:
755
+ if (n->type == ROFFT_BODY)
756
+ term_word(p, "\\ \\ ");
757
+ break;
758
+ case LIST_inset:
759
+ if (n->type == ROFFT_BODY && n->parent->head->child != NULL)
760
+ term_word(p, "\\ ");
761
+ break;
762
+ default:
763
+ break;
764
+ }
765
+
766
+ p->flags |= TERMP_NOSPACE;
767
+
768
+ switch (type) {
769
+ case LIST_diag:
770
+ if (n->type == ROFFT_HEAD)
771
+ term_fontpush(p, TERMFONT_BOLD);
772
+ break;
773
+ default:
774
+ break;
775
+ }
776
+
777
+ /*
778
+ * Pad and break control. This is the tricky part. These flags
779
+ * are documented in term_flushln() in term.c. Note that we're
780
+ * going to unset all of these flags in termp_it_post() when we
781
+ * exit.
782
+ */
783
+
784
+ switch (type) {
785
+ case LIST_enum:
786
+ case LIST_bullet:
787
+ case LIST_dash:
788
+ case LIST_hyphen:
789
+ if (n->type == ROFFT_HEAD) {
790
+ p->flags |= TERMP_NOBREAK | TERMP_HANG;
791
+ p->trailspace = 1;
792
+ } else if (width <= (int)term_len(p, 2))
793
+ p->flags |= TERMP_NOPAD;
794
+ break;
795
+ case LIST_hang:
796
+ if (n->type != ROFFT_HEAD)
797
+ break;
798
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
799
+ p->trailspace = 1;
800
+ break;
801
+ case LIST_tag:
802
+ if (n->type != ROFFT_HEAD)
803
+ break;
804
+
805
+ p->flags |= TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND;
806
+ p->trailspace = 2;
807
+
808
+ if (NULL == n->next || NULL == n->next->child)
809
+ p->flags |= TERMP_HANG;
810
+ break;
811
+ case LIST_column:
812
+ if (n->type == ROFFT_HEAD)
813
+ break;
814
+
815
+ if (NULL == n->next) {
816
+ p->flags &= ~TERMP_NOBREAK;
817
+ p->trailspace = 0;
818
+ } else {
819
+ p->flags |= TERMP_NOBREAK;
820
+ p->trailspace = 1;
821
+ }
822
+
823
+ break;
824
+ case LIST_diag:
825
+ if (n->type != ROFFT_HEAD)
826
+ break;
827
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
828
+ p->trailspace = 1;
829
+ break;
830
+ default:
831
+ break;
832
+ }
833
+
834
+ /*
835
+ * Margin control. Set-head-width lists have their right
836
+ * margins shortened. The body for these lists has the offset
837
+ * necessarily lengthened. Everybody gets the offset.
838
+ */
839
+
840
+ p->tcol->offset += offset;
841
+
842
+ switch (type) {
843
+ case LIST_bullet:
844
+ case LIST_dash:
845
+ case LIST_enum:
846
+ case LIST_hyphen:
847
+ case LIST_hang:
848
+ case LIST_tag:
849
+ if (n->type == ROFFT_HEAD)
850
+ p->tcol->rmargin = p->tcol->offset + width;
851
+ else
852
+ p->tcol->offset += width;
853
+ break;
854
+ case LIST_column:
855
+ assert(width);
856
+ p->tcol->rmargin = p->tcol->offset + width;
857
+ /*
858
+ * XXX - this behaviour is not documented: the
859
+ * right-most column is filled to the right margin.
860
+ */
861
+ if (n->type == ROFFT_HEAD)
862
+ break;
863
+ if (n->next == NULL && p->tcol->rmargin < p->maxrmargin)
864
+ p->tcol->rmargin = p->maxrmargin;
865
+ break;
866
+ default:
867
+ break;
868
+ }
869
+
870
+ /*
871
+ * The dash, hyphen, bullet and enum lists all have a special
872
+ * HEAD character (temporarily bold, in some cases).
873
+ */
874
+
875
+ if (n->type == ROFFT_HEAD)
876
+ switch (type) {
877
+ case LIST_bullet:
878
+ term_fontpush(p, TERMFONT_BOLD);
879
+ term_word(p, "\\[bu]");
880
+ term_fontpop(p);
881
+ break;
882
+ case LIST_dash:
883
+ case LIST_hyphen:
884
+ term_fontpush(p, TERMFONT_BOLD);
885
+ term_word(p, "-");
886
+ term_fontpop(p);
887
+ break;
888
+ case LIST_enum:
889
+ (pair->ppair->ppair->count)++;
890
+ (void)snprintf(buf, sizeof(buf), "%d.",
891
+ pair->ppair->ppair->count);
892
+ term_word(p, buf);
893
+ break;
894
+ default:
895
+ break;
896
+ }
897
+
898
+ /*
899
+ * If we're not going to process our children, indicate so here.
900
+ */
901
+
902
+ switch (type) {
903
+ case LIST_bullet:
904
+ case LIST_item:
905
+ case LIST_dash:
906
+ case LIST_hyphen:
907
+ case LIST_enum:
908
+ if (n->type == ROFFT_HEAD)
909
+ return 0;
910
+ break;
911
+ case LIST_column:
912
+ if (n->type == ROFFT_HEAD)
913
+ return 0;
914
+ p->minbl = 0;
915
+ break;
916
+ default:
917
+ break;
918
+ }
919
+
920
+ return 1;
921
+ }
922
+
923
+ static void
924
+ termp_it_post(DECL_ARGS)
925
+ {
926
+ enum mdoc_list type;
927
+
928
+ if (n->type == ROFFT_BLOCK)
929
+ return;
930
+
931
+ type = n->parent->parent->parent->norm->Bl.type;
932
+
933
+ switch (type) {
934
+ case LIST_item:
935
+ case LIST_diag:
936
+ case LIST_inset:
937
+ if (n->type == ROFFT_BODY)
938
+ term_newln(p);
939
+ break;
940
+ case LIST_column:
941
+ if (n->type == ROFFT_BODY)
942
+ term_flushln(p);
943
+ break;
944
+ default:
945
+ term_newln(p);
946
+ break;
947
+ }
948
+
949
+ /*
950
+ * Now that our output is flushed, we can reset our tags. Since
951
+ * only `It' sets these flags, we're free to assume that nobody
952
+ * has munged them in the meanwhile.
953
+ */
954
+
955
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND | TERMP_HANG);
956
+ p->trailspace = 0;
957
+ }
958
+
959
+ static int
960
+ termp_nm_pre(DECL_ARGS)
961
+ {
962
+ const char *cp;
963
+
964
+ if (n->type == ROFFT_BLOCK) {
965
+ p->flags |= TERMP_PREKEEP;
966
+ return 1;
967
+ }
968
+
969
+ if (n->type == ROFFT_BODY) {
970
+ if (n->child == NULL)
971
+ return 0;
972
+ p->flags |= TERMP_NOSPACE;
973
+ cp = NULL;
974
+ if (n->prev->child != NULL)
975
+ cp = n->prev->child->string;
976
+ if (cp == NULL)
977
+ cp = meta->name;
978
+ if (cp == NULL)
979
+ p->tcol->offset += term_len(p, 6);
980
+ else
981
+ p->tcol->offset += term_len(p, 1) +
982
+ term_strlen(p, cp);
983
+ return 1;
984
+ }
985
+
986
+ if (n->child == NULL)
987
+ return 0;
988
+
989
+ if (n->type == ROFFT_HEAD)
990
+ synopsis_pre(p, n->parent);
991
+
992
+ if (n->type == ROFFT_HEAD &&
993
+ n->next != NULL && n->next->child != NULL) {
994
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
995
+ p->trailspace = 1;
996
+ p->tcol->rmargin = p->tcol->offset + term_len(p, 1);
997
+ if (n->child == NULL)
998
+ p->tcol->rmargin += term_strlen(p, meta->name);
999
+ else if (n->child->type == ROFFT_TEXT) {
1000
+ p->tcol->rmargin += term_strlen(p, n->child->string);
1001
+ if (n->child->next != NULL)
1002
+ p->flags |= TERMP_HANG;
1003
+ } else {
1004
+ p->tcol->rmargin += term_len(p, 5);
1005
+ p->flags |= TERMP_HANG;
1006
+ }
1007
+ }
1008
+ return termp_bold_pre(p, pair, meta, n);
1009
+ }
1010
+
1011
+ static void
1012
+ termp_nm_post(DECL_ARGS)
1013
+ {
1014
+ switch (n->type) {
1015
+ case ROFFT_BLOCK:
1016
+ p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
1017
+ break;
1018
+ case ROFFT_HEAD:
1019
+ if (n->next == NULL || n->next->child == NULL)
1020
+ break;
1021
+ term_flushln(p);
1022
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
1023
+ p->trailspace = 0;
1024
+ break;
1025
+ case ROFFT_BODY:
1026
+ if (n->child != NULL)
1027
+ term_flushln(p);
1028
+ break;
1029
+ default:
1030
+ break;
1031
+ }
1032
+ }
1033
+
1034
+ static int
1035
+ termp_fl_pre(DECL_ARGS)
1036
+ {
1037
+ struct roff_node *nn;
1038
+
1039
+ term_fontpush(p, TERMFONT_BOLD);
1040
+ term_word(p, "\\-");
1041
+
1042
+ if (n->child != NULL ||
1043
+ ((nn = roff_node_next(n)) != NULL &&
1044
+ nn->type != ROFFT_TEXT &&
1045
+ (nn->flags & NODE_LINE) == 0))
1046
+ p->flags |= TERMP_NOSPACE;
1047
+
1048
+ return 1;
1049
+ }
1050
+
1051
+ static int
1052
+ termp__a_pre(DECL_ARGS)
1053
+ {
1054
+ struct roff_node *nn;
1055
+
1056
+ if ((nn = roff_node_prev(n)) != NULL && nn->tok == MDOC__A &&
1057
+ ((nn = roff_node_next(n)) == NULL || nn->tok != MDOC__A))
1058
+ term_word(p, "and");
1059
+
1060
+ return 1;
1061
+ }
1062
+
1063
+ static int
1064
+ termp_an_pre(DECL_ARGS)
1065
+ {
1066
+
1067
+ if (n->norm->An.auth == AUTH_split) {
1068
+ p->flags &= ~TERMP_NOSPLIT;
1069
+ p->flags |= TERMP_SPLIT;
1070
+ return 0;
1071
+ }
1072
+ if (n->norm->An.auth == AUTH_nosplit) {
1073
+ p->flags &= ~TERMP_SPLIT;
1074
+ p->flags |= TERMP_NOSPLIT;
1075
+ return 0;
1076
+ }
1077
+
1078
+ if (p->flags & TERMP_SPLIT)
1079
+ term_newln(p);
1080
+
1081
+ if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT))
1082
+ p->flags |= TERMP_SPLIT;
1083
+
1084
+ return 1;
1085
+ }
1086
+
1087
+ static int
1088
+ termp_ns_pre(DECL_ARGS)
1089
+ {
1090
+
1091
+ if ( ! (NODE_LINE & n->flags))
1092
+ p->flags |= TERMP_NOSPACE;
1093
+ return 1;
1094
+ }
1095
+
1096
+ static int
1097
+ termp_rs_pre(DECL_ARGS)
1098
+ {
1099
+ if (SEC_SEE_ALSO != n->sec)
1100
+ return 1;
1101
+ if (n->type == ROFFT_BLOCK && roff_node_prev(n) != NULL)
1102
+ term_vspace(p);
1103
+ return 1;
1104
+ }
1105
+
1106
+ static int
1107
+ termp_ex_pre(DECL_ARGS)
1108
+ {
1109
+ term_newln(p);
1110
+ return 1;
1111
+ }
1112
+
1113
+ static int
1114
+ termp_nd_pre(DECL_ARGS)
1115
+ {
1116
+ if (n->type == ROFFT_BODY)
1117
+ term_word(p, "\\(en");
1118
+ return 1;
1119
+ }
1120
+
1121
+ static int
1122
+ termp_bl_pre(DECL_ARGS)
1123
+ {
1124
+ switch (n->type) {
1125
+ case ROFFT_BLOCK:
1126
+ term_newln(p);
1127
+ return 1;
1128
+ case ROFFT_HEAD:
1129
+ return 0;
1130
+ default:
1131
+ return 1;
1132
+ }
1133
+ }
1134
+
1135
+ static void
1136
+ termp_bl_post(DECL_ARGS)
1137
+ {
1138
+ if (n->type != ROFFT_BLOCK)
1139
+ return;
1140
+ term_newln(p);
1141
+ if (n->tok != MDOC_Bl || n->norm->Bl.type != LIST_column)
1142
+ return;
1143
+ term_tab_set(p, NULL);
1144
+ term_tab_set(p, "T");
1145
+ term_tab_set(p, ".5i");
1146
+ }
1147
+
1148
+ static int
1149
+ termp_xr_pre(DECL_ARGS)
1150
+ {
1151
+ if (NULL == (n = n->child))
1152
+ return 0;
1153
+
1154
+ assert(n->type == ROFFT_TEXT);
1155
+ term_word(p, n->string);
1156
+
1157
+ if (NULL == (n = n->next))
1158
+ return 0;
1159
+
1160
+ p->flags |= TERMP_NOSPACE;
1161
+ term_word(p, "(");
1162
+ p->flags |= TERMP_NOSPACE;
1163
+
1164
+ assert(n->type == ROFFT_TEXT);
1165
+ term_word(p, n->string);
1166
+
1167
+ p->flags |= TERMP_NOSPACE;
1168
+ term_word(p, ")");
1169
+
1170
+ return 0;
1171
+ }
1172
+
1173
+ /*
1174
+ * This decides how to assert whitespace before any of the SYNOPSIS set
1175
+ * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain
1176
+ * macro combos).
1177
+ */
1178
+ static void
1179
+ synopsis_pre(struct termp *p, struct roff_node *n)
1180
+ {
1181
+ struct roff_node *np;
1182
+
1183
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
1184
+ (np = roff_node_prev(n)) == NULL)
1185
+ return;
1186
+
1187
+ /*
1188
+ * If we're the second in a pair of like elements, emit our
1189
+ * newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
1190
+ * case we soldier on.
1191
+ */
1192
+ if (np->tok == n->tok &&
1193
+ MDOC_Ft != n->tok &&
1194
+ MDOC_Fo != n->tok &&
1195
+ MDOC_Fn != n->tok) {
1196
+ term_newln(p);
1197
+ return;
1198
+ }
1199
+
1200
+ /*
1201
+ * If we're one of the SYNOPSIS set and non-like pair-wise after
1202
+ * another (or Fn/Fo, which we've let slip through) then assert
1203
+ * vertical space, else only newline and move on.
1204
+ */
1205
+ switch (np->tok) {
1206
+ case MDOC_Fd:
1207
+ case MDOC_Fn:
1208
+ case MDOC_Fo:
1209
+ case MDOC_In:
1210
+ case MDOC_Vt:
1211
+ term_vspace(p);
1212
+ break;
1213
+ case MDOC_Ft:
1214
+ if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
1215
+ term_vspace(p);
1216
+ break;
1217
+ }
1218
+ /* FALLTHROUGH */
1219
+ default:
1220
+ term_newln(p);
1221
+ break;
1222
+ }
1223
+ }
1224
+
1225
+ static int
1226
+ termp_vt_pre(DECL_ARGS)
1227
+ {
1228
+ switch (n->type) {
1229
+ case ROFFT_ELEM:
1230
+ return termp_ft_pre(p, pair, meta, n);
1231
+ case ROFFT_BLOCK:
1232
+ synopsis_pre(p, n);
1233
+ return 1;
1234
+ case ROFFT_HEAD:
1235
+ return 0;
1236
+ default:
1237
+ return termp_under_pre(p, pair, meta, n);
1238
+ }
1239
+ }
1240
+
1241
+ static int
1242
+ termp_bold_pre(DECL_ARGS)
1243
+ {
1244
+ term_fontpush(p, TERMFONT_BOLD);
1245
+ return 1;
1246
+ }
1247
+
1248
+ static int
1249
+ termp_fd_pre(DECL_ARGS)
1250
+ {
1251
+ synopsis_pre(p, n);
1252
+ return termp_bold_pre(p, pair, meta, n);
1253
+ }
1254
+
1255
+ static void
1256
+ termp_fd_post(DECL_ARGS)
1257
+ {
1258
+ term_newln(p);
1259
+ }
1260
+
1261
+ static int
1262
+ termp_sh_pre(DECL_ARGS)
1263
+ {
1264
+ struct roff_node *np;
1265
+
1266
+ switch (n->type) {
1267
+ case ROFFT_BLOCK:
1268
+ /*
1269
+ * Vertical space before sections, except
1270
+ * when the previous section was empty.
1271
+ */
1272
+ if ((np = roff_node_prev(n)) == NULL ||
1273
+ np->tok != MDOC_Sh ||
1274
+ (np->body != NULL && np->body->child != NULL))
1275
+ term_vspace(p);
1276
+ break;
1277
+ case ROFFT_HEAD:
1278
+ return termp_bold_pre(p, pair, meta, n);
1279
+ case ROFFT_BODY:
1280
+ p->tcol->offset = term_len(p, p->defindent);
1281
+ term_tab_set(p, NULL);
1282
+ term_tab_set(p, "T");
1283
+ term_tab_set(p, ".5i");
1284
+ if (n->sec == SEC_AUTHORS)
1285
+ p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
1286
+ break;
1287
+ default:
1288
+ break;
1289
+ }
1290
+ return 1;
1291
+ }
1292
+
1293
+ static void
1294
+ termp_sh_post(DECL_ARGS)
1295
+ {
1296
+ switch (n->type) {
1297
+ case ROFFT_HEAD:
1298
+ term_newln(p);
1299
+ break;
1300
+ case ROFFT_BODY:
1301
+ term_newln(p);
1302
+ p->tcol->offset = 0;
1303
+ break;
1304
+ default:
1305
+ break;
1306
+ }
1307
+ }
1308
+
1309
+ static void
1310
+ termp_lb_post(DECL_ARGS)
1311
+ {
1312
+ if (n->sec == SEC_LIBRARY && n->flags & NODE_LINE)
1313
+ term_newln(p);
1314
+ }
1315
+
1316
+ static int
1317
+ termp_d1_pre(DECL_ARGS)
1318
+ {
1319
+ if (n->type != ROFFT_BLOCK)
1320
+ return 1;
1321
+ term_newln(p);
1322
+ p->tcol->offset += term_len(p, p->defindent + 1);
1323
+ term_tab_set(p, NULL);
1324
+ term_tab_set(p, "T");
1325
+ term_tab_set(p, ".5i");
1326
+ return 1;
1327
+ }
1328
+
1329
+ static int
1330
+ termp_ft_pre(DECL_ARGS)
1331
+ {
1332
+ synopsis_pre(p, n);
1333
+ return termp_under_pre(p, pair, meta, n);
1334
+ }
1335
+
1336
+ static int
1337
+ termp_fn_pre(DECL_ARGS)
1338
+ {
1339
+ size_t rmargin = 0;
1340
+ int pretty;
1341
+
1342
+ synopsis_pre(p, n);
1343
+ pretty = n->flags & NODE_SYNPRETTY;
1344
+ if ((n = n->child) == NULL)
1345
+ return 0;
1346
+
1347
+ if (pretty) {
1348
+ rmargin = p->tcol->rmargin;
1349
+ p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
1350
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
1351
+ }
1352
+
1353
+ assert(n->type == ROFFT_TEXT);
1354
+ term_fontpush(p, TERMFONT_BOLD);
1355
+ term_word(p, n->string);
1356
+ term_fontpop(p);
1357
+
1358
+ if (pretty) {
1359
+ term_flushln(p);
1360
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
1361
+ p->flags |= TERMP_NOPAD;
1362
+ p->tcol->offset = p->tcol->rmargin;
1363
+ p->tcol->rmargin = rmargin;
1364
+ }
1365
+
1366
+ p->flags |= TERMP_NOSPACE;
1367
+ term_word(p, "(");
1368
+ p->flags |= TERMP_NOSPACE;
1369
+
1370
+ for (n = n->next; n; n = n->next) {
1371
+ assert(n->type == ROFFT_TEXT);
1372
+ term_fontpush(p, TERMFONT_UNDER);
1373
+ if (pretty)
1374
+ p->flags |= TERMP_NBRWORD;
1375
+ term_word(p, n->string);
1376
+ term_fontpop(p);
1377
+
1378
+ if (n->next) {
1379
+ p->flags |= TERMP_NOSPACE;
1380
+ term_word(p, ",");
1381
+ }
1382
+ }
1383
+
1384
+ p->flags |= TERMP_NOSPACE;
1385
+ term_word(p, ")");
1386
+
1387
+ if (pretty) {
1388
+ p->flags |= TERMP_NOSPACE;
1389
+ term_word(p, ";");
1390
+ term_flushln(p);
1391
+ }
1392
+ return 0;
1393
+ }
1394
+
1395
+ static int
1396
+ termp_fa_pre(DECL_ARGS)
1397
+ {
1398
+ const struct roff_node *nn;
1399
+
1400
+ if (n->parent->tok != MDOC_Fo)
1401
+ return termp_under_pre(p, pair, meta, n);
1402
+
1403
+ for (nn = n->child; nn != NULL; nn = nn->next) {
1404
+ term_fontpush(p, TERMFONT_UNDER);
1405
+ p->flags |= TERMP_NBRWORD;
1406
+ term_word(p, nn->string);
1407
+ term_fontpop(p);
1408
+ if (nn->next != NULL) {
1409
+ p->flags |= TERMP_NOSPACE;
1410
+ term_word(p, ",");
1411
+ }
1412
+ }
1413
+ if (n->child != NULL &&
1414
+ (nn = roff_node_next(n)) != NULL &&
1415
+ nn->tok == MDOC_Fa) {
1416
+ p->flags |= TERMP_NOSPACE;
1417
+ term_word(p, ",");
1418
+ }
1419
+ return 0;
1420
+ }
1421
+
1422
+ static int
1423
+ termp_bd_pre(DECL_ARGS)
1424
+ {
1425
+ int offset;
1426
+
1427
+ if (n->type == ROFFT_BLOCK) {
1428
+ print_bvspace(p, n, n);
1429
+ return 1;
1430
+ } else if (n->type == ROFFT_HEAD)
1431
+ return 0;
1432
+
1433
+ /* Handle the -offset argument. */
1434
+
1435
+ if (n->norm->Bd.offs == NULL ||
1436
+ ! strcmp(n->norm->Bd.offs, "left"))
1437
+ /* nothing */;
1438
+ else if ( ! strcmp(n->norm->Bd.offs, "indent"))
1439
+ p->tcol->offset += term_len(p, p->defindent + 1);
1440
+ else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
1441
+ p->tcol->offset += term_len(p, (p->defindent + 1) * 2);
1442
+ else {
1443
+ offset = a2width(p, n->norm->Bd.offs);
1444
+ if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
1445
+ p->tcol->offset = 0;
1446
+ else if (offset < SHRT_MAX)
1447
+ p->tcol->offset += offset;
1448
+ }
1449
+
1450
+ switch (n->norm->Bd.type) {
1451
+ case DISP_literal:
1452
+ term_tab_set(p, NULL);
1453
+ term_tab_set(p, "T");
1454
+ term_tab_set(p, "8n");
1455
+ break;
1456
+ case DISP_centered:
1457
+ p->flags |= TERMP_CENTER;
1458
+ break;
1459
+ default:
1460
+ break;
1461
+ }
1462
+ return 1;
1463
+ }
1464
+
1465
+ static void
1466
+ termp_bd_post(DECL_ARGS)
1467
+ {
1468
+ if (n->type != ROFFT_BODY)
1469
+ return;
1470
+ if (n->norm->Bd.type == DISP_unfilled ||
1471
+ n->norm->Bd.type == DISP_literal)
1472
+ p->flags |= TERMP_BRNEVER;
1473
+ p->flags |= TERMP_NOSPACE;
1474
+ term_newln(p);
1475
+ p->flags &= ~TERMP_BRNEVER;
1476
+ if (n->norm->Bd.type == DISP_centered)
1477
+ p->flags &= ~TERMP_CENTER;
1478
+ }
1479
+
1480
+ static int
1481
+ termp_xx_pre(DECL_ARGS)
1482
+ {
1483
+ if ((n->aux = p->flags & TERMP_PREKEEP) == 0)
1484
+ p->flags |= TERMP_PREKEEP;
1485
+ return 1;
1486
+ }
1487
+
1488
+ static void
1489
+ termp_xx_post(DECL_ARGS)
1490
+ {
1491
+ if (n->aux == 0)
1492
+ p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
1493
+ }
1494
+
1495
+ static void
1496
+ termp_pf_post(DECL_ARGS)
1497
+ {
1498
+ if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
1499
+ p->flags |= TERMP_NOSPACE;
1500
+ }
1501
+
1502
+ static int
1503
+ termp_ss_pre(DECL_ARGS)
1504
+ {
1505
+ switch (n->type) {
1506
+ case ROFFT_BLOCK:
1507
+ if (roff_node_prev(n) == NULL)
1508
+ term_newln(p);
1509
+ else
1510
+ term_vspace(p);
1511
+ break;
1512
+ case ROFFT_HEAD:
1513
+ p->tcol->offset = term_len(p, (p->defindent+1)/2);
1514
+ return termp_bold_pre(p, pair, meta, n);
1515
+ case ROFFT_BODY:
1516
+ p->tcol->offset = term_len(p, p->defindent);
1517
+ term_tab_set(p, NULL);
1518
+ term_tab_set(p, "T");
1519
+ term_tab_set(p, ".5i");
1520
+ break;
1521
+ default:
1522
+ break;
1523
+ }
1524
+ return 1;
1525
+ }
1526
+
1527
+ static void
1528
+ termp_ss_post(DECL_ARGS)
1529
+ {
1530
+ if (n->type == ROFFT_HEAD || n->type == ROFFT_BODY)
1531
+ term_newln(p);
1532
+ }
1533
+
1534
+ static int
1535
+ termp_in_pre(DECL_ARGS)
1536
+ {
1537
+ synopsis_pre(p, n);
1538
+ if (n->flags & NODE_SYNPRETTY && n->flags & NODE_LINE) {
1539
+ term_fontpush(p, TERMFONT_BOLD);
1540
+ term_word(p, "#include");
1541
+ term_word(p, "<");
1542
+ } else {
1543
+ term_word(p, "<");
1544
+ term_fontpush(p, TERMFONT_UNDER);
1545
+ }
1546
+ p->flags |= TERMP_NOSPACE;
1547
+ return 1;
1548
+ }
1549
+
1550
+ static void
1551
+ termp_in_post(DECL_ARGS)
1552
+ {
1553
+ if (n->flags & NODE_SYNPRETTY)
1554
+ term_fontpush(p, TERMFONT_BOLD);
1555
+ p->flags |= TERMP_NOSPACE;
1556
+ term_word(p, ">");
1557
+ if (n->flags & NODE_SYNPRETTY)
1558
+ term_fontpop(p);
1559
+ }
1560
+
1561
+ static int
1562
+ termp_pp_pre(DECL_ARGS)
1563
+ {
1564
+ term_vspace(p);
1565
+ if (n->flags & NODE_ID)
1566
+ term_tag_write(n, p->line);
1567
+ return 0;
1568
+ }
1569
+
1570
+ static int
1571
+ termp_skip_pre(DECL_ARGS)
1572
+ {
1573
+ return 0;
1574
+ }
1575
+
1576
+ static int
1577
+ termp_quote_pre(DECL_ARGS)
1578
+ {
1579
+ if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
1580
+ return 1;
1581
+
1582
+ switch (n->tok) {
1583
+ case MDOC_Ao:
1584
+ case MDOC_Aq:
1585
+ term_word(p, n->child != NULL && n->child->next == NULL &&
1586
+ n->child->tok == MDOC_Mt ? "<" : "\\(la");
1587
+ break;
1588
+ case MDOC_Bro:
1589
+ case MDOC_Brq:
1590
+ term_word(p, "{");
1591
+ break;
1592
+ case MDOC_Oo:
1593
+ case MDOC_Op:
1594
+ case MDOC_Bo:
1595
+ case MDOC_Bq:
1596
+ term_word(p, "[");
1597
+ break;
1598
+ case MDOC__T:
1599
+ /* FALLTHROUGH */
1600
+ case MDOC_Do:
1601
+ case MDOC_Dq:
1602
+ term_word(p, "\\(lq");
1603
+ break;
1604
+ case MDOC_En:
1605
+ if (NULL == n->norm->Es ||
1606
+ NULL == n->norm->Es->child)
1607
+ return 1;
1608
+ term_word(p, n->norm->Es->child->string);
1609
+ break;
1610
+ case MDOC_Po:
1611
+ case MDOC_Pq:
1612
+ term_word(p, "(");
1613
+ break;
1614
+ case MDOC_Qo:
1615
+ case MDOC_Qq:
1616
+ term_word(p, "\"");
1617
+ break;
1618
+ case MDOC_Ql:
1619
+ case MDOC_So:
1620
+ case MDOC_Sq:
1621
+ term_word(p, "\\(oq");
1622
+ break;
1623
+ default:
1624
+ abort();
1625
+ }
1626
+
1627
+ p->flags |= TERMP_NOSPACE;
1628
+ return 1;
1629
+ }
1630
+
1631
+ static void
1632
+ termp_quote_post(DECL_ARGS)
1633
+ {
1634
+
1635
+ if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
1636
+ return;
1637
+
1638
+ p->flags |= TERMP_NOSPACE;
1639
+
1640
+ switch (n->tok) {
1641
+ case MDOC_Ao:
1642
+ case MDOC_Aq:
1643
+ term_word(p, n->child != NULL && n->child->next == NULL &&
1644
+ n->child->tok == MDOC_Mt ? ">" : "\\(ra");
1645
+ break;
1646
+ case MDOC_Bro:
1647
+ case MDOC_Brq:
1648
+ term_word(p, "}");
1649
+ break;
1650
+ case MDOC_Oo:
1651
+ case MDOC_Op:
1652
+ case MDOC_Bo:
1653
+ case MDOC_Bq:
1654
+ term_word(p, "]");
1655
+ break;
1656
+ case MDOC__T:
1657
+ /* FALLTHROUGH */
1658
+ case MDOC_Do:
1659
+ case MDOC_Dq:
1660
+ term_word(p, "\\(rq");
1661
+ break;
1662
+ case MDOC_En:
1663
+ if (n->norm->Es == NULL ||
1664
+ n->norm->Es->child == NULL ||
1665
+ n->norm->Es->child->next == NULL)
1666
+ p->flags &= ~TERMP_NOSPACE;
1667
+ else
1668
+ term_word(p, n->norm->Es->child->next->string);
1669
+ break;
1670
+ case MDOC_Po:
1671
+ case MDOC_Pq:
1672
+ term_word(p, ")");
1673
+ break;
1674
+ case MDOC_Qo:
1675
+ case MDOC_Qq:
1676
+ term_word(p, "\"");
1677
+ break;
1678
+ case MDOC_Ql:
1679
+ case MDOC_So:
1680
+ case MDOC_Sq:
1681
+ term_word(p, "\\(cq");
1682
+ break;
1683
+ default:
1684
+ abort();
1685
+ }
1686
+ }
1687
+
1688
+ static int
1689
+ termp_eo_pre(DECL_ARGS)
1690
+ {
1691
+
1692
+ if (n->type != ROFFT_BODY)
1693
+ return 1;
1694
+
1695
+ if (n->end == ENDBODY_NOT &&
1696
+ n->parent->head->child == NULL &&
1697
+ n->child != NULL &&
1698
+ n->child->end != ENDBODY_NOT)
1699
+ term_word(p, "\\&");
1700
+ else if (n->end != ENDBODY_NOT ? n->child != NULL :
1701
+ n->parent->head->child != NULL && (n->child != NULL ||
1702
+ (n->parent->tail != NULL && n->parent->tail->child != NULL)))
1703
+ p->flags |= TERMP_NOSPACE;
1704
+
1705
+ return 1;
1706
+ }
1707
+
1708
+ static void
1709
+ termp_eo_post(DECL_ARGS)
1710
+ {
1711
+ int body, tail;
1712
+
1713
+ if (n->type != ROFFT_BODY)
1714
+ return;
1715
+
1716
+ if (n->end != ENDBODY_NOT) {
1717
+ p->flags &= ~TERMP_NOSPACE;
1718
+ return;
1719
+ }
1720
+
1721
+ body = n->child != NULL || n->parent->head->child != NULL;
1722
+ tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
1723
+
1724
+ if (body && tail)
1725
+ p->flags |= TERMP_NOSPACE;
1726
+ else if ( ! (body || tail))
1727
+ term_word(p, "\\&");
1728
+ else if ( ! tail)
1729
+ p->flags &= ~TERMP_NOSPACE;
1730
+ }
1731
+
1732
+ static int
1733
+ termp_fo_pre(DECL_ARGS)
1734
+ {
1735
+ size_t rmargin;
1736
+
1737
+ switch (n->type) {
1738
+ case ROFFT_BLOCK:
1739
+ synopsis_pre(p, n);
1740
+ return 1;
1741
+ case ROFFT_BODY:
1742
+ rmargin = p->tcol->rmargin;
1743
+ if (n->flags & NODE_SYNPRETTY) {
1744
+ p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
1745
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND |
1746
+ TERMP_HANG;
1747
+ }
1748
+ p->flags |= TERMP_NOSPACE;
1749
+ term_word(p, "(");
1750
+ p->flags |= TERMP_NOSPACE;
1751
+ if (n->flags & NODE_SYNPRETTY) {
1752
+ term_flushln(p);
1753
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
1754
+ TERMP_HANG);
1755
+ p->flags |= TERMP_NOPAD;
1756
+ p->tcol->offset = p->tcol->rmargin;
1757
+ p->tcol->rmargin = rmargin;
1758
+ }
1759
+ return 1;
1760
+ default:
1761
+ return termp_bold_pre(p, pair, meta, n);
1762
+ }
1763
+ }
1764
+
1765
+ static void
1766
+ termp_fo_post(DECL_ARGS)
1767
+ {
1768
+ if (n->type != ROFFT_BODY)
1769
+ return;
1770
+
1771
+ p->flags |= TERMP_NOSPACE;
1772
+ term_word(p, ")");
1773
+
1774
+ if (n->flags & NODE_SYNPRETTY) {
1775
+ p->flags |= TERMP_NOSPACE;
1776
+ term_word(p, ";");
1777
+ term_flushln(p);
1778
+ }
1779
+ }
1780
+
1781
+ static int
1782
+ termp_bf_pre(DECL_ARGS)
1783
+ {
1784
+ switch (n->type) {
1785
+ case ROFFT_HEAD:
1786
+ return 0;
1787
+ case ROFFT_BODY:
1788
+ break;
1789
+ default:
1790
+ return 1;
1791
+ }
1792
+ switch (n->norm->Bf.font) {
1793
+ case FONT_Em:
1794
+ return termp_under_pre(p, pair, meta, n);
1795
+ case FONT_Sy:
1796
+ return termp_bold_pre(p, pair, meta, n);
1797
+ default:
1798
+ return termp_li_pre(p, pair, meta, n);
1799
+ }
1800
+ }
1801
+
1802
+ static int
1803
+ termp_sm_pre(DECL_ARGS)
1804
+ {
1805
+ if (n->child == NULL)
1806
+ p->flags ^= TERMP_NONOSPACE;
1807
+ else if (strcmp(n->child->string, "on") == 0)
1808
+ p->flags &= ~TERMP_NONOSPACE;
1809
+ else
1810
+ p->flags |= TERMP_NONOSPACE;
1811
+
1812
+ if (p->col && ! (TERMP_NONOSPACE & p->flags))
1813
+ p->flags &= ~TERMP_NOSPACE;
1814
+
1815
+ return 0;
1816
+ }
1817
+
1818
+ static int
1819
+ termp_ap_pre(DECL_ARGS)
1820
+ {
1821
+ p->flags |= TERMP_NOSPACE;
1822
+ term_word(p, "'");
1823
+ p->flags |= TERMP_NOSPACE;
1824
+ return 1;
1825
+ }
1826
+
1827
+ static void
1828
+ termp____post(DECL_ARGS)
1829
+ {
1830
+ struct roff_node *nn;
1831
+
1832
+ /*
1833
+ * Handle lists of authors. In general, print each followed by
1834
+ * a comma. Don't print the comma if there are only two
1835
+ * authors.
1836
+ */
1837
+ if (n->tok == MDOC__A &&
1838
+ (nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
1839
+ ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
1840
+ ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
1841
+ return;
1842
+
1843
+ /* TODO: %U. */
1844
+
1845
+ if (n->parent == NULL || n->parent->tok != MDOC_Rs)
1846
+ return;
1847
+
1848
+ p->flags |= TERMP_NOSPACE;
1849
+ if (roff_node_next(n) == NULL) {
1850
+ term_word(p, ".");
1851
+ p->flags |= TERMP_SENTENCE;
1852
+ } else
1853
+ term_word(p, ",");
1854
+ }
1855
+
1856
+ static int
1857
+ termp_li_pre(DECL_ARGS)
1858
+ {
1859
+ term_fontpush(p, TERMFONT_NONE);
1860
+ return 1;
1861
+ }
1862
+
1863
+ static int
1864
+ termp_lk_pre(DECL_ARGS)
1865
+ {
1866
+ const struct roff_node *link, *descr, *punct;
1867
+
1868
+ if ((link = n->child) == NULL)
1869
+ return 0;
1870
+
1871
+ /* Find beginning of trailing punctuation. */
1872
+ punct = n->last;
1873
+ while (punct != link && punct->flags & NODE_DELIMC)
1874
+ punct = punct->prev;
1875
+ punct = punct->next;
1876
+
1877
+ /* Link text. */
1878
+ if ((descr = link->next) != NULL && descr != punct) {
1879
+ term_fontpush(p, TERMFONT_UNDER);
1880
+ while (descr != punct) {
1881
+ if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
1882
+ p->flags |= TERMP_NOSPACE;
1883
+ term_word(p, descr->string);
1884
+ descr = descr->next;
1885
+ }
1886
+ term_fontpop(p);
1887
+ p->flags |= TERMP_NOSPACE;
1888
+ term_word(p, ":");
1889
+ }
1890
+
1891
+ /* Link target. */
1892
+ term_fontpush(p, TERMFONT_BOLD);
1893
+ term_word(p, link->string);
1894
+ term_fontpop(p);
1895
+
1896
+ /* Trailing punctuation. */
1897
+ while (punct != NULL) {
1898
+ p->flags |= TERMP_NOSPACE;
1899
+ term_word(p, punct->string);
1900
+ punct = punct->next;
1901
+ }
1902
+ return 0;
1903
+ }
1904
+
1905
+ static int
1906
+ termp_bk_pre(DECL_ARGS)
1907
+ {
1908
+ switch (n->type) {
1909
+ case ROFFT_BLOCK:
1910
+ break;
1911
+ case ROFFT_HEAD:
1912
+ return 0;
1913
+ case ROFFT_BODY:
1914
+ if (n->parent->args != NULL || n->prev->child == NULL)
1915
+ p->flags |= TERMP_PREKEEP;
1916
+ break;
1917
+ default:
1918
+ abort();
1919
+ }
1920
+ return 1;
1921
+ }
1922
+
1923
+ static void
1924
+ termp_bk_post(DECL_ARGS)
1925
+ {
1926
+ if (n->type == ROFFT_BODY)
1927
+ p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
1928
+ }
1929
+
1930
+ /*
1931
+ * If we are in an `Rs' and there is a journal present,
1932
+ * then quote us instead of underlining us (for disambiguation).
1933
+ */
1934
+ static void
1935
+ termp__t_post(DECL_ARGS)
1936
+ {
1937
+ if (n->parent != NULL && n->parent->tok == MDOC_Rs &&
1938
+ n->parent->norm->Rs.quote_T)
1939
+ termp_quote_post(p, pair, meta, n);
1940
+ termp____post(p, pair, meta, n);
1941
+ }
1942
+
1943
+ static int
1944
+ termp__t_pre(DECL_ARGS)
1945
+ {
1946
+ if (n->parent != NULL && n->parent->tok == MDOC_Rs &&
1947
+ n->parent->norm->Rs.quote_T)
1948
+ return termp_quote_pre(p, pair, meta, n);
1949
+ else
1950
+ return termp_under_pre(p, pair, meta, n);
1951
+ }
1952
+
1953
+ static int
1954
+ termp_under_pre(DECL_ARGS)
1955
+ {
1956
+ term_fontpush(p, TERMFONT_UNDER);
1957
+ return 1;
1958
+ }
1959
+
1960
+ static int
1961
+ termp_abort_pre(DECL_ARGS)
1962
+ {
1963
+ abort();
1964
+ }