Annotation of mandoc/man_term.c, Revision 1.4
1.4 ! kristaps 1: /* $Id: man_term.c,v 1.3 2009/03/26 15:19:44 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@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
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 <err.h>
21: #include <stdio.h>
22: #include <stdlib.h>
23: #include <string.h>
24:
25: #include "term.h"
26: #include "man.h"
27:
1.2 kristaps 28: #ifdef __linux__
29: extern size_t strlcpy(char *, const char *, size_t);
30: extern size_t strlcat(char *, const char *, size_t);
31: #endif
32:
1.1 kristaps 33: #define DECL_ARGS struct termp *p, \
34: const struct man_node *n, \
35: const struct man_meta *m
36:
37: struct termact {
38: int (*pre)(DECL_ARGS);
39: void (*post)(DECL_ARGS);
40: };
41:
42: static int pre_B(DECL_ARGS);
1.3 kristaps 43: static int pre_BI(DECL_ARGS);
44: static int pre_BR(DECL_ARGS);
1.1 kristaps 45: static int pre_I(DECL_ARGS);
1.3 kristaps 46: static int pre_IB(DECL_ARGS);
1.4 ! kristaps 47: static int pre_IP(DECL_ARGS);
1.3 kristaps 48: static int pre_IR(DECL_ARGS);
1.1 kristaps 49: static int pre_PP(DECL_ARGS);
1.3 kristaps 50: static int pre_RB(DECL_ARGS);
51: static int pre_RI(DECL_ARGS);
1.1 kristaps 52: static int pre_SH(DECL_ARGS);
53: static int pre_SS(DECL_ARGS);
54: static int pre_TP(DECL_ARGS);
55:
56: static void post_B(DECL_ARGS);
57: static void post_I(DECL_ARGS);
58: static void post_SH(DECL_ARGS);
59: static void post_SS(DECL_ARGS);
60:
61: static const struct termact termacts[MAN_MAX] = {
62: { NULL, NULL }, /* __ */
63: { NULL, NULL }, /* TH */
64: { pre_SH, post_SH }, /* SH */
65: { pre_SS, post_SS }, /* SS */
66: { pre_TP, NULL }, /* TP */
67: { pre_PP, NULL }, /* LP */
68: { pre_PP, NULL }, /* PP */
69: { pre_PP, NULL }, /* P */
1.4 ! kristaps 70: { pre_IP, NULL }, /* IP */
! 71: { pre_PP, NULL }, /* HP */ /* FIXME */
1.1 kristaps 72: { NULL, NULL }, /* SM */
73: { pre_B, post_B }, /* SB */
1.3 kristaps 74: { pre_BI, NULL }, /* BI */
75: { pre_IB, NULL }, /* IB */
76: { pre_BR, NULL }, /* BR */
77: { pre_RB, NULL }, /* RB */
1.1 kristaps 78: { NULL, NULL }, /* R */
79: { pre_B, post_B }, /* B */
80: { pre_I, post_I }, /* I */
1.3 kristaps 81: { pre_IR, NULL }, /* IR */
82: { pre_RI, NULL }, /* RI */
1.1 kristaps 83: };
84:
85: static void print_head(struct termp *,
86: const struct man_meta *);
87: static void print_body(DECL_ARGS);
88: static void print_node(DECL_ARGS);
89: static void print_foot(struct termp *,
90: const struct man_meta *);
91:
92:
93: int
94: man_run(struct termp *p, const struct man *m)
95: {
96:
97: print_head(p, man_meta(m));
98: p->flags |= TERMP_NOSPACE;
99: print_body(p, man_node(m), man_meta(m));
100: print_foot(p, man_meta(m));
101:
102: return(1);
103: }
104:
105:
1.3 kristaps 106: /* ARGSUSED */
1.1 kristaps 107: static int
108: pre_I(DECL_ARGS)
109: {
110:
111: p->flags |= TERMP_UNDER;
112: return(1);
113: }
114:
115:
1.3 kristaps 116: /* ARGSUSED */
1.1 kristaps 117: static void
118: post_I(DECL_ARGS)
119: {
120:
121: p->flags &= ~TERMP_UNDER;
122: }
123:
124:
1.3 kristaps 125: /* ARGSUSED */
126: static int
127: pre_IR(DECL_ARGS)
128: {
129: const struct man_node *nn;
130: int i;
131:
132: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
133: if ( ! (i % 2))
134: p->flags |= TERMP_UNDER;
1.4 ! kristaps 135: if (i > 0)
! 136: p->flags |= TERMP_NOSPACE;
1.3 kristaps 137: print_node(p, nn, m);
138: if ( ! (i % 2))
139: p->flags &= ~TERMP_UNDER;
140: }
141: return(0);
142: }
143:
144:
145: /* ARGSUSED */
146: static int
147: pre_IB(DECL_ARGS)
148: {
149: const struct man_node *nn;
150: int i;
151:
152: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
153: p->flags |= i % 2 ? TERMP_BOLD : TERMP_UNDER;
1.4 ! kristaps 154: if (i > 0)
! 155: p->flags |= TERMP_NOSPACE;
1.3 kristaps 156: print_node(p, nn, m);
157: p->flags &= i % 2 ? ~TERMP_BOLD : ~TERMP_UNDER;
158: }
159: return(0);
160: }
161:
162:
163: /* ARGSUSED */
164: static int
165: pre_RB(DECL_ARGS)
166: {
167: const struct man_node *nn;
168: int i;
169:
170: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
171: if (i % 2)
172: p->flags |= TERMP_BOLD;
1.4 ! kristaps 173: if (i > 0)
! 174: p->flags |= TERMP_NOSPACE;
1.3 kristaps 175: print_node(p, nn, m);
176: if (i % 2)
177: p->flags &= ~TERMP_BOLD;
178: }
179: return(0);
180: }
181:
182:
183: /* ARGSUSED */
184: static int
185: pre_RI(DECL_ARGS)
186: {
187: const struct man_node *nn;
188: int i;
189:
190: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
191: if ( ! (i % 2))
192: p->flags |= TERMP_UNDER;
1.4 ! kristaps 193: if (i > 0)
! 194: p->flags |= TERMP_NOSPACE;
1.3 kristaps 195: print_node(p, nn, m);
196: if ( ! (i % 2))
197: p->flags &= ~TERMP_UNDER;
198: }
199: return(0);
200: }
201:
202:
203: /* ARGSUSED */
204: static int
205: pre_BR(DECL_ARGS)
206: {
207: const struct man_node *nn;
208: int i;
209:
210: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
211: if ( ! (i % 2))
212: p->flags |= TERMP_BOLD;
1.4 ! kristaps 213: if (i > 0)
! 214: p->flags |= TERMP_NOSPACE;
1.3 kristaps 215: print_node(p, nn, m);
216: if ( ! (i % 2))
217: p->flags &= ~TERMP_BOLD;
218: }
219: return(0);
220: }
221:
222:
223: /* ARGSUSED */
224: static int
225: pre_BI(DECL_ARGS)
226: {
227: const struct man_node *nn;
228: int i;
229:
230: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
231: p->flags |= i % 2 ? TERMP_UNDER : TERMP_BOLD;
1.4 ! kristaps 232: if (i > 0)
! 233: p->flags |= TERMP_NOSPACE;
1.3 kristaps 234: print_node(p, nn, m);
235: p->flags &= i % 2 ? ~TERMP_UNDER : ~TERMP_BOLD;
236: }
237: return(0);
238: }
239:
240:
241: /* ARGSUSED */
1.1 kristaps 242: static int
243: pre_B(DECL_ARGS)
244: {
245:
246: p->flags |= TERMP_BOLD;
247: return(1);
248: }
249:
250:
1.3 kristaps 251: /* ARGSUSED */
1.1 kristaps 252: static void
253: post_B(DECL_ARGS)
254: {
255:
256: p->flags &= ~TERMP_BOLD;
257: }
258:
259:
1.3 kristaps 260: /* ARGSUSED */
1.1 kristaps 261: static int
262: pre_PP(DECL_ARGS)
263: {
264:
265: term_vspace(p);
266: p->offset = INDENT;
267: return(0);
268: }
269:
270:
1.3 kristaps 271: /* ARGSUSED */
1.1 kristaps 272: static int
1.4 ! kristaps 273: pre_IP(DECL_ARGS)
! 274: {
! 275: const struct man_node *nn;
! 276: size_t offs;
! 277:
! 278: term_vspace(p);
! 279: p->offset = INDENT;
! 280:
! 281: if (NULL == (nn = n->child))
! 282: return(1);
! 283:
! 284: /* FIXME - ignore the designator. */
! 285: nn = nn->next;
! 286:
! 287: if (MAN_TEXT != nn->type)
! 288: errx(1, "expected text line argument");
! 289:
! 290: offs = (size_t)atoi(nn->string);
! 291: nn = nn->next;
! 292:
! 293: p->flags |= TERMP_NOSPACE;
! 294: p->offset += offs;
! 295: return(0);
! 296: }
! 297:
! 298:
! 299: /* ARGSUSED */
! 300: static int
1.1 kristaps 301: pre_TP(DECL_ARGS)
302: {
303: const struct man_node *nn;
304: size_t offs;
305:
306: term_vspace(p);
307: p->offset = INDENT;
308:
309: if (NULL == (nn = n->child))
310: return(1);
311:
312: if (nn->line == n->line) {
313: if (MAN_TEXT != nn->type)
314: errx(1, "expected text line argument");
1.3 kristaps 315: offs = (size_t)atoi(nn->string);
1.1 kristaps 316: nn = nn->next;
317: } else
318: offs = INDENT;
319:
320: for ( ; nn; nn = nn->next)
321: print_node(p, nn, m);
322:
323: term_flushln(p);
324: p->flags |= TERMP_NOSPACE;
325: p->offset += offs;
326: return(0);
327: }
328:
329:
1.3 kristaps 330: /* ARGSUSED */
1.1 kristaps 331: static int
332: pre_SS(DECL_ARGS)
333: {
334:
335: term_vspace(p);
336: p->flags |= TERMP_BOLD;
337: return(1);
338: }
339:
340:
1.3 kristaps 341: /* ARGSUSED */
1.1 kristaps 342: static void
343: post_SS(DECL_ARGS)
344: {
345:
346: term_flushln(p);
347: p->flags &= ~TERMP_BOLD;
348: p->flags |= TERMP_NOSPACE;
349: }
350:
351:
1.3 kristaps 352: /* ARGSUSED */
1.1 kristaps 353: static int
354: pre_SH(DECL_ARGS)
355: {
356:
357: term_vspace(p);
358: p->offset = 0;
359: p->flags |= TERMP_BOLD;
360: return(1);
361: }
362:
363:
1.3 kristaps 364: /* ARGSUSED */
1.1 kristaps 365: static void
366: post_SH(DECL_ARGS)
367: {
368:
369: term_flushln(p);
370: p->offset = INDENT;
371: p->flags &= ~TERMP_BOLD;
372: p->flags |= TERMP_NOSPACE;
373: }
374:
375:
376: static void
377: print_node(DECL_ARGS)
378: {
1.4 ! kristaps 379: int c, sz;
1.1 kristaps 380:
381: c = 1;
382:
383: switch (n->type) {
384: case(MAN_ELEM):
385: if (termacts[n->tok].pre)
386: c = (*termacts[n->tok].pre)(p, n, m);
387: break;
388: case(MAN_TEXT):
1.4 ! kristaps 389: if (0 == *n->string) {
! 390: term_vspace(p);
1.1 kristaps 391: break;
392: }
1.4 ! kristaps 393: /*
! 394: * Note! This is hacky. Here, we recognise the `\c'
! 395: * escape embedded in so many -man pages. It's supposed
! 396: * to remove the subsequent space, so we mark NOSPACE if
! 397: * it's encountered in the string.
! 398: */
! 399: sz = (int)strlen(n->string);
! 400: term_word(p, n->string);
! 401: if (sz >= 2 && n->string[sz - 1] == 'c' &&
! 402: n->string[sz - 2] == '\\')
! 403: p->flags |= TERMP_NOSPACE;
1.1 kristaps 404: break;
405: default:
406: break;
407: }
408:
409: if (c && n->child)
410: print_body(p, n->child, m);
411:
412: switch (n->type) {
413: case (MAN_ELEM):
414: if (termacts[n->tok].post)
415: (*termacts[n->tok].post)(p, n, m);
416: break;
417: default:
418: break;
419: }
420: }
421:
422:
423: static void
424: print_body(DECL_ARGS)
425: {
426: print_node(p, n, m);
427: if ( ! n->next)
428: return;
429: print_body(p, n->next, m);
430: }
431:
432:
433: static void
434: print_foot(struct termp *p, const struct man_meta *meta)
435: {
436: struct tm *tm;
437: char *buf;
438:
439: if (NULL == (buf = malloc(p->rmargin)))
440: err(1, "malloc");
441:
442: tm = localtime(&meta->date);
443:
444: #ifdef __OpenBSD__
445: if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
446: #else
447: if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
448: #endif
449: err(1, "strftime");
450:
451: term_vspace(p);
452:
453: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
454: p->rmargin = p->maxrmargin - strlen(buf);
455: p->offset = 0;
456:
457: if (meta->source)
458: term_word(p, meta->source);
459: if (meta->source)
460: term_word(p, "");
461: term_flushln(p);
462:
463: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
464: p->offset = p->rmargin;
465: p->rmargin = p->maxrmargin;
466: p->flags &= ~TERMP_NOBREAK;
467:
468: term_word(p, buf);
469: term_flushln(p);
470:
471: free(buf);
472: }
473:
474:
475: static void
476: print_head(struct termp *p, const struct man_meta *meta)
477: {
478: char *buf, *title;
479:
480: p->rmargin = p->maxrmargin;
481: p->offset = 0;
482:
483: if (NULL == (buf = malloc(p->rmargin)))
484: err(1, "malloc");
485: if (NULL == (title = malloc(p->rmargin)))
486: err(1, "malloc");
487:
488: if (meta->vol)
489: (void)strlcpy(buf, meta->vol, p->rmargin);
490: else
491: *buf = 0;
492:
493: (void)snprintf(title, p->rmargin, "%s(%d)",
494: meta->title, meta->msec);
495:
496: p->offset = 0;
497: p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
498: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
499:
500: term_word(p, title);
501: term_flushln(p);
502:
503: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
504: p->offset = p->rmargin;
505: p->rmargin = p->maxrmargin - strlen(title);
506:
507: term_word(p, buf);
508: term_flushln(p);
509:
510: p->offset = p->rmargin;
511: p->rmargin = p->maxrmargin;
512: p->flags &= ~TERMP_NOBREAK;
513: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
514:
515: term_word(p, title);
516: term_flushln(p);
517:
518: p->rmargin = p->maxrmargin;
519: p->offset = 0;
520: p->flags &= ~TERMP_NOSPACE;
521:
522: free(title);
523: free(buf);
524: }
525:
CVSweb