Annotation of mandoc/termact.c, Revision 1.3
1.3 ! kristaps 1: /* $Id: termact.c,v 1.2 2009/02/21 21:00:06 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
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
7: * above copyright notice and this permission notice appear in all
8: * copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
19: #include <assert.h>
20: #include <stdlib.h>
21: #include <string.h>
22:
23: #include "term.h"
24:
25: #define TTYPE_PROG 0
26: #define TTYPE_CMD_FLAG 1
27: #define TTYPE_CMD_ARG 2
28: #define TTYPE_SECTION 3
29: #define TTYPE_NMAX 4
30:
31: /*
32: * These define "styles" for element types, like command arguments or
33: * executable names. This is useful when multiple macros must decorate
34: * the same thing (like .Ex -std cmd and .Nm cmd).
35: */
36:
37: const int ttypes[TTYPE_NMAX] = {
38: TERMP_BOLD, /* TTYPE_PROG */
39: TERMP_BOLD, /* TTYPE_CMD_FLAG */
40: TERMP_UNDERLINE, /* TTYPE_CMD_ARG */
41: TERMP_BOLD /* TTYPE_SECTION */
42: };
43:
44: static int arg_hasattr(int, size_t,
45: const struct mdoc_arg *);
46: static int arg_getattr(int, size_t,
47: const struct mdoc_arg *);
48:
49: /*
50: * What follows describes prefix and postfix operations for the abstract
51: * syntax tree descent.
52: */
53:
54: #define DECL_ARGS \
55: struct termp *p, \
56: const struct mdoc_meta *meta, \
57: const struct mdoc_node *node
58:
1.2 kristaps 59: #define DECL_PRE(name) \
60: static int name##_pre(DECL_ARGS)
61: #define DECL_POST(name) \
62: static void name##_post(DECL_ARGS)
1.1 kristaps 63:
64: DECL_PRE(termp_aq);
65: DECL_PRE(termp_ar);
66: DECL_PRE(termp_d1);
67: DECL_PRE(termp_dq);
68: DECL_PRE(termp_ex);
69: DECL_PRE(termp_fl);
70: DECL_PRE(termp_it);
71: DECL_PRE(termp_nd);
72: DECL_PRE(termp_nm);
73: DECL_PRE(termp_ns);
74: DECL_PRE(termp_op);
75: DECL_PRE(termp_pp);
76: DECL_PRE(termp_sh);
77: DECL_PRE(termp_ud);
78: DECL_PRE(termp_xr);
79:
80: DECL_POST(termp_aq);
81: DECL_POST(termp_ar);
82: DECL_POST(termp_bl);
83: DECL_POST(termp_d1);
84: DECL_POST(termp_dq);
85: DECL_POST(termp_fl);
86: DECL_POST(termp_it);
87: DECL_POST(termp_nm);
88: DECL_POST(termp_op);
89: DECL_POST(termp_sh);
90:
91: const struct termact __termacts[MDOC_MAX] = {
92: { NULL, NULL }, /* \" */
93: { NULL, NULL }, /* Dd */
94: { NULL, NULL }, /* Dt */
95: { NULL, NULL }, /* Os */
96: { termp_sh_pre, termp_sh_post }, /* Sh */
97: { NULL, NULL }, /* Ss */
98: { termp_pp_pre, NULL }, /* Pp */
99: { termp_d1_pre, termp_d1_post }, /* D1 */
100: { NULL, NULL }, /* Dl */
101: { NULL, NULL }, /* Bd */
102: { NULL, NULL }, /* Ed */
103: { NULL, termp_bl_post }, /* Bl */
104: { NULL, NULL }, /* El */
105: { termp_it_pre, termp_it_post }, /* It */
106: { NULL, NULL }, /* Ad */
107: { NULL, NULL }, /* An */
108: { termp_ar_pre, termp_ar_post }, /* Ar */
109: { NULL, NULL }, /* Cd */
110: { NULL, NULL }, /* Cm */
111: { NULL, NULL }, /* Dv */
112: { NULL, NULL }, /* Er */
113: { NULL, NULL }, /* Ev */
114: { termp_ex_pre, NULL }, /* Ex */
115: { NULL, NULL }, /* Fa */
116: { NULL, NULL }, /* Fd */
117: { termp_fl_pre, termp_fl_post }, /* Fl */
118: { NULL, NULL }, /* Fn */
119: { NULL, NULL }, /* Ft */
120: { NULL, NULL }, /* Ic */
121: { NULL, NULL }, /* In */
122: { NULL, NULL }, /* Li */
123: { termp_nd_pre, NULL }, /* Nd */
124: { termp_nm_pre, termp_nm_post }, /* Nm */
125: { termp_op_pre, termp_op_post }, /* Op */
126: { NULL, NULL }, /* Ot */
127: { NULL, NULL }, /* Pa */
128: { NULL, NULL }, /* Rv */
129: { NULL, NULL }, /* St */
130: { NULL, NULL }, /* Va */
131: { NULL, NULL }, /* Vt */
132: { termp_xr_pre, NULL }, /* Xr */
133: { NULL, NULL }, /* %A */
134: { NULL, NULL }, /* %B */
135: { NULL, NULL }, /* %D */
136: { NULL, NULL }, /* %I */
137: { NULL, NULL }, /* %J */
138: { NULL, NULL }, /* %N */
139: { NULL, NULL }, /* %O */
140: { NULL, NULL }, /* %P */
141: { NULL, NULL }, /* %R */
142: { NULL, NULL }, /* %T */
143: { NULL, NULL }, /* %V */
144: { NULL, NULL }, /* Ac */
145: { NULL, NULL }, /* Ao */
146: { termp_aq_pre, termp_aq_post }, /* Aq */
147: { NULL, NULL }, /* At */
148: { NULL, NULL }, /* Bc */
149: { NULL, NULL }, /* Bf */
150: { NULL, NULL }, /* Bo */
151: { NULL, NULL }, /* Bq */
152: { NULL, NULL }, /* Bsx */
153: { NULL, NULL }, /* Bx */
154: { NULL, NULL }, /* Db */
155: { NULL, NULL }, /* Dc */
156: { NULL, NULL }, /* Do */
157: { termp_dq_pre, termp_dq_post }, /* Dq */
158: { NULL, NULL }, /* Ec */
159: { NULL, NULL }, /* Ef */
160: { NULL, NULL }, /* Em */
161: { NULL, NULL }, /* Eo */
162: { NULL, NULL }, /* Fx */
163: { NULL, NULL }, /* Ms */
164: { NULL, NULL }, /* No */
165: { termp_ns_pre, NULL }, /* Ns */
166: { NULL, NULL }, /* Nx */
167: { NULL, NULL }, /* Ox */
168: { NULL, NULL }, /* Pc */
169: { NULL, NULL }, /* Pf */
170: { NULL, NULL }, /* Po */
171: { NULL, NULL }, /* Pq */
172: { NULL, NULL }, /* Qc */
173: { NULL, NULL }, /* Ql */
174: { NULL, NULL }, /* Qo */
175: { NULL, NULL }, /* Qq */
176: { NULL, NULL }, /* Re */
177: { NULL, NULL }, /* Rs */
178: { NULL, NULL }, /* Sc */
179: { NULL, NULL }, /* So */
180: { NULL, NULL }, /* Sq */
181: { NULL, NULL }, /* Sm */
182: { NULL, NULL }, /* Sx */
183: { NULL, NULL }, /* Sy */
184: { NULL, NULL }, /* Tn */
185: { NULL, NULL }, /* Ux */
186: { NULL, NULL }, /* Xc */
187: { NULL, NULL }, /* Xo */
188: { NULL, NULL }, /* Fo */
189: { NULL, NULL }, /* Fc */
190: { NULL, NULL }, /* Oo */
191: { NULL, NULL }, /* Oc */
192: { NULL, NULL }, /* Bk */
193: { NULL, NULL }, /* Ek */
194: { NULL, NULL }, /* Bt */
195: { NULL, NULL }, /* Hf */
196: { NULL, NULL }, /* Fr */
197: { termp_ud_pre, NULL }, /* Ud */
198: };
199:
200: const struct termact *termacts = __termacts;
201:
202:
203: /* ARGSUSED */
204: static int
205: termp_dq_pre(DECL_ARGS)
206: {
207:
208: if (MDOC_BODY != node->type)
209: return(1);
210:
211: word(p, "``");
212: p->flags |= TERMP_NOSPACE;
213: return(1);
214: }
215:
216:
217: /* ARGSUSED */
1.2 kristaps 218: static void
1.1 kristaps 219: termp_dq_post(DECL_ARGS)
220: {
221:
222: if (MDOC_BODY != node->type)
1.2 kristaps 223: return;
1.1 kristaps 224:
225: p->flags |= TERMP_NOSPACE;
226: word(p, "''");
227: }
228:
229:
230: /* ARGSUSED */
1.2 kristaps 231: static void
1.1 kristaps 232: termp_it_post(DECL_ARGS)
233: {
234: const struct mdoc_node *n, *it;
235: const struct mdoc_block *bl;
236: int i;
237: size_t width;
238:
239: /*
240: * This (and termp_it_pre()) are the most complicated functions
241: * here. They must account for a considerable number of
242: * switches that completely change the output behaviour, like
243: * -tag versus -column. Yech.
244: */
245:
246: switch (node->type) {
247: case (MDOC_BODY):
248: /* FALLTHROUGH */
249: case (MDOC_HEAD):
250: break;
251: default:
1.2 kristaps 252: return;
1.1 kristaps 253: }
254:
255: it = node->parent;
256: assert(MDOC_BLOCK == it->type);
257: assert(MDOC_It == it->tok);
258:
259: n = it->parent;
260: assert(MDOC_BODY == n->type);
261: assert(MDOC_Bl == n->tok);
262: n = n->parent;
263: bl = &n->data.block;
264:
265: /* If `-tag', adjust our margins accordingly. */
266:
267: if (arg_hasattr(MDOC_Tag, bl->argc, bl->argv)) {
268: i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
269: assert(i >= 0);
270: assert(1 == bl->argv[i].sz);
271: width = strlen(*bl->argv[i].value); /* XXX */
272:
273: if (MDOC_HEAD == node->type) {
274: flushln(p);
275: /* FIXME: nested lists. */
276: p->rmargin = p->maxrmargin;
277: p->flags &= ~TERMP_NOBREAK;
278: } else {
279: flushln(p);
280: p->offset -= width + 1;
281: p->flags &= ~TERMP_NOLPAD;
282: }
283: }
284: }
285:
286:
287: /* ARGSUSED */
288: static int
289: termp_it_pre(DECL_ARGS)
290: {
291: const struct mdoc_node *n, *it;
292: const struct mdoc_block *bl;
293: int i;
294: size_t width;
295:
296: /*
297: * Also see termp_it_post() for general comments.
298: */
299:
300: switch (node->type) {
301: case (MDOC_BODY):
302: /* FALLTHROUGH */
303: case (MDOC_HEAD):
304: it = node->parent;
305: break;
306: case (MDOC_BLOCK):
307: it = node;
308: break;
309: default:
310: return(1);
311: }
312:
313: assert(MDOC_BLOCK == it->type);
314: assert(MDOC_It == it->tok);
315:
316: n = it->parent;
317: assert(MDOC_BODY == n->type);
318: assert(MDOC_Bl == n->tok);
319: n = n->parent;
320: bl = &n->data.block;
321:
322: /* If `-compact', don't assert vertical space. */
323:
324: if (MDOC_BLOCK == node->type) {
325: if (arg_hasattr(MDOC_Compact, bl->argc, bl->argv))
326: newln(p);
327: else
328: vspace(p);
329: return(1);
330: }
331:
332: assert(MDOC_HEAD == node->type
333: || MDOC_BODY == node->type);
334:
335: /* If `-tag', adjust our margins accordingly. */
336:
337: if (arg_hasattr(MDOC_Tag, bl->argc, bl->argv)) {
338: i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
339: assert(i >= 0); /* XXX */
340: assert(1 == bl->argv[i].sz);
341: width = strlen(*bl->argv[i].value); /* XXX */
342:
343: /* FIXME: nested lists. */
344:
345: if (MDOC_HEAD == node->type) {
346: p->flags |= TERMP_NOBREAK;
347: p->flags |= TERMP_NOSPACE;
348: p->rmargin = p->offset + width;
349: } else {
350: p->flags |= TERMP_NOSPACE;
351: p->flags |= TERMP_NOLPAD;
352: p->offset += width + 1;
353: }
354: }
355:
356: return(1);
357: }
358:
359:
360: /* ARGSUSED */
1.2 kristaps 361: static void
1.1 kristaps 362: termp_nm_post(DECL_ARGS)
363: {
364:
365: p->flags &= ~ttypes[TTYPE_PROG];
366: }
367:
368:
369: /* ARGSUSED */
1.2 kristaps 370: static void
1.1 kristaps 371: termp_fl_post(DECL_ARGS)
372: {
373:
374: p->flags &= ~ttypes[TTYPE_CMD_FLAG];
375: }
376:
377:
378: /* ARGSUSED */
379: static int
380: termp_ar_pre(DECL_ARGS)
381: {
382:
383: p->flags |= ttypes[TTYPE_CMD_ARG];
384: if (NULL == node->child)
385: word(p, "...");
386: return(1);
387: }
388:
389:
390: /* ARGSUSED */
391: static int
392: termp_nm_pre(DECL_ARGS)
393: {
394:
395: p->flags |= ttypes[TTYPE_PROG];
396: if (NULL == node->child)
397: word(p, meta->name);
398: return(1);
399: }
400:
401:
402: /* ARGSUSED */
403: static int
404: termp_ns_pre(DECL_ARGS)
405: {
406:
407: p->flags |= TERMP_NOSPACE;
408: return(1);
409: }
410:
411:
412: /* ARGSUSED */
413: static int
414: termp_pp_pre(DECL_ARGS)
415: {
416:
417: vspace(p);
418: return(1);
419: }
420:
421:
422: /* ARGSUSED */
1.2 kristaps 423: static void
1.1 kristaps 424: termp_ar_post(DECL_ARGS)
425: {
426:
427: p->flags &= ~ttypes[TTYPE_CMD_ARG];
428: }
429:
430:
431: /* ARGSUSED */
432: static int
433: termp_ex_pre(DECL_ARGS)
434: {
435: int i;
436:
437: i = arg_getattr(MDOC_Std, node->data.elem.argc,
438: node->data.elem.argv);
439: assert(i >= 0);
440:
441: word(p, "The");
442: p->flags |= ttypes[TTYPE_PROG];
443: word(p, *node->data.elem.argv[i].value);
444: p->flags &= ~ttypes[TTYPE_PROG];
445: word(p, "utility exits 0 on success, and >0 if an error occurs.");
446:
447: return(1);
448: }
449:
450:
451: /* ARGSUSED */
452: static int
453: termp_nd_pre(DECL_ARGS)
454: {
455:
456: word(p, "\\-");
457: return(1);
458: }
459:
460:
461: /* ARGSUSED */
1.2 kristaps 462: static void
1.1 kristaps 463: termp_bl_post(DECL_ARGS)
464: {
465:
1.2 kristaps 466: if (MDOC_BLOCK == node->type)
1.1 kristaps 467: newln(p);
468: }
469:
470:
471: /* ARGSUSED */
1.2 kristaps 472: static void
1.1 kristaps 473: termp_op_post(DECL_ARGS)
474: {
475:
1.2 kristaps 476: if (MDOC_BODY != node->type)
477: return;
478: p->flags |= TERMP_NOSPACE;
479: word(p, "\\(rB");
1.1 kristaps 480: }
481:
482:
483: /* ARGSUSED */
1.2 kristaps 484: static void
1.1 kristaps 485: termp_sh_post(DECL_ARGS)
486: {
487:
488: switch (node->type) {
489: case (MDOC_HEAD):
490: p->flags &= ~ttypes[TTYPE_SECTION];
491: newln(p);
492: break;
493: case (MDOC_BODY):
494: newln(p);
495: p->offset -= 4;
496: break;
497: default:
498: break;
499: }
500: }
501:
502:
503: /* ARGSUSED */
504: static int
505: termp_xr_pre(DECL_ARGS)
506: {
507: const struct mdoc_node *n;
508:
509: n = node->child;
510: assert(n);
511:
512: assert(MDOC_TEXT == n->type);
513: word(p, n->data.text.string);
514:
515: if (NULL == (n = n->next))
516: return(0);
517:
518: assert(MDOC_TEXT == n->type);
519: p->flags |= TERMP_NOSPACE;
1.2 kristaps 520: word(p, "(");
1.1 kristaps 521: p->flags |= TERMP_NOSPACE;
522: word(p, n->data.text.string);
523: p->flags |= TERMP_NOSPACE;
1.2 kristaps 524: word(p, ")");
1.1 kristaps 525:
526: return(0);
527: }
528:
529:
530: /* ARGSUSED */
531: static int
532: termp_sh_pre(DECL_ARGS)
533: {
534:
535: switch (node->type) {
536: case (MDOC_HEAD):
537: vspace(p);
538: p->flags |= ttypes[TTYPE_SECTION];
539: break;
540: case (MDOC_BODY):
541: p->offset += 4;
542: break;
543: default:
544: break;
545: }
546: return(1);
547: }
548:
549:
550: /* ARGSUSED */
551: static int
552: termp_op_pre(DECL_ARGS)
553: {
554:
555: switch (node->type) {
556: case (MDOC_BODY):
1.2 kristaps 557: word(p, "\\(lB");
1.1 kristaps 558: p->flags |= TERMP_NOSPACE;
559: break;
560: default:
561: break;
562: }
563: return(1);
564: }
565:
566:
567: /* ARGSUSED */
568: static int
569: termp_ud_pre(DECL_ARGS)
570: {
571:
572: word(p, "currently under development.");
573: return(1);
574: }
575:
576:
577: /* ARGSUSED */
578: static int
579: termp_fl_pre(DECL_ARGS)
580: {
581:
582: p->flags |= ttypes[TTYPE_CMD_FLAG];
583: word(p, "\\-");
584: p->flags |= TERMP_NOSPACE;
585: return(1);
586: }
587:
588:
589: /* ARGSUSED */
590: static int
591: termp_d1_pre(DECL_ARGS)
592: {
593:
594: if (MDOC_BODY != node->type)
595: return(1);
596: newln(p);
597: p->offset += 4;
598: return(1);
599: }
600:
601:
602: /* ARGSUSED */
1.2 kristaps 603: static void
1.1 kristaps 604: termp_d1_post(DECL_ARGS)
605: {
606:
1.2 kristaps 607: if (MDOC_BODY != node->type)
608: return;
1.1 kristaps 609: newln(p);
610: p->offset -= 4;
611: }
612:
613:
614: /* ARGSUSED */
615: static int
616: termp_aq_pre(DECL_ARGS)
617: {
618:
619: if (MDOC_BODY != node->type)
620: return(1);
1.3 ! kristaps 621: word(p, "<");
1.1 kristaps 622: p->flags |= TERMP_NOSPACE;
623: return(1);
624: }
625:
626:
627: /* ARGSUSED */
1.2 kristaps 628: static void
1.1 kristaps 629: termp_aq_post(DECL_ARGS)
630: {
631:
632: if (MDOC_BODY != node->type)
1.2 kristaps 633: return;
1.1 kristaps 634: p->flags |= TERMP_NOSPACE;
1.3 ! kristaps 635: word(p, ">");
1.1 kristaps 636: }
637:
638:
639: static int
640: arg_hasattr(int arg, size_t argc, const struct mdoc_arg *argv)
641: {
642:
643: return(-1 != arg_getattr(arg, argc, argv));
644: }
645:
646:
647: static int
648: arg_getattr(int arg, size_t argc, const struct mdoc_arg *argv)
649: {
650: int i;
651:
652: for (i = 0; i < (int)argc; i++)
653: if (argv[i].arg == arg)
654: return(i);
655: return(-1);
656: }
657:
CVSweb