Annotation of src/usr.bin/mandoc/man_term.c, Revision 1.3
1.3 ! schwarze 1: /* $Id: man_term.c,v 1.2 2009/06/14 23:00:57 schwarze Exp $ */
1.1 kristaps 2: /*
1.2 schwarze 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.2 schwarze 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.2 schwarze 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.
1.1 kristaps 16: */
17: #include <assert.h>
18: #include <err.h>
19: #include <stdio.h>
20: #include <stdlib.h>
21: #include <string.h>
22:
23: #include "term.h"
24: #include "man.h"
25:
26: #define DECL_ARGS struct termp *p, \
27: const struct man_node *n, \
28: const struct man_meta *m
29:
30: struct termact {
31: int (*pre)(DECL_ARGS);
32: void (*post)(DECL_ARGS);
33: };
34:
35: static int pre_B(DECL_ARGS);
36: static int pre_BI(DECL_ARGS);
37: static int pre_BR(DECL_ARGS);
38: static int pre_I(DECL_ARGS);
39: static int pre_IB(DECL_ARGS);
40: static int pre_IP(DECL_ARGS);
41: static int pre_IR(DECL_ARGS);
42: static int pre_PP(DECL_ARGS);
43: static int pre_RB(DECL_ARGS);
44: static int pre_RI(DECL_ARGS);
45: static int pre_SH(DECL_ARGS);
46: static int pre_SS(DECL_ARGS);
47: static int pre_TP(DECL_ARGS);
48:
49: static void post_B(DECL_ARGS);
50: static void post_I(DECL_ARGS);
51: static void post_SH(DECL_ARGS);
52: static void post_SS(DECL_ARGS);
53:
54: static const struct termact termacts[MAN_MAX] = {
55: { NULL, NULL }, /* __ */
56: { NULL, NULL }, /* TH */
57: { pre_SH, post_SH }, /* SH */
58: { pre_SS, post_SS }, /* SS */
59: { pre_TP, NULL }, /* TP */
60: { pre_PP, NULL }, /* LP */
61: { pre_PP, NULL }, /* PP */
62: { pre_PP, NULL }, /* P */
63: { pre_IP, NULL }, /* IP */
64: { pre_PP, NULL }, /* HP */ /* FIXME */
65: { NULL, NULL }, /* SM */
66: { pre_B, post_B }, /* SB */
67: { pre_BI, NULL }, /* BI */
68: { pre_IB, NULL }, /* IB */
69: { pre_BR, NULL }, /* BR */
70: { pre_RB, NULL }, /* RB */
71: { NULL, NULL }, /* R */
72: { pre_B, post_B }, /* B */
73: { pre_I, post_I }, /* I */
74: { pre_IR, NULL }, /* IR */
75: { pre_RI, NULL }, /* RI */
76: { pre_PP, NULL }, /* br */
77: { NULL, NULL }, /* na */
78: { pre_I, post_I }, /* i */
79: };
80:
81: static void print_head(struct termp *,
82: const struct man_meta *);
83: static void print_body(DECL_ARGS);
84: static void print_node(DECL_ARGS);
85: static void print_foot(struct termp *,
86: const struct man_meta *);
87:
88:
89: int
90: man_run(struct termp *p, const struct man *m)
91: {
92:
93: print_head(p, man_meta(m));
94: p->flags |= TERMP_NOSPACE;
95: print_body(p, man_node(m), man_meta(m));
96: print_foot(p, man_meta(m));
97:
98: return(1);
99: }
100:
101:
102: /* ARGSUSED */
103: static int
104: pre_I(DECL_ARGS)
105: {
106:
107: p->flags |= TERMP_UNDER;
108: return(1);
109: }
110:
111:
112: /* ARGSUSED */
113: static void
114: post_I(DECL_ARGS)
115: {
116:
117: p->flags &= ~TERMP_UNDER;
118: }
119:
120:
121: /* ARGSUSED */
122: static int
123: pre_IR(DECL_ARGS)
124: {
125: const struct man_node *nn;
126: int i;
127:
128: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
129: if ( ! (i % 2))
130: p->flags |= TERMP_UNDER;
131: if (i > 0)
132: p->flags |= TERMP_NOSPACE;
133: print_node(p, nn, m);
134: if ( ! (i % 2))
135: p->flags &= ~TERMP_UNDER;
136: }
137: return(0);
138: }
139:
140:
141: /* ARGSUSED */
142: static int
143: pre_IB(DECL_ARGS)
144: {
145: const struct man_node *nn;
146: int i;
147:
148: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
149: p->flags |= i % 2 ? TERMP_BOLD : TERMP_UNDER;
150: if (i > 0)
151: p->flags |= TERMP_NOSPACE;
152: print_node(p, nn, m);
153: p->flags &= i % 2 ? ~TERMP_BOLD : ~TERMP_UNDER;
154: }
155: return(0);
156: }
157:
158:
159: /* ARGSUSED */
160: static int
161: pre_RB(DECL_ARGS)
162: {
163: const struct man_node *nn;
164: int i;
165:
166: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
167: if (i % 2)
168: p->flags |= TERMP_BOLD;
169: if (i > 0)
170: p->flags |= TERMP_NOSPACE;
171: print_node(p, nn, m);
172: if (i % 2)
173: p->flags &= ~TERMP_BOLD;
174: }
175: return(0);
176: }
177:
178:
179: /* ARGSUSED */
180: static int
181: pre_RI(DECL_ARGS)
182: {
183: const struct man_node *nn;
184: int i;
185:
186: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
187: if ( ! (i % 2))
188: p->flags |= TERMP_UNDER;
189: if (i > 0)
190: p->flags |= TERMP_NOSPACE;
191: print_node(p, nn, m);
192: if ( ! (i % 2))
193: p->flags &= ~TERMP_UNDER;
194: }
195: return(0);
196: }
197:
198:
199: /* ARGSUSED */
200: static int
201: pre_BR(DECL_ARGS)
202: {
203: const struct man_node *nn;
204: int i;
205:
206: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
207: if ( ! (i % 2))
208: p->flags |= TERMP_BOLD;
209: if (i > 0)
210: p->flags |= TERMP_NOSPACE;
211: print_node(p, nn, m);
212: if ( ! (i % 2))
213: p->flags &= ~TERMP_BOLD;
214: }
215: return(0);
216: }
217:
218:
219: /* ARGSUSED */
220: static int
221: pre_BI(DECL_ARGS)
222: {
223: const struct man_node *nn;
224: int i;
225:
226: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
227: p->flags |= i % 2 ? TERMP_UNDER : TERMP_BOLD;
228: if (i > 0)
229: p->flags |= TERMP_NOSPACE;
230: print_node(p, nn, m);
231: p->flags &= i % 2 ? ~TERMP_UNDER : ~TERMP_BOLD;
232: }
233: return(0);
234: }
235:
236:
237: /* ARGSUSED */
238: static int
239: pre_B(DECL_ARGS)
240: {
241:
242: p->flags |= TERMP_BOLD;
243: return(1);
244: }
245:
246:
247: /* ARGSUSED */
248: static void
249: post_B(DECL_ARGS)
250: {
251:
252: p->flags &= ~TERMP_BOLD;
253: }
254:
255:
256: /* ARGSUSED */
257: static int
258: pre_PP(DECL_ARGS)
259: {
260:
261: term_vspace(p);
262: p->offset = INDENT;
263: return(0);
264: }
265:
266:
267: /* ARGSUSED */
268: static int
269: pre_IP(DECL_ARGS)
270: {
271: #if 0
272: const struct man_node *nn;
273: size_t offs;
274: #endif
275:
276: term_vspace(p);
277: p->offset = INDENT;
278:
279: #if 0
280: if (NULL == (nn = n->child))
281: return(1);
282: if (MAN_TEXT != nn->type)
283: errx(1, "expected text line argument");
284:
285: if (nn->next) {
286: if (MAN_TEXT != nn->next->type)
287: errx(1, "expected text line argument");
288: offs = (size_t)atoi(nn->next->string);
289: } else
290: offs = strlen(nn->string);
291:
292: p->offset += offs;
293: #endif
294: p->flags |= TERMP_NOSPACE;
295: return(0);
296: }
297:
298:
299: /* ARGSUSED */
300: static int
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");
315: offs = (size_t)atoi(nn->string);
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:
330: /* ARGSUSED */
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:
341: /* ARGSUSED */
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:
352: /* ARGSUSED */
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:
364: /* ARGSUSED */
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: {
379: int c, sz;
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):
389: if (0 == *n->string) {
390: term_vspace(p);
391: break;
392: }
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;
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:
1.3 ! schwarze 444: if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
1.1 kristaps 445: err(1, "strftime");
446:
447: term_vspace(p);
448:
449: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
450: p->rmargin = p->maxrmargin - strlen(buf);
451: p->offset = 0;
452:
453: if (meta->source)
454: term_word(p, meta->source);
455: if (meta->source)
456: term_word(p, "");
457: term_flushln(p);
458:
459: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
460: p->offset = p->rmargin;
461: p->rmargin = p->maxrmargin;
462: p->flags &= ~TERMP_NOBREAK;
463:
464: term_word(p, buf);
465: term_flushln(p);
466:
467: free(buf);
468: }
469:
470:
471: static void
472: print_head(struct termp *p, const struct man_meta *meta)
473: {
474: char *buf, *title;
475:
476: p->rmargin = p->maxrmargin;
477: p->offset = 0;
478:
479: if (NULL == (buf = malloc(p->rmargin)))
480: err(1, "malloc");
481: if (NULL == (title = malloc(p->rmargin)))
482: err(1, "malloc");
483:
484: if (meta->vol)
485: (void)strlcpy(buf, meta->vol, p->rmargin);
486: else
487: *buf = 0;
488:
489: (void)snprintf(title, p->rmargin, "%s(%d)",
490: meta->title, meta->msec);
491:
492: p->offset = 0;
493: p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
494: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
495:
496: term_word(p, title);
497: term_flushln(p);
498:
499: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
500: p->offset = p->rmargin;
501: p->rmargin = p->maxrmargin - strlen(title);
502:
503: term_word(p, buf);
504: term_flushln(p);
505:
506: p->offset = p->rmargin;
507: p->rmargin = p->maxrmargin;
508: p->flags &= ~TERMP_NOBREAK;
509: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
510:
511: term_word(p, title);
512: term_flushln(p);
513:
514: p->rmargin = p->maxrmargin;
515: p->offset = 0;
516: p->flags &= ~TERMP_NOSPACE;
517:
518: free(title);
519: free(buf);
520: }
521: