]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_man.c
Initial, incomplete support for -Tman
[mandoc.git] / mdoc_man.c
1 /* $Id: mdoc_man.c,v 1.1 2011/09/17 15:00:51 schwarze Exp $ */
2 /*
3 * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #include <stdio.h>
18 #include <string.h>
19
20 #include "mandoc.h"
21 #include "mdoc.h"
22 #include "main.h"
23
24 static int need_space = 0;
25 static int need_nl = 0;
26
27 #define DECL_ARGS const struct mdoc_meta *m, \
28 const struct mdoc_node *n
29
30 struct manact {
31 int (*cond)(DECL_ARGS);
32 int (*pre)(DECL_ARGS);
33 void (*post)(DECL_ARGS);
34 char *prefix;
35 char *suffix;
36 };
37
38 static void print_word(const char *);
39 static void print_node(DECL_ARGS);
40
41 static int cond_head(DECL_ARGS);
42 static int cond_body(DECL_ARGS);
43 static int pre_enc(DECL_ARGS);
44 static void post_enc(DECL_ARGS);
45 static void post_percent(DECL_ARGS);
46
47 static int pre_dl(DECL_ARGS);
48 static void post_dl(DECL_ARGS);
49 static int pre_it(DECL_ARGS);
50 static int pre_nm(DECL_ARGS);
51 static void post_nm(DECL_ARGS);
52 static int pre_ns(DECL_ARGS);
53 static int pre_pp(DECL_ARGS);
54 static int pre_sh(DECL_ARGS);
55 static void post_sh(DECL_ARGS);
56 static int pre_xr(DECL_ARGS);
57
58
59 static const struct manact manacts[MDOC_MAX] = {
60 { NULL, NULL, NULL, NULL, NULL }, /* _Ap */
61 { NULL, NULL, NULL, NULL, NULL }, /* _Dd */
62 { NULL, NULL, NULL, NULL, NULL }, /* _Dt */
63 { NULL, NULL, NULL, NULL, NULL }, /* _Os */
64 { NULL, pre_sh, post_sh, NULL, NULL }, /* Sh */
65 { NULL, NULL, NULL, NULL, NULL }, /* _Ss */
66 { NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
67 { NULL, NULL, NULL, NULL, NULL }, /* _D1 */
68 { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
69 { NULL, NULL, NULL, NULL, NULL }, /* _Bd */
70 { NULL, NULL, NULL, NULL, NULL }, /* _Ed */
71 { NULL, NULL, NULL, NULL, NULL }, /* _Bl */
72 { NULL, NULL, NULL, NULL, NULL }, /* _El */
73 { NULL, pre_it, NULL, NULL, NULL }, /* _It */
74 { NULL, NULL, NULL, NULL, NULL }, /* _Ad */
75 { NULL, NULL, NULL, NULL, NULL }, /* _An */
76 { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */
77 { NULL, NULL, NULL, NULL, NULL }, /* _Cd */
78 { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */
79 { NULL, NULL, NULL, NULL, NULL }, /* _Dv */
80 { NULL, NULL, NULL, NULL, NULL }, /* _Er */
81 { NULL, NULL, NULL, NULL, NULL }, /* _Ev */
82 { NULL, pre_enc, post_enc, "The \\fB",
83 "\\fP\nutility exits 0 on success, and >0 if an error occurs."
84 }, /* Ex */
85 { NULL, NULL, NULL, NULL, NULL }, /* _Fa */
86 { NULL, NULL, NULL, NULL, NULL }, /* _Fd */
87 { NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */
88 { NULL, NULL, NULL, NULL, NULL }, /* _Fn */
89 { NULL, NULL, NULL, NULL, NULL }, /* _Ft */
90 { NULL, NULL, NULL, NULL, NULL }, /* _Ic */
91 { NULL, NULL, NULL, NULL, NULL }, /* _In */
92 { NULL, NULL, NULL, NULL, NULL }, /* _Li */
93 { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
94 { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
95 { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
96 { NULL, NULL, NULL, NULL, NULL }, /* _Ot */
97 { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* _Pa */
98 { NULL, NULL, NULL, NULL, NULL }, /* _Rv */
99 { NULL, NULL, NULL, NULL, NULL }, /* _St */
100 { NULL, NULL, NULL, NULL, NULL }, /* _Va */
101 { NULL, NULL, NULL, NULL, NULL }, /* _Vt */
102 { NULL, pre_xr, NULL, NULL, NULL }, /* _Xr */
103 { NULL, NULL, post_percent, NULL, NULL }, /* _%A */
104 { NULL, NULL, NULL, NULL, NULL }, /* _%B */
105 { NULL, NULL, post_percent, NULL, NULL }, /* _%D */
106 { NULL, NULL, NULL, NULL, NULL }, /* _%I */
107 { NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */
108 { NULL, NULL, NULL, NULL, NULL }, /* _%N */
109 { NULL, NULL, NULL, NULL, NULL }, /* _%O */
110 { NULL, NULL, NULL, NULL, NULL }, /* _%P */
111 { NULL, NULL, NULL, NULL, NULL }, /* _%R */
112 { NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */
113 { NULL, NULL, NULL, NULL, NULL }, /* _%V */
114 { NULL, NULL, NULL, NULL, NULL }, /* _Ac */
115 { NULL, NULL, NULL, NULL, NULL }, /* _Ao */
116 { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */
117 { NULL, NULL, NULL, NULL, NULL }, /* _At */
118 { NULL, NULL, NULL, NULL, NULL }, /* _Bc */
119 { NULL, NULL, NULL, NULL, NULL }, /* _Bf */
120 { NULL, NULL, NULL, NULL, NULL }, /* _Bo */
121 { NULL, NULL, NULL, NULL, NULL }, /* _Bq */
122 { NULL, NULL, NULL, NULL, NULL }, /* _Bsx */
123 { NULL, NULL, NULL, NULL, NULL }, /* _Bx */
124 { NULL, NULL, NULL, NULL, NULL }, /* _Db */
125 { NULL, NULL, NULL, NULL, NULL }, /* _Dc */
126 { NULL, NULL, NULL, NULL, NULL }, /* _Do */
127 { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */
128 { NULL, NULL, NULL, NULL, NULL }, /* _Ec */
129 { NULL, NULL, NULL, NULL, NULL }, /* _Ef */
130 { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* _Em */
131 { NULL, NULL, NULL, NULL, NULL }, /* _Eo */
132 { NULL, NULL, NULL, NULL, NULL }, /* _Fx */
133 { NULL, NULL, NULL, NULL, NULL }, /* _Ms */
134 { NULL, NULL, NULL, NULL, NULL }, /* _No */
135 { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
136 { NULL, NULL, NULL, NULL, NULL }, /* _Nx */
137 { NULL, NULL, NULL, NULL, NULL }, /* _Ox */
138 { NULL, NULL, NULL, NULL, NULL }, /* _Pc */
139 { NULL, NULL, NULL, NULL, NULL }, /* _Pf */
140 { NULL, NULL, NULL, NULL, NULL }, /* _Po */
141 { cond_body, pre_enc, post_enc, "(", ")" }, /* _Pq */
142 { NULL, NULL, NULL, NULL, NULL }, /* _Qc */
143 { cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */
144 { NULL, NULL, NULL, NULL, NULL }, /* _Qo */
145 { NULL, NULL, NULL, NULL, NULL }, /* _Qq */
146 { NULL, NULL, NULL, NULL, NULL }, /* _Re */
147 { cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */
148 { NULL, NULL, NULL, NULL, NULL }, /* _Sc */
149 { NULL, NULL, NULL, NULL, NULL }, /* _So */
150 { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */
151 { NULL, NULL, NULL, NULL, NULL }, /* _Sm */
152 { NULL, NULL, NULL, NULL, NULL }, /* _Sx */
153 { NULL, NULL, NULL, NULL, NULL }, /* _Sy */
154 { NULL, NULL, NULL, NULL, NULL }, /* _Tn */
155 { NULL, NULL, NULL, NULL, NULL }, /* _Ux */
156 { NULL, NULL, NULL, NULL, NULL }, /* _Xc */
157 { NULL, NULL, NULL, NULL, NULL }, /* _Xo */
158 { NULL, NULL, NULL, NULL, NULL }, /* _Fo */
159 { NULL, NULL, NULL, NULL, NULL }, /* _Fc */
160 { NULL, NULL, NULL, NULL, NULL }, /* _Oo */
161 { NULL, NULL, NULL, NULL, NULL }, /* _Oc */
162 { NULL, NULL, NULL, NULL, NULL }, /* _Bk */
163 { NULL, NULL, NULL, NULL, NULL }, /* _Ek */
164 { NULL, NULL, NULL, NULL, NULL }, /* _Bt */
165 { NULL, NULL, NULL, NULL, NULL }, /* _Hf */
166 { NULL, NULL, NULL, NULL, NULL }, /* _Fr */
167 { NULL, NULL, NULL, NULL, NULL }, /* _Ud */
168 { NULL, NULL, NULL, NULL, NULL }, /* _Lb */
169 { NULL, NULL, NULL, NULL, NULL }, /* _Lp */
170 { NULL, NULL, NULL, NULL, NULL }, /* _Lk */
171 { NULL, NULL, NULL, NULL, NULL }, /* _Mt */
172 { NULL, NULL, NULL, NULL, NULL }, /* _Brq */
173 { NULL, NULL, NULL, NULL, NULL }, /* _Bro */
174 { NULL, NULL, NULL, NULL, NULL }, /* _Brc */
175 { NULL, NULL, NULL, NULL, NULL }, /* _%C */
176 { NULL, NULL, NULL, NULL, NULL }, /* _Es */
177 { NULL, NULL, NULL, NULL, NULL }, /* _En */
178 { NULL, NULL, NULL, NULL, NULL }, /* _Dx */
179 { NULL, NULL, NULL, NULL, NULL }, /* _%Q */
180 { NULL, NULL, NULL, NULL, NULL }, /* _br */
181 { NULL, NULL, NULL, NULL, NULL }, /* _sp */
182 { NULL, NULL, NULL, NULL, NULL }, /* _%U */
183 { NULL, NULL, NULL, NULL, NULL }, /* _Ta */
184 };
185
186
187 static void
188 print_word(const char *s)
189 {
190 if (need_nl) {
191 putchar('\n');
192 need_space = 0;
193 need_nl = 0;
194 } else if (need_space &&
195 (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]))
196 putchar(' ');
197 need_space = ('(' != s[0] && '[' != s[0]) || '\0' != s[1];
198 for ( ; *s; s++) {
199 switch (*s) {
200 case (ASCII_NBRSP):
201 printf("\\~");
202 break;
203 case (ASCII_HYPH):
204 putchar('-');
205 break;
206 default:
207 putchar(*s);
208 break;
209 }
210 }
211 }
212
213 void
214 man_mdoc(void *arg, const struct mdoc *mdoc)
215 {
216 const struct mdoc_meta *m;
217 const struct mdoc_node *n;
218
219 m = mdoc_meta(mdoc);
220 n = mdoc_node(mdoc);
221
222 printf(".TH \"%s\" \"%s\" \"%s\"", m->title, m->msec, m->date);
223 need_nl = 1;
224 need_space = 0;
225
226 print_node(m, n);
227 }
228
229 static void
230 print_node(DECL_ARGS)
231 {
232 const struct mdoc_node *prev, *sub;
233 const struct manact *act = NULL;
234 int cond, do_sub;
235
236 prev = n->prev ? n->prev : n->parent;
237 if (prev && prev->line < n->line)
238 need_nl = 1;
239
240 cond = 0;
241 do_sub = 1;
242 if (MDOC_TEXT == n->type) {
243 print_word(n->string);
244 } else {
245 act = manacts + n->tok;
246 cond = NULL == act->cond || (*act->cond)(m, n);
247 if (cond && act->pre)
248 do_sub = (*act->pre)(m, n);
249 }
250
251 if (do_sub)
252 for (sub = n->child; sub; sub = sub->next)
253 print_node(m, sub);
254
255 if (cond && act->post)
256 (*act->post)(m, n);
257 }
258
259 static int
260 cond_head(DECL_ARGS)
261 {
262 return(MDOC_HEAD == n->type);
263 }
264
265 static int
266 cond_body(DECL_ARGS)
267 {
268 return(MDOC_BODY == n->type);
269 }
270
271 static int
272 pre_enc(DECL_ARGS)
273 {
274 const char *prefix;
275
276 prefix = manacts[n->tok].prefix;
277 if (NULL == prefix)
278 return(1);
279 print_word(prefix);
280 need_space = 0;
281 return(1);
282 }
283
284 static void
285 post_enc(DECL_ARGS)
286 {
287 const char *suffix;
288
289 suffix = manacts[n->tok].suffix;
290 if (NULL == suffix)
291 return;
292 need_space = 0;
293 print_word(suffix);
294 }
295
296 static void
297 post_percent(DECL_ARGS)
298 {
299
300 post_enc(m, n);
301 if (n->next)
302 print_word(",");
303 else {
304 print_word(".");
305 need_nl = 1;
306 }
307 }
308
309 static int
310 pre_dl(DECL_ARGS)
311 {
312
313 need_nl = 1;
314 print_word(".RS 6n");
315 need_nl = 1;
316 return(1);
317 }
318
319 static void
320 post_dl(DECL_ARGS)
321 {
322
323 need_nl = 1;
324 print_word(".RE");
325 need_nl = 1;
326 }
327
328 static int
329 pre_it(DECL_ARGS)
330 {
331 const struct mdoc_node *bln;
332
333 if (MDOC_HEAD == n->type) {
334 need_nl = 1;
335 print_word(".TP");
336 bln = n->parent->parent->prev;
337 print_word(bln->norm->Bl.width);
338 need_nl = 1;
339 }
340 return(1);
341 }
342
343 static int
344 pre_nm(DECL_ARGS)
345 {
346
347 if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
348 return(1);
349 print_word("\\fB");
350 need_space = 0;
351 if (NULL == n->child)
352 print_word(m->name);
353 return(1);
354 }
355
356 static void
357 post_nm(DECL_ARGS)
358 {
359
360 if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
361 return;
362 need_space = 0;
363 print_word("\\fP");
364 }
365
366 static int
367 pre_ns(DECL_ARGS)
368 {
369
370 need_space = 0;
371 return(0);
372 }
373
374 static int
375 pre_pp(DECL_ARGS)
376 {
377
378 need_nl = 1;
379 if (MDOC_It == n->parent->tok)
380 print_word(".sp");
381 else
382 print_word(".PP");
383 need_nl = 1;
384 return(1);
385 }
386
387 static int
388 pre_sh(DECL_ARGS)
389 {
390
391 if (MDOC_HEAD != n->type)
392 return(1);
393 need_nl = 1;
394 print_word(".SH \"");
395 need_space = 0;
396 return(1);
397 }
398
399 static void
400 post_sh(DECL_ARGS)
401 {
402
403 if (MDOC_HEAD != n->type)
404 return;
405 need_space = 0;
406 print_word("\"");
407 need_nl = 1;
408 }
409
410 static int
411 pre_xr(DECL_ARGS)
412 {
413
414 n = n->child;
415 if (NULL == n)
416 return(0);
417 print_node(m, n);
418 n = n->next;
419 if (NULL == n)
420 return(0);
421 need_space = 0;
422 print_word("(");
423 print_node(m, n);
424 print_word(")");
425 return(0);
426 }