netinet{,6}: Assert in{,6}_inithead() are only used for system routing tables.
[dragonfly.git] / contrib / mdocml / out.c
1 /*      $Id: out.c,v 1.49 2014/08/01 19:25:52 schwarze Exp $ */
2 /*
3  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <sys/types.h>
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30
31 #include "mandoc_aux.h"
32 #include "mandoc.h"
33 #include "out.h"
34
35 static  void    tblcalc_data(struct rofftbl *, struct roffcol *,
36                         const struct tbl_opts *, const struct tbl_dat *);
37 static  void    tblcalc_literal(struct rofftbl *, struct roffcol *,
38                         const struct tbl_dat *);
39 static  void    tblcalc_number(struct rofftbl *, struct roffcol *,
40                         const struct tbl_opts *, const struct tbl_dat *);
41
42
43 /*
44  * Convert a `scaling unit' to a consistent form, or fail.  Scaling
45  * units are documented in groff.7, mdoc.7, man.7.
46  */
47 int
48 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
49 {
50         char             buf[BUFSIZ], hasd;
51         int              i;
52         enum roffscale   unit;
53
54         if ('\0' == *src)
55                 return(0);
56
57         i = hasd = 0;
58
59         switch (*src) {
60         case '+':
61                 src++;
62                 break;
63         case '-':
64                 buf[i++] = *src++;
65                 break;
66         default:
67                 break;
68         }
69
70         if ('\0' == *src)
71                 return(0);
72
73         while (i < BUFSIZ) {
74                 if ( ! isdigit((unsigned char)*src)) {
75                         if ('.' != *src)
76                                 break;
77                         else if (hasd)
78                                 break;
79                         else
80                                 hasd = 1;
81                 }
82                 buf[i++] = *src++;
83         }
84
85         if (BUFSIZ == i || (*src && *(src + 1)))
86                 return(0);
87
88         buf[i] = '\0';
89
90         switch (*src) {
91         case 'c':
92                 unit = SCALE_CM;
93                 break;
94         case 'i':
95                 unit = SCALE_IN;
96                 break;
97         case 'P':
98                 unit = SCALE_PC;
99                 break;
100         case 'p':
101                 unit = SCALE_PT;
102                 break;
103         case 'f':
104                 unit = SCALE_FS;
105                 break;
106         case 'v':
107                 unit = SCALE_VS;
108                 break;
109         case 'm':
110                 unit = SCALE_EM;
111                 break;
112         case '\0':
113                 if (SCALE_MAX == def)
114                         return(0);
115                 unit = SCALE_BU;
116                 break;
117         case 'u':
118                 unit = SCALE_BU;
119                 break;
120         case 'M':
121                 unit = SCALE_MM;
122                 break;
123         case 'n':
124                 unit = SCALE_EN;
125                 break;
126         default:
127                 return(0);
128         }
129
130         /* FIXME: do this in the caller. */
131         if ((dst->scale = atof(buf)) < 0.0)
132                 dst->scale = 0.0;
133         dst->unit = unit;
134         return(1);
135 }
136
137 /*
138  * Calculate the abstract widths and decimal positions of columns in a
139  * table.  This routine allocates the columns structures then runs over
140  * all rows and cells in the table.  The function pointers in "tbl" are
141  * used for the actual width calculations.
142  */
143 void
144 tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
145 {
146         const struct tbl_dat    *dp;
147         struct roffcol          *col;
148         int                      spans;
149
150         /*
151          * Allocate the master column specifiers.  These will hold the
152          * widths and decimal positions for all cells in the column.  It
153          * must be freed and nullified by the caller.
154          */
155
156         assert(NULL == tbl->cols);
157         tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
158             sizeof(struct roffcol));
159
160         for ( ; sp; sp = sp->next) {
161                 if (TBL_SPAN_DATA != sp->pos)
162                         continue;
163                 spans = 1;
164                 /*
165                  * Account for the data cells in the layout, matching it
166                  * to data cells in the data section.
167                  */
168                 for (dp = sp->first; dp; dp = dp->next) {
169                         /* Do not used spanned cells in the calculation. */
170                         if (0 < --spans)
171                                 continue;
172                         spans = dp->spans;
173                         if (1 < spans)
174                                 continue;
175                         assert(dp->layout);
176                         col = &tbl->cols[dp->layout->head->ident];
177                         tblcalc_data(tbl, col, sp->opts, dp);
178                 }
179         }
180 }
181
182 static void
183 tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
184                 const struct tbl_opts *opts, const struct tbl_dat *dp)
185 {
186         size_t           sz;
187
188         /* Branch down into data sub-types. */
189
190         switch (dp->layout->pos) {
191         case TBL_CELL_HORIZ:
192                 /* FALLTHROUGH */
193         case TBL_CELL_DHORIZ:
194                 sz = (*tbl->len)(1, tbl->arg);
195                 if (col->width < sz)
196                         col->width = sz;
197                 break;
198         case TBL_CELL_LONG:
199                 /* FALLTHROUGH */
200         case TBL_CELL_CENTRE:
201                 /* FALLTHROUGH */
202         case TBL_CELL_LEFT:
203                 /* FALLTHROUGH */
204         case TBL_CELL_RIGHT:
205                 tblcalc_literal(tbl, col, dp);
206                 break;
207         case TBL_CELL_NUMBER:
208                 tblcalc_number(tbl, col, opts, dp);
209                 break;
210         case TBL_CELL_DOWN:
211                 break;
212         default:
213                 abort();
214                 /* NOTREACHED */
215         }
216 }
217
218 static void
219 tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
220                 const struct tbl_dat *dp)
221 {
222         size_t           sz;
223         const char      *str;
224
225         str = dp->string ? dp->string : "";
226         sz = (*tbl->slen)(str, tbl->arg);
227
228         if (col->width < sz)
229                 col->width = sz;
230 }
231
232 static void
233 tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
234                 const struct tbl_opts *opts, const struct tbl_dat *dp)
235 {
236         int              i;
237         size_t           sz, psz, ssz, d;
238         const char      *str;
239         char            *cp;
240         char             buf[2];
241
242         /*
243          * First calculate number width and decimal place (last + 1 for
244          * non-decimal numbers).  If the stored decimal is subsequent to
245          * ours, make our size longer by that difference
246          * (right-"shifting"); similarly, if ours is subsequent the
247          * stored, then extend the stored size by the difference.
248          * Finally, re-assign the stored values.
249          */
250
251         str = dp->string ? dp->string : "";
252         sz = (*tbl->slen)(str, tbl->arg);
253
254         /* FIXME: TBL_DATA_HORIZ et al.? */
255
256         buf[0] = opts->decimal;
257         buf[1] = '\0';
258
259         psz = (*tbl->slen)(buf, tbl->arg);
260
261         if (NULL != (cp = strrchr(str, opts->decimal))) {
262                 buf[1] = '\0';
263                 for (ssz = 0, i = 0; cp != &str[i]; i++) {
264                         buf[0] = str[i];
265                         ssz += (*tbl->slen)(buf, tbl->arg);
266                 }
267                 d = ssz + psz;
268         } else
269                 d = sz + psz;
270
271         /* Adjust the settings for this column. */
272
273         if (col->decimal > d) {
274                 sz += col->decimal - d;
275                 d = col->decimal;
276         } else
277                 col->width += d - col->decimal;
278
279         if (sz > col->width)
280                 col->width = sz;
281         if (d > col->decimal)
282                 col->decimal = d;
283 }