]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_man.c
994855074843c52d5c0143577a218ad011f8af1c
[mandoc.git] / mdoc_man.c
1 /* $Id: mdoc_man.c,v 1.3 2011/09/30 00:13:28 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 const char *prefix;
35 const 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 static int pre_sect(DECL_ARGS);
47 static void post_sect(DECL_ARGS);
48
49 static int pre_ap(DECL_ARGS);
50 static int pre_bd(DECL_ARGS);
51 static void post_bd(DECL_ARGS);
52 static int pre_br(DECL_ARGS);
53 static int pre_dl(DECL_ARGS);
54 static void post_dl(DECL_ARGS);
55 static int pre_it(DECL_ARGS);
56 static int pre_nm(DECL_ARGS);
57 static void post_nm(DECL_ARGS);
58 static int pre_ns(DECL_ARGS);
59 static void post_pf(DECL_ARGS);
60 static int pre_pp(DECL_ARGS);
61 static int pre_sp(DECL_ARGS);
62 static void post_sp(DECL_ARGS);
63 static int pre_xr(DECL_ARGS);
64
65
66 static const struct manact manacts[MDOC_MAX + 1] = {
67 { NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
68 { NULL, NULL, NULL, NULL, NULL }, /* Dd */
69 { NULL, NULL, NULL, NULL, NULL }, /* Dt */
70 { NULL, NULL, NULL, NULL, NULL }, /* _Os */
71 { NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
72 { NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
73 { NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
74 { cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
75 { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
76 { cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */
77 { NULL, NULL, NULL, NULL, NULL }, /* Ed */
78 { NULL, NULL, NULL, NULL, NULL }, /* Bl */
79 { NULL, NULL, NULL, NULL, NULL }, /* El */
80 { NULL, pre_it, NULL, NULL, NULL }, /* _It */
81 { NULL, NULL, NULL, NULL, NULL }, /* _Ad */
82 { NULL, NULL, NULL, NULL, NULL }, /* _An */
83 { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */
84 { NULL, NULL, NULL, NULL, NULL }, /* _Cd */
85 { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */
86 { NULL, NULL, NULL, NULL, NULL }, /* _Dv */
87 { NULL, NULL, NULL, NULL, NULL }, /* _Er */
88 { NULL, NULL, NULL, NULL, NULL }, /* _Ev */
89 { NULL, pre_enc, post_enc, "The \\fB",
90 "\\fP\nutility exits 0 on success, and >0 if an error occurs."
91 }, /* Ex */
92 { NULL, NULL, NULL, NULL, NULL }, /* _Fa */
93 { NULL, NULL, NULL, NULL, NULL }, /* _Fd */
94 { NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */
95 { NULL, NULL, NULL, NULL, NULL }, /* _Fn */
96 { NULL, NULL, NULL, NULL, NULL }, /* _Ft */
97 { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ic */
98 { NULL, NULL, NULL, NULL, NULL }, /* _In */
99 { NULL, NULL, NULL, NULL, NULL }, /* _Li */
100 { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
101 { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
102 { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
103 { NULL, NULL, NULL, NULL, NULL }, /* _Ot */
104 { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* _Pa */
105 { NULL, NULL, NULL, NULL, NULL }, /* _Rv */
106 { NULL, NULL, NULL, NULL, NULL }, /* _St */
107 { NULL, NULL, NULL, NULL, NULL }, /* _Va */
108 { NULL, NULL, NULL, NULL, NULL }, /* _Vt */
109 { NULL, pre_xr, NULL, NULL, NULL }, /* _Xr */
110 { NULL, NULL, post_percent, NULL, NULL }, /* _%A */
111 { NULL, NULL, NULL, NULL, NULL }, /* _%B */
112 { NULL, NULL, post_percent, NULL, NULL }, /* _%D */
113 { NULL, NULL, NULL, NULL, NULL }, /* _%I */
114 { NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */
115 { NULL, NULL, NULL, NULL, NULL }, /* _%N */
116 { NULL, NULL, NULL, NULL, NULL }, /* _%O */
117 { NULL, NULL, NULL, NULL, NULL }, /* _%P */
118 { NULL, NULL, NULL, NULL, NULL }, /* _%R */
119 { NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */
120 { NULL, NULL, NULL, NULL, NULL }, /* _%V */
121 { NULL, NULL, NULL, NULL, NULL }, /* _Ac */
122 { NULL, NULL, NULL, NULL, NULL }, /* _Ao */
123 { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */
124 { NULL, NULL, NULL, NULL, NULL }, /* _At */
125 { NULL, NULL, NULL, NULL, NULL }, /* Bc */
126 { NULL, NULL, NULL, NULL, NULL }, /* _Bf */
127 { cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
128 { cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
129 { NULL, NULL, NULL, NULL, NULL }, /* _Bsx */
130 { NULL, NULL, NULL, NULL, NULL }, /* _Bx */
131 { NULL, NULL, NULL, NULL, NULL }, /* _Db */
132 { NULL, NULL, NULL, NULL, NULL }, /* _Dc */
133 { NULL, NULL, NULL, NULL, NULL }, /* _Do */
134 { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */
135 { NULL, NULL, NULL, NULL, NULL }, /* _Ec */
136 { NULL, NULL, NULL, NULL, NULL }, /* _Ef */
137 { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Em */
138 { NULL, NULL, NULL, NULL, NULL }, /* _Eo */
139 { NULL, NULL, NULL, NULL, NULL }, /* _Fx */
140 { NULL, NULL, NULL, NULL, NULL }, /* _Ms */
141 { NULL, NULL, NULL, NULL, NULL }, /* _No */
142 { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
143 { NULL, NULL, NULL, NULL, NULL }, /* _Nx */
144 { NULL, NULL, NULL, NULL, NULL }, /* _Ox */
145 { NULL, NULL, NULL, NULL, NULL }, /* Pc */
146 { NULL, NULL, post_pf, NULL, NULL }, /* Pf */
147 { cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
148 { cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
149 { NULL, NULL, NULL, NULL, NULL }, /* _Qc */
150 { cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */
151 { NULL, NULL, NULL, NULL, NULL }, /* _Qo */
152 { NULL, NULL, NULL, NULL, NULL }, /* _Qq */
153 { NULL, NULL, NULL, NULL, NULL }, /* _Re */
154 { cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */
155 { NULL, NULL, NULL, NULL, NULL }, /* _Sc */
156 { NULL, NULL, NULL, NULL, NULL }, /* _So */
157 { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */
158 { NULL, NULL, NULL, NULL, NULL }, /* _Sm */
159 { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Sx */
160 { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Sy */
161 { NULL, NULL, NULL, NULL, NULL }, /* _Tn */
162 { NULL, NULL, NULL, NULL, NULL }, /* _Ux */
163 { NULL, NULL, NULL, NULL, NULL }, /* _Xc */
164 { NULL, NULL, NULL, NULL, NULL }, /* _Xo */
165 { NULL, NULL, NULL, NULL, NULL }, /* _Fo */
166 { NULL, NULL, NULL, NULL, NULL }, /* _Fc */
167 { cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
168 { NULL, NULL, NULL, NULL, NULL }, /* _Oc */
169 { NULL, NULL, NULL, NULL, NULL }, /* _Bk */
170 { NULL, NULL, NULL, NULL, NULL }, /* _Ek */
171 { NULL, NULL, NULL, NULL, NULL }, /* _Bt */
172 { NULL, NULL, NULL, NULL, NULL }, /* _Hf */
173 { NULL, NULL, NULL, NULL, NULL }, /* _Fr */
174 { NULL, NULL, NULL, NULL, NULL }, /* _Ud */
175 { NULL, NULL, NULL, NULL, NULL }, /* _Lb */
176 { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
177 { NULL, NULL, NULL, NULL, NULL }, /* _Lk */
178 { NULL, NULL, NULL, NULL, NULL }, /* _Mt */
179 { NULL, NULL, NULL, NULL, NULL }, /* _Brq */
180 { NULL, NULL, NULL, NULL, NULL }, /* _Bro */
181 { NULL, NULL, NULL, NULL, NULL }, /* _Brc */
182 { NULL, NULL, NULL, NULL, NULL }, /* _%C */
183 { NULL, NULL, NULL, NULL, NULL }, /* _Es */
184 { NULL, NULL, NULL, NULL, NULL }, /* _En */
185 { NULL, NULL, NULL, NULL, NULL }, /* _Dx */
186 { NULL, NULL, NULL, NULL, NULL }, /* _%Q */
187 { NULL, pre_br, NULL, NULL, NULL }, /* br */
188 { NULL, pre_sp, post_sp, NULL, NULL }, /* sp */
189 { NULL, NULL, NULL, NULL, NULL }, /* _%U */
190 { NULL, NULL, NULL, NULL, NULL }, /* _Ta */
191 { NULL, NULL, NULL, NULL, NULL }, /* ROOT */
192 };
193
194
195 static void
196 print_word(const char *s)
197 {
198 if (need_nl) {
199 putchar('\n');
200 need_space = 0;
201 need_nl = 0;
202 } else if (need_space &&
203 (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]))
204 putchar(' ');
205 need_space = ('(' != s[0] && '[' != s[0]) || '\0' != s[1];
206 for ( ; *s; s++) {
207 switch (*s) {
208 case (ASCII_NBRSP):
209 printf("\\~");
210 break;
211 case (ASCII_HYPH):
212 putchar('-');
213 break;
214 default:
215 putchar(*s);
216 break;
217 }
218 }
219 }
220
221 void
222 man_mdoc(void *arg, const struct mdoc *mdoc)
223 {
224 const struct mdoc_meta *m;
225 const struct mdoc_node *n;
226
227 m = mdoc_meta(mdoc);
228 n = mdoc_node(mdoc);
229
230 printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
231 m->title, m->msec, m->date, m->os, m->vol);
232 need_nl = 1;
233 need_space = 0;
234
235 print_node(m, n);
236 putchar('\n');
237 }
238
239 static void
240 print_node(DECL_ARGS)
241 {
242 const struct mdoc_node *prev, *sub;
243 const struct manact *act = NULL;
244 int cond, do_sub;
245
246 prev = n->prev ? n->prev : n->parent;
247 if (prev && prev->line < n->line)
248 need_nl = 1;
249
250 cond = 0;
251 do_sub = 1;
252 if (MDOC_TEXT == n->type) {
253 if (need_nl && ('.' == *n->string || '\'' == *n->string)) {
254 print_word("\\&");
255 need_space = 0;
256 }
257 print_word(n->string);
258 } else {
259 act = manacts + n->tok;
260 cond = NULL == act->cond || (*act->cond)(m, n);
261 if (cond && act->pre)
262 do_sub = (*act->pre)(m, n);
263 }
264
265 if (do_sub)
266 for (sub = n->child; sub; sub = sub->next)
267 print_node(m, sub);
268
269 if (cond && act->post)
270 (*act->post)(m, n);
271 }
272
273 static int
274 cond_head(DECL_ARGS)
275 {
276 return(MDOC_HEAD == n->type);
277 }
278
279 static int
280 cond_body(DECL_ARGS)
281 {
282 return(MDOC_BODY == n->type);
283 }
284
285 static int
286 pre_enc(DECL_ARGS)
287 {
288 const char *prefix;
289
290 prefix = manacts[n->tok].prefix;
291 if (NULL == prefix)
292 return(1);
293 print_word(prefix);
294 need_space = 0;
295 return(1);
296 }
297
298 static void
299 post_enc(DECL_ARGS)
300 {
301 const char *suffix;
302
303 suffix = manacts[n->tok].suffix;
304 if (NULL == suffix)
305 return;
306 need_space = 0;
307 print_word(suffix);
308 }
309
310 static void
311 post_percent(DECL_ARGS)
312 {
313
314 post_enc(m, n);
315 if (n->next)
316 print_word(",");
317 else {
318 print_word(".");
319 need_nl = 1;
320 }
321 }
322
323 static int
324 pre_sect(DECL_ARGS)
325 {
326
327 if (MDOC_HEAD != n->type)
328 return(1);
329 need_nl = 1;
330 print_word(manacts[n->tok].prefix);
331 print_word("\"");
332 need_space = 0;
333 return(1);
334 }
335
336 static void
337 post_sect(DECL_ARGS)
338 {
339
340 if (MDOC_HEAD != n->type)
341 return;
342 need_space = 0;
343 print_word("\"");
344 need_nl = 1;
345 }
346
347 static int
348 pre_ap(DECL_ARGS)
349 {
350
351 need_space = 0;
352 print_word("'");
353 need_space = 0;
354 return(0);
355 }
356
357 static int
358 pre_bd(DECL_ARGS)
359 {
360
361 if (DISP_unfilled == n->norm->Bd.type ||
362 DISP_literal == n->norm->Bd.type) {
363 need_nl = 1;
364 print_word(".nf");
365 }
366 need_nl = 1;
367 return(1);
368 }
369
370 static void
371 post_bd(DECL_ARGS)
372 {
373
374 if (DISP_unfilled == n->norm->Bd.type ||
375 DISP_literal == n->norm->Bd.type) {
376 need_nl = 1;
377 print_word(".fi");
378 }
379 need_nl = 1;
380 }
381
382 static int
383 pre_br(DECL_ARGS)
384 {
385
386 need_nl = 1;
387 print_word(".br");
388 need_nl = 1;
389 return(0);
390 }
391
392 static int
393 pre_dl(DECL_ARGS)
394 {
395
396 need_nl = 1;
397 print_word(".RS 6n");
398 need_nl = 1;
399 return(1);
400 }
401
402 static void
403 post_dl(DECL_ARGS)
404 {
405
406 need_nl = 1;
407 print_word(".RE");
408 need_nl = 1;
409 }
410
411 static int
412 pre_it(DECL_ARGS)
413 {
414 const struct mdoc_node *bln;
415
416 if (MDOC_HEAD == n->type) {
417 need_nl = 1;
418 print_word(".TP");
419 bln = n->parent->parent->prev;
420 switch (bln->norm->Bl.type) {
421 case (LIST_bullet):
422 print_word("4n");
423 need_nl = 1;
424 print_word("\\fBo\\fP");
425 break;
426 default:
427 if (bln->norm->Bl.width)
428 print_word(bln->norm->Bl.width);
429 break;
430 }
431 need_nl = 1;
432 }
433 return(1);
434 }
435
436 static int
437 pre_nm(DECL_ARGS)
438 {
439
440 if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
441 return(1);
442 print_word("\\fB");
443 need_space = 0;
444 if (NULL == n->child)
445 print_word(m->name);
446 return(1);
447 }
448
449 static void
450 post_nm(DECL_ARGS)
451 {
452
453 if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
454 return;
455 need_space = 0;
456 print_word("\\fP");
457 }
458
459 static int
460 pre_ns(DECL_ARGS)
461 {
462
463 need_space = 0;
464 return(0);
465 }
466
467 static void
468 post_pf(DECL_ARGS)
469 {
470
471 need_space = 0;
472 }
473
474 static int
475 pre_pp(DECL_ARGS)
476 {
477
478 need_nl = 1;
479 if (MDOC_It == n->parent->tok)
480 print_word(".sp");
481 else
482 print_word(".PP");
483 need_nl = 1;
484 return(1);
485 }
486
487 static int
488 pre_sp(DECL_ARGS)
489 {
490
491 need_nl = 1;
492 print_word(".sp");
493 return(1);
494 }
495
496 static void
497 post_sp(DECL_ARGS)
498 {
499
500 need_nl = 1;
501 }
502
503 static int
504 pre_xr(DECL_ARGS)
505 {
506
507 n = n->child;
508 if (NULL == n)
509 return(0);
510 print_node(m, n);
511 n = n->next;
512 if (NULL == n)
513 return(0);
514 need_space = 0;
515 print_word("(");
516 print_node(m, n);
517 print_word(")");
518 return(0);
519 }