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