]> git.cameronkatri.com Git - mandoc.git/blob - tbl_term.c
Tiny edit required after MDOC_HALT change.
[mandoc.git] / tbl_term.c
1 /* $Id: tbl_term.c,v 1.1 2011/01/02 12:21:07 kristaps Exp $ */
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 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 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "mandoc.h"
27 #include "out.h"
28 #include "term.h"
29
30 /* FIXME: `n' modifier doesn't always do the right thing. */
31 /* FIXME: `n' modifier doesn't use the cell-spacing buffer. */
32
33 static inline void tbl_char(struct termp *, char, int);
34 static void tbl_hframe(struct termp *,
35 const struct tbl_span *);
36 static void tbl_data_number(struct termp *,
37 const struct tbl *,
38 const struct tbl_dat *, int);
39 static void tbl_data_literal(struct termp *,
40 const struct tbl_dat *, int);
41 static void tbl_data_spanner(struct termp *,
42 const struct tbl_dat *, int);
43 static void tbl_data(struct termp *, const struct tbl *,
44 const struct tbl_dat *, int);
45 static void tbl_spanner(struct termp *,
46 const struct tbl_head *);
47 static void tbl_hrule(struct termp *,
48 const struct tbl_span *);
49 static void tbl_vframe(struct termp *, const struct tbl *);
50
51 void
52 term_tbl(struct termp *tp, const struct tbl_span *sp)
53 {
54 const struct tbl_head *hp;
55 const struct tbl_dat *dp;
56
57 if (TBL_SPAN_FIRST & sp->flags)
58 term_flushln(tp);
59
60 if (TBL_SPAN_FIRST & sp->flags)
61 tbl_hframe(tp, sp);
62
63 tp->flags |= TERMP_NONOSPACE;
64 tp->flags |= TERMP_NOSPACE;
65
66 tbl_vframe(tp, sp->tbl);
67
68 switch (sp->pos) {
69 case (TBL_SPAN_HORIZ):
70 /* FALLTHROUGH */
71 case (TBL_SPAN_DHORIZ):
72 tbl_hrule(tp, sp);
73 tbl_vframe(tp, sp->tbl);
74 term_newln(tp);
75 tp->flags &= ~TERMP_NONOSPACE;
76 return;
77 default:
78 break;
79 }
80
81 dp = sp->first;
82 for (hp = sp->head; hp; hp = hp->next) {
83 switch (hp->pos) {
84 case (TBL_HEAD_VERT):
85 /* FALLTHROUGH */
86 case (TBL_HEAD_DVERT):
87 tbl_spanner(tp, hp);
88 break;
89 case (TBL_HEAD_DATA):
90 tbl_data(tp, sp->tbl, dp, hp->width);
91 if (dp)
92 dp = dp->next;
93 break;
94 default:
95 abort();
96 /* NOTREACHED */
97 }
98 }
99
100 tbl_vframe(tp, sp->tbl);
101 term_flushln(tp);
102
103 if (TBL_SPAN_LAST & sp->flags)
104 tbl_hframe(tp, sp);
105
106 tp->flags &= ~TERMP_NONOSPACE;
107
108 }
109
110 static void
111 tbl_hrule(struct termp *tp, const struct tbl_span *sp)
112 {
113 const struct tbl_head *hp;
114 char c;
115
116 /*
117 * An hrule extends across the entire table and is demarked by a
118 * standalone `_' or whatnot in lieu of a table row. Spanning
119 * headers are marked by a `+', as are table boundaries.
120 */
121
122 c = '-';
123 if (TBL_SPAN_DHORIZ == sp->pos)
124 c = '=';
125
126 /* FIXME: don't use `+' between data and a spanner! */
127
128 for (hp = sp->head; hp; hp = hp->next) {
129 switch (hp->pos) {
130 case (TBL_HEAD_DATA):
131 tbl_char(tp, c, hp->width);
132 break;
133 case (TBL_HEAD_DVERT):
134 tbl_char(tp, '+', hp->width);
135 /* FALLTHROUGH */
136 case (TBL_HEAD_VERT):
137 tbl_char(tp, '+', hp->width);
138 break;
139 default:
140 abort();
141 /* NOTREACHED */
142 }
143 }
144 }
145
146 static void
147 tbl_hframe(struct termp *tp, const struct tbl_span *sp)
148 {
149 const struct tbl_head *hp;
150
151 if ( ! (TBL_OPT_BOX & sp->tbl->opts ||
152 TBL_OPT_DBOX & sp->tbl->opts))
153 return;
154
155 tp->flags |= TERMP_NONOSPACE;
156 tp->flags |= TERMP_NOSPACE;
157
158 /*
159 * Print out the horizontal part of a frame or double frame. A
160 * double frame has an unbroken `-' outer line the width of the
161 * table, bordered by `+'. The frame (or inner frame, in the
162 * case of the double frame) is a `-' bordered by `+' and broken
163 * by `+' whenever a span is encountered.
164 */
165
166 if (TBL_OPT_DBOX & sp->tbl->opts) {
167 term_word(tp, "+");
168 for (hp = sp->head; hp; hp = hp->next)
169 tbl_char(tp, '-', hp->width);
170 term_word(tp, "+");
171 term_flushln(tp);
172 }
173
174 term_word(tp, "+");
175 for (hp = sp->head; hp; hp = hp->next) {
176 switch (hp->pos) {
177 case (TBL_HEAD_DATA):
178 tbl_char(tp, '-', hp->width);
179 break;
180 default:
181 tbl_char(tp, '+', hp->width);
182 break;
183 }
184 }
185 term_word(tp, "+");
186 term_flushln(tp);
187 }
188
189 static void
190 tbl_data(struct termp *tp, const struct tbl *tbl,
191 const struct tbl_dat *dp, int width)
192 {
193 enum tbl_cellt pos;
194
195 if (NULL == dp) {
196 tbl_char(tp, ASCII_NBRSP, width);
197 return;
198 }
199
200 switch (dp->pos) {
201 case (TBL_DATA_HORIZ):
202 /* FALLTHROUGH */
203 case (TBL_DATA_DHORIZ):
204 tbl_data_spanner(tp, dp, width);
205 return;
206 default:
207 break;
208 }
209
210 pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
211
212 switch (pos) {
213 case (TBL_CELL_HORIZ):
214 /* FALLTHROUGH */
215 case (TBL_CELL_DHORIZ):
216 tbl_data_spanner(tp, dp, width);
217 break;
218 case (TBL_CELL_LONG):
219 /* FALLTHROUGH */
220 case (TBL_CELL_CENTRE):
221 /* FALLTHROUGH */
222 case (TBL_CELL_LEFT):
223 /* FALLTHROUGH */
224 case (TBL_CELL_RIGHT):
225 tbl_data_literal(tp, dp, width);
226 break;
227 case (TBL_CELL_NUMBER):
228 tbl_data_number(tp, tbl, dp, width);
229 break;
230 default:
231 abort();
232 /* NOTREACHED */
233 }
234 }
235 static void
236 tbl_spanner(struct termp *tp, const struct tbl_head *hp)
237 {
238
239 switch (hp->pos) {
240 case (TBL_HEAD_VERT):
241 term_word(tp, "|");
242 break;
243 case (TBL_HEAD_DVERT):
244 term_word(tp, "||");
245 break;
246 default:
247 break;
248 }
249 }
250
251 static void
252 tbl_vframe(struct termp *tp, const struct tbl *tbl)
253 {
254 /* Always just a single vertical line. */
255
256 if (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)
257 term_word(tp, "|");
258 }
259
260
261 static inline void
262 tbl_char(struct termp *tp, char c, int len)
263 {
264 int i;
265 char cp[2];
266
267 cp[0] = c;
268 cp[1] = '\0';
269
270 for (i = 0; i < len; i++)
271 term_word(tp, cp);
272 }
273
274 static void
275 tbl_data_spanner(struct termp *tp, const struct tbl_dat *dp, int width)
276 {
277
278 switch (dp->pos) {
279 case (TBL_DATA_HORIZ):
280 case (TBL_DATA_NHORIZ):
281 tbl_char(tp, '-', width);
282 break;
283 case (TBL_DATA_DHORIZ):
284 case (TBL_DATA_NDHORIZ):
285 tbl_char(tp, '=', width);
286 break;
287 default:
288 break;
289 }
290 }
291
292 static void
293 tbl_data_literal(struct termp *tp, const struct tbl_dat *dp, int width)
294 {
295 int padl, padr;
296 enum tbl_cellt pos;
297
298 padl = padr = 0;
299
300 pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
301
302 switch (pos) {
303 case (TBL_CELL_LONG):
304 padl = 1;
305 padr = width - (int)strlen(dp->string) - 1;
306 break;
307 case (TBL_CELL_CENTRE):
308 padl = width - (int)strlen(dp->string);
309 if (padl % 2)
310 padr++;
311 padl /= 2;
312 padr += padl;
313 break;
314 case (TBL_CELL_RIGHT):
315 padl = width - (int)strlen(dp->string);
316 break;
317 default:
318 padr = width - (int)strlen(dp->string);
319 break;
320 }
321
322 tbl_char(tp, ASCII_NBRSP, padl);
323 term_word(tp, dp->string);
324 tbl_char(tp, ASCII_NBRSP, padr);
325 }
326
327 static void
328 tbl_data_number(struct termp *tp, const struct tbl *tbl,
329 const struct tbl_dat *dp, int width)
330 {
331 char *decp, pnt;
332 int d, padl, sz;
333
334 /*
335 * See calc_data_number(). Left-pad by taking the offset of our
336 * and the maximum decimal; right-pad by the remaining amount.
337 */
338
339 sz = (int)strlen(dp->string);
340 pnt = tbl->decimal;
341
342 if (NULL == (decp = strchr(dp->string, pnt))) {
343 d = sz + 1;
344 } else {
345 d = (int)(decp - dp->string) + 1;
346 }
347
348 assert(d <= dp->layout->head->decimal);
349 assert(sz - d <= dp->layout->head->width -
350 dp->layout->head->decimal);
351
352 padl = dp->layout->head->decimal - d + 1;
353 assert(width - sz - padl);
354
355 tbl_char(tp, ASCII_NBRSP, padl);
356 term_word(tp, dp->string);
357 tbl_char(tp, ASCII_NBRSP, width - sz - padl);
358 }