Merge remote branch 'crater/vendor/MDOCML' into HEAD
[dragonfly.git] / contrib / mdocml / tbl_data.c
1 /*      $Id: tbl_data.c,v 1.14 2011/01/07 14:59:52 kristaps Exp $ */
2 /*
3  * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
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 <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26
27 #include "mandoc.h"
28 #include "libmandoc.h"
29 #include "libroff.h"
30
31 static  int     data(struct tbl_node *, struct tbl_span *, 
32                         int, const char *, int *);
33
34 static int
35 data(struct tbl_node *tbl, struct tbl_span *dp, 
36                 int ln, const char *p, int *pos)
37 {
38         struct tbl_dat  *dat;
39         struct tbl_cell *cp;
40         int              sv;
41
42         cp = NULL;
43         if (dp->last && dp->last->layout)
44                 cp = dp->last->layout->next;
45         else if (NULL == dp->last)
46                 cp = dp->layout->first;
47
48         /* 
49          * Skip over spanners and vertical lines to data formats, since
50          * we want to match data with data layout cells in the header.
51          */
52
53         while (cp && (TBL_CELL_VERT == cp->pos || 
54                                 TBL_CELL_DVERT == cp->pos ||
55                                 TBL_CELL_SPAN == cp->pos))
56                 cp = cp->next;
57
58         dat = mandoc_calloc(1, sizeof(struct tbl_dat));
59         dat->layout = cp;
60         dat->pos = TBL_DATA_NONE;
61
62         if (NULL == dat->layout)
63                 TBL_MSG(tbl, MANDOCERR_TBLEXTRADAT, ln, *pos);
64
65         if (dp->last) {
66                 dp->last->next = dat;
67                 dp->last = dat;
68         } else
69                 dp->last = dp->first = dat;
70
71         sv = *pos;
72         while (p[*pos] && p[*pos] != tbl->opts.tab)
73                 (*pos)++;
74
75         /*
76          * Check for a continued-data scope opening.  This consists of a
77          * trailing `T{' at the end of the line.  Subsequent lines,
78          * until a standalone `T}', are included in our cell.
79          */
80
81         if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) {
82                 tbl->part = TBL_PART_CDATA;
83                 return(0);
84         }
85
86         dat->string = mandoc_malloc(*pos - sv + 1);
87         memcpy(dat->string, &p[sv], *pos - sv);
88         dat->string[*pos - sv] = '\0';
89
90         if (p[*pos])
91                 (*pos)++;
92
93         if ( ! strcmp(dat->string, "_"))
94                 dat->pos = TBL_DATA_HORIZ;
95         else if ( ! strcmp(dat->string, "="))
96                 dat->pos = TBL_DATA_DHORIZ;
97         else if ( ! strcmp(dat->string, "\\_"))
98                 dat->pos = TBL_DATA_NHORIZ;
99         else if ( ! strcmp(dat->string, "\\="))
100                 dat->pos = TBL_DATA_NDHORIZ;
101         else
102                 dat->pos = TBL_DATA_DATA;
103
104         if (NULL == dat->layout)
105                 return(1);
106
107         if (TBL_CELL_HORIZ == dat->layout->pos ||
108                         TBL_CELL_DHORIZ == dat->layout->pos)
109                 if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string)
110                         TBL_MSG(tbl, MANDOCERR_TBLIGNDATA, ln, sv);
111
112         return(1);
113 }
114
115 /* ARGSUSED */
116 int
117 tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
118 {
119         struct tbl_dat  *dat;
120         size_t           sz;
121         int              pos;
122
123         pos = 0;
124
125         dat = tbl->last_span->last;
126         dat->pos = TBL_DATA_DATA;
127
128         if (p[pos] == 'T' && p[pos + 1] == '}') {
129                 pos += 2;
130                 if (p[pos] == tbl->opts.tab) {
131                         tbl->part = TBL_PART_DATA;
132                         pos++;
133                         return(data(tbl, tbl->last_span, ln, p, &pos));
134                 } else if ('\0' == p[pos]) {
135                         tbl->part = TBL_PART_DATA;
136                         return(1);
137                 }
138
139                 /* Fallthrough: T} is part of a word. */
140         }
141
142         if (dat->string) {
143                 sz = strlen(p) + strlen(dat->string) + 2;
144                 dat->string = mandoc_realloc(dat->string, sz);
145                 strlcat(dat->string, " ", sz);
146                 strlcat(dat->string, p, sz);
147         } else
148                 dat->string = mandoc_strdup(p);
149
150         return(0);
151 }
152
153 int
154 tbl_data(struct tbl_node *tbl, int ln, const char *p)
155 {
156         struct tbl_span *dp;
157         struct tbl_row  *rp;
158         int              pos;
159
160         pos = 0;
161
162         if ('\0' == p[pos]) {
163                 TBL_MSG(tbl, MANDOCERR_TBL, ln, pos);
164                 return(0);
165         }
166
167         /* 
168          * Choose a layout row: take the one following the last parsed
169          * span's.  If that doesn't exist, use the last parsed span's.
170          * If there's no last parsed span, use the first row.  This can
171          * be NULL!
172          */
173
174         if (tbl->last_span) {
175                 assert(tbl->last_span->layout);
176                 rp = tbl->last_span->layout->next;
177                 if (NULL == rp)
178                         rp = tbl->last_span->layout;
179         } else
180                 rp = tbl->first_row;
181
182         dp = mandoc_calloc(1, sizeof(struct tbl_span));
183         dp->tbl = &tbl->opts;
184         dp->layout = rp;
185         dp->head = tbl->first_head;
186
187         if (tbl->last_span) {
188                 tbl->last_span->next = dp;
189                 tbl->last_span = dp;
190         } else {
191                 tbl->last_span = tbl->first_span = dp;
192                 dp->flags |= TBL_SPAN_FIRST;
193         }
194
195         if ( ! strcmp(p, "_")) {
196                 dp->pos = TBL_SPAN_HORIZ;
197                 return(1);
198         } else if ( ! strcmp(p, "=")) {
199                 dp->pos = TBL_SPAN_DHORIZ;
200                 return(1);
201         }
202
203         dp->pos = TBL_SPAN_DATA;
204
205         /* This returns 0 when TBL_PART_CDATA is entered. */
206
207         while ('\0' != p[pos])
208                 if ( ! data(tbl, dp, ln, p, &pos))
209                         return(0);
210
211         return(1);
212 }