| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /* $OpenBSD: tbl_layout.c,v 1.31 2017/06/27 18:23:29 schwarze Exp $ */  | 
    ||
2  | 
    /*  | 
    ||
3  | 
    * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>  | 
    ||
4  | 
    * Copyright (c) 2012, 2014, 2015, 2017 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  | 
    #include <sys/types.h>  | 
    ||
19  | 
    |||
20  | 
    #include <ctype.h>  | 
    ||
21  | 
    #include <stdint.h>  | 
    ||
22  | 
    #include <stdlib.h>  | 
    ||
23  | 
    #include <string.h>  | 
    ||
24  | 
    #include <time.h>  | 
    ||
25  | 
    |||
26  | 
    #include "mandoc.h"  | 
    ||
27  | 
    #include "mandoc_aux.h"  | 
    ||
28  | 
    #include "libmandoc.h"  | 
    ||
29  | 
    #include "libroff.h"  | 
    ||
30  | 
    |||
31  | 
    struct	tbl_phrase { | 
    ||
32  | 
    char name;  | 
    ||
33  | 
    enum tbl_cellt key;  | 
    ||
34  | 
    };  | 
    ||
35  | 
    |||
36  | 
    static	const struct tbl_phrase keys[] = { | 
    ||
37  | 
    	{ 'c',		 TBL_CELL_CENTRE }, | 
    ||
38  | 
    	{ 'r',		 TBL_CELL_RIGHT }, | 
    ||
39  | 
    	{ 'l',		 TBL_CELL_LEFT }, | 
    ||
40  | 
    	{ 'n',		 TBL_CELL_NUMBER }, | 
    ||
41  | 
    	{ 's',		 TBL_CELL_SPAN }, | 
    ||
42  | 
    	{ 'a',		 TBL_CELL_LONG }, | 
    ||
43  | 
    	{ '^',		 TBL_CELL_DOWN }, | 
    ||
44  | 
    	{ '-',		 TBL_CELL_HORIZ }, | 
    ||
45  | 
    	{ '_',		 TBL_CELL_HORIZ }, | 
    ||
46  | 
    	{ '=',		 TBL_CELL_DHORIZ } | 
    ||
47  | 
    };  | 
    ||
48  | 
    |||
49  | 
    #define KEYS_MAX ((int)(sizeof(keys)/sizeof(keys[0])))  | 
    ||
50  | 
    |||
51  | 
    static void mods(struct tbl_node *, struct tbl_cell *,  | 
    ||
52  | 
    int, const char *, int *);  | 
    ||
53  | 
    static void cell(struct tbl_node *, struct tbl_row *,  | 
    ||
54  | 
    int, const char *, int *);  | 
    ||
55  | 
    static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *,  | 
    ||
56  | 
    enum tbl_cellt);  | 
    ||
57  | 
    |||
58  | 
    |||
59  | 
    static void  | 
    ||
60  | 
    mods(struct tbl_node *tbl, struct tbl_cell *cp,  | 
    ||
61  | 
    int ln, const char *p, int *pos)  | 
    ||
62  | 
    { | 
    ||
63  | 
    106314  | 
    char *endptr;  | 
    |
64  | 
    53157  | 
    size_t sz;  | 
    |
65  | 
    |||
66  | 
    mod:  | 
    ||
67  | 
    ✓✓✓✓ | 
    277785  | 
    while (p[*pos] == ' ' || p[*pos] == '\t')  | 
    
68  | 
    45126  | 
    (*pos)++;  | 
    |
69  | 
    |||
70  | 
    /* Row delimiters and cell specifiers end modifier lists. */  | 
    ||
71  | 
    |||
72  | 
    ✓✓ | 62505  | 
    	if (strchr(".,-=^_ACLNRSaclnrs", p[*pos]) != NULL) | 
    
73  | 
    53157  | 
    return;  | 
    |
74  | 
    |||
75  | 
    /* Throw away parenthesised expression. */  | 
    ||
76  | 
    |||
77  | 
    ✓✓ | 9348  | 
    	if ('(' == p[*pos]) { | 
    
78  | 
    (*pos)++;  | 
    ||
79  | 
    ✓✗✓✓ | 
    378  | 
    while (p[*pos] && ')' != p[*pos])  | 
    
80  | 
    (*pos)++;  | 
    ||
81  | 
    ✓✗ | 18  | 
    		if (')' == p[*pos]) { | 
    
82  | 
    18  | 
    (*pos)++;  | 
    |
83  | 
    18  | 
    goto mod;  | 
    |
84  | 
    }  | 
    ||
85  | 
    mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse,  | 
    ||
86  | 
    ln, *pos, NULL);  | 
    ||
87  | 
    return;  | 
    ||
88  | 
    }  | 
    ||
89  | 
    |||
90  | 
    /* Parse numerical spacing from modifier string. */  | 
    ||
91  | 
    |||
92  | 
    ✓✓ | 9330  | 
    	if (isdigit((unsigned char)p[*pos])) { | 
    
93  | 
    246  | 
    cp->spacing = strtoull(p + *pos, &endptr, 10);  | 
    |
94  | 
    246  | 
    *pos = endptr - p;  | 
    |
95  | 
    246  | 
    goto mod;  | 
    |
96  | 
    }  | 
    ||
97  | 
    |||
98  | 
    ✓✗✓✓ ✗✗✓✓ ✗✓✓✓ ✓✗✓  | 
    9084  | 
    	switch (tolower((unsigned char)p[(*pos)++])) { | 
    
99  | 
    case 'b':  | 
    ||
100  | 
    84  | 
    cp->flags |= TBL_CELL_BOLD;  | 
    |
101  | 
    84  | 
    goto mod;  | 
    |
102  | 
    case 'd':  | 
    ||
103  | 
    cp->flags |= TBL_CELL_BALIGN;  | 
    ||
104  | 
    goto mod;  | 
    ||
105  | 
    case 'e':  | 
    ||
106  | 
    6  | 
    cp->flags |= TBL_CELL_EQUAL;  | 
    |
107  | 
    6  | 
    goto mod;  | 
    |
108  | 
    case 'f':  | 
    ||
109  | 
    break;  | 
    ||
110  | 
    case 'i':  | 
    ||
111  | 
    84  | 
    cp->flags |= TBL_CELL_ITALIC;  | 
    |
112  | 
    84  | 
    goto mod;  | 
    |
113  | 
    case 'm':  | 
    ||
114  | 
    mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse,  | 
    ||
115  | 
    ln, *pos, "m");  | 
    ||
116  | 
    goto mod;  | 
    ||
117  | 
    case 'p':  | 
    ||
118  | 
    case 'v':  | 
    ||
119  | 
    ✗✓✗✗ | 
    18  | 
    if (p[*pos] == '-' || p[*pos] == '+')  | 
    
120  | 
    18  | 
    (*pos)++;  | 
    |
121  | 
    ✓✓ | 90  | 
    while (isdigit((unsigned char)p[*pos]))  | 
    
122  | 
    (*pos)++;  | 
    ||
123  | 
    goto mod;  | 
    ||
124  | 
    case 't':  | 
    ||
125  | 
    6  | 
    cp->flags |= TBL_CELL_TALIGN;  | 
    |
126  | 
    6  | 
    goto mod;  | 
    |
127  | 
    case 'u':  | 
    ||
128  | 
    cp->flags |= TBL_CELL_UP;  | 
    ||
129  | 
    goto mod;  | 
    ||
130  | 
    case 'w':  | 
    ||
131  | 
    sz = 0;  | 
    ||
132  | 
    ✓✓ | 174  | 
    		if (p[*pos] == '(') { | 
    
133  | 
    18  | 
    (*pos)++;  | 
    |
134  | 
    ✓✗✓✓ | 
    243  | 
    while (p[*pos + sz] != '\0' && p[*pos + sz] != ')')  | 
    
135  | 
    63  | 
    sz++;  | 
    |
136  | 
    } else  | 
    ||
137  | 
    ✓✓ | 630  | 
    while (isdigit((unsigned char)p[*pos + sz]))  | 
    
138  | 
    237  | 
    sz++;  | 
    |
139  | 
    ✗✓ | 174  | 
    		if (sz) { | 
    
140  | 
    174  | 
    free(cp->wstr);  | 
    |
141  | 
    174  | 
    cp->wstr = mandoc_strndup(p + *pos, sz);  | 
    |
142  | 
    174  | 
    *pos += sz;  | 
    |
143  | 
    ✓✓ | 174  | 
    if (p[*pos] == ')')  | 
    
144  | 
    18  | 
    (*pos)++;  | 
    |
145  | 
    }  | 
    ||
146  | 
    goto mod;  | 
    ||
147  | 
    case 'x':  | 
    ||
148  | 
    1656  | 
    cp->flags |= TBL_CELL_WMAX;  | 
    |
149  | 
    1656  | 
    goto mod;  | 
    |
150  | 
    case 'z':  | 
    ||
151  | 
    15  | 
    cp->flags |= TBL_CELL_WIGN;  | 
    |
152  | 
    15  | 
    goto mod;  | 
    |
153  | 
    case '|':  | 
    ||
154  | 
    ✓✓ | 6861  | 
    if (cp->vert < 2)  | 
    
155  | 
    6825  | 
    cp->vert++;  | 
    |
156  | 
    else  | 
    ||
157  | 
    36  | 
    mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,  | 
    |
158  | 
    36  | 
    tbl->parse, ln, *pos - 1, NULL);  | 
    |
159  | 
    goto mod;  | 
    ||
160  | 
    default:  | 
    ||
161  | 
    mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,  | 
    ||
162  | 
    ln, *pos - 1, "%c", p[*pos - 1]);  | 
    ||
163  | 
    goto mod;  | 
    ||
164  | 
    }  | 
    ||
165  | 
    |||
166  | 
    /* Ignore parenthised font names for now. */  | 
    ||
167  | 
    |||
168  | 
    ✓✓ | 180  | 
    	if (p[*pos] == '(') | 
    
169  | 
    goto mod;  | 
    ||
170  | 
    |||
171  | 
    /* Support only one-character font-names for now. */  | 
    ||
172  | 
    |||
173  | 
    ✓✓✓✓ ✓✓  | 
    378  | 
    	if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) { | 
    
174  | 
    108  | 
    mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,  | 
    |
175  | 
    54  | 
    ln, *pos, "TS %s", p + *pos - 1);  | 
    |
176  | 
    ✓✓ | 54  | 
    if (p[*pos] != '\0')  | 
    
177  | 
    36  | 
    (*pos)++;  | 
    |
178  | 
    ✓✓ | 54  | 
    if (p[*pos] != '\0')  | 
    
179  | 
    18  | 
    (*pos)++;  | 
    |
180  | 
    goto mod;  | 
    ||
181  | 
    }  | 
    ||
182  | 
    |||
183  | 
    ✗✓✗✓ ✗✓✗  | 
    270  | 
    	switch (p[(*pos)++]) { | 
    
184  | 
    case '3':  | 
    ||
185  | 
    case 'B':  | 
    ||
186  | 
    54  | 
    cp->flags |= TBL_CELL_BOLD;  | 
    |
187  | 
    54  | 
    goto mod;  | 
    |
188  | 
    case '2':  | 
    ||
189  | 
    case 'I':  | 
    ||
190  | 
    54  | 
    cp->flags |= TBL_CELL_ITALIC;  | 
    |
191  | 
    54  | 
    goto mod;  | 
    |
192  | 
    case '1':  | 
    ||
193  | 
    case 'R':  | 
    ||
194  | 
    goto mod;  | 
    ||
195  | 
    default:  | 
    ||
196  | 
    mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,  | 
    ||
197  | 
    ln, *pos - 1, "TS f%c", p[*pos - 1]);  | 
    ||
198  | 
    goto mod;  | 
    ||
199  | 
    }  | 
    ||
200  | 
    53157  | 
    }  | 
    |
201  | 
    |||
202  | 
    static void  | 
    ||
203  | 
    cell(struct tbl_node *tbl, struct tbl_row *rp,  | 
    ||
204  | 
    int ln, const char *p, int *pos)  | 
    ||
205  | 
    { | 
    ||
206  | 
    int i;  | 
    ||
207  | 
    enum tbl_cellt c;  | 
    ||
208  | 
    |||
209  | 
    /* Handle leading vertical lines */  | 
    ||
210  | 
    |||
211  | 
    ✓✓✓✗ ✓✓  | 
    273957  | 
    	while (p[*pos] == ' ' || p[*pos] == '\t' || p[*pos] == '|') { | 
    
212  | 
    ✓✓ | 2448  | 
    		if (p[*pos] == '|') { | 
    
213  | 
    ✓✗ | 1548  | 
    if (rp->vert < 2)  | 
    
214  | 
    1548  | 
    rp->vert++;  | 
    |
215  | 
    else  | 
    ||
216  | 
    mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,  | 
    ||
217  | 
    tbl->parse, ln, *pos, NULL);  | 
    ||
218  | 
    }  | 
    ||
219  | 
    2448  | 
    (*pos)++;  | 
    |
220  | 
    }  | 
    ||
221  | 
    |||
222  | 
    again:  | 
    ||
223  | 
    ✓✗✗✓ | 
    159579  | 
    while (p[*pos] == ' ' || p[*pos] == '\t')  | 
    
224  | 
    (*pos)++;  | 
    ||
225  | 
    |||
226  | 
    ✓✓✓✓ | 
    106359  | 
    if (p[*pos] == '.' || p[*pos] == '\0')  | 
    
227  | 
    36  | 
    return;  | 
    |
228  | 
    |||
229  | 
    /* Parse the column position (`c', `l', `r', ...). */  | 
    ||
230  | 
    |||
231  | 
    ✓✗ | 384234  | 
    for (i = 0; i < KEYS_MAX; i++)  | 
    
232  | 
    ✓✓ | 192117  | 
    if (tolower((unsigned char)p[*pos]) == keys[i].name)  | 
    
233  | 
    break;  | 
    ||
234  | 
    |||
235  | 
    ✗✓ | 53157  | 
    	if (i == KEYS_MAX) { | 
    
236  | 
    mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,  | 
    ||
237  | 
    ln, *pos, "%c", p[*pos]);  | 
    ||
238  | 
    (*pos)++;  | 
    ||
239  | 
    goto again;  | 
    ||
240  | 
    }  | 
    ||
241  | 
    53157  | 
    c = keys[i].key;  | 
    |
242  | 
    |||
243  | 
    /* Special cases of spanners. */  | 
    ||
244  | 
    |||
245  | 
    ✓✓ | 53157  | 
    	if (c == TBL_CELL_SPAN) { | 
    
246  | 
    ✗✓ | 198  | 
    if (rp->last == NULL)  | 
    
247  | 
    mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN,  | 
    ||
248  | 
    tbl->parse, ln, *pos, NULL);  | 
    ||
249  | 
    ✓✗✗✓ | 
    396  | 
    else if (rp->last->pos == TBL_CELL_HORIZ ||  | 
    
250  | 
    198  | 
    rp->last->pos == TBL_CELL_DHORIZ)  | 
    |
251  | 
    c = rp->last->pos;  | 
    ||
252  | 
    ✓✓✓✓ | 
    53019  | 
    } else if (c == TBL_CELL_DOWN && rp == tbl->first_row)  | 
    
253  | 
    18  | 
    mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN,  | 
    |
254  | 
    18  | 
    tbl->parse, ln, *pos, NULL);  | 
    |
255  | 
    |||
256  | 
    53157  | 
    (*pos)++;  | 
    |
257  | 
    |||
258  | 
    /* Allocate cell then parse its modifiers. */  | 
    ||
259  | 
    |||
260  | 
    53157  | 
    mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos);  | 
    |
261  | 
    106350  | 
    }  | 
    |
262  | 
    |||
263  | 
    void  | 
    ||
264  | 
    tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos)  | 
    ||
265  | 
    { | 
    ||
266  | 
    struct tbl_row *rp;  | 
    ||
267  | 
    |||
268  | 
    rp = NULL;  | 
    ||
269  | 
    73787  | 
    	for (;;) { | 
    |
270  | 
    /* Skip whitespace before and after each cell. */  | 
    ||
271  | 
    |||
272  | 
    ✓✓✗✓ | 
    232692  | 
    while (p[pos] == ' ' || p[pos] == '\t')  | 
    
273  | 
    5625  | 
    pos++;  | 
    |
274  | 
    |||
275  | 
    ✓✓✓✓ | 
    73814  | 
    		switch (p[pos]) { | 
    
276  | 
    case ',': /* Next row on this input line. */  | 
    ||
277  | 
    27  | 
    pos++;  | 
    |
278  | 
    rp = NULL;  | 
    ||
279  | 
    27  | 
    continue;  | 
    |
280  | 
    case '\0': /* Next row on next input line. */  | 
    ||
281  | 
    13657  | 
    return;  | 
    |
282  | 
    case '.': /* End of layout. */  | 
    ||
283  | 
    6937  | 
    pos++;  | 
    |
284  | 
    6937  | 
    tbl->part = TBL_PART_DATA;  | 
    |
285  | 
    |||
286  | 
    /*  | 
    ||
287  | 
    * When the layout is completely empty,  | 
    ||
288  | 
    * default to one left-justified column.  | 
    ||
289  | 
    */  | 
    ||
290  | 
    |||
291  | 
    ✓✓ | 6937  | 
    			if (tbl->first_row == NULL) { | 
    
292  | 
    18  | 
    tbl->first_row = tbl->last_row =  | 
    |
293  | 
    18  | 
    mandoc_calloc(1, sizeof(*rp));  | 
    |
294  | 
    18  | 
    }  | 
    |
295  | 
    ✓✓ | 6937  | 
    			if (tbl->first_row->first == NULL) { | 
    
296  | 
    36  | 
    mandoc_msg(MANDOCERR_TBLLAYOUT_NONE,  | 
    |
297  | 
    36  | 
    tbl->parse, ln, pos, NULL);  | 
    |
298  | 
    36  | 
    cell_alloc(tbl, tbl->first_row,  | 
    |
299  | 
    TBL_CELL_LEFT);  | 
    ||
300  | 
    ✓✓ | 36  | 
    if (tbl->opts.lvert < tbl->first_row->vert)  | 
    
301  | 
    18  | 
    tbl->opts.lvert = tbl->first_row->vert;  | 
    |
302  | 
    36  | 
    return;  | 
    |
303  | 
    }  | 
    ||
304  | 
    |||
305  | 
    /*  | 
    ||
306  | 
    * Search for the widest line  | 
    ||
307  | 
    * along the left and right margins.  | 
    ||
308  | 
    */  | 
    ||
309  | 
    |||
310  | 
    ✓✓ | 54972  | 
    			for (rp = tbl->first_row; rp; rp = rp->next) { | 
    
311  | 
    ✓✓ | 20585  | 
    if (tbl->opts.lvert < rp->vert)  | 
    
312  | 
    1008  | 
    tbl->opts.lvert = rp->vert;  | 
    |
313  | 
    ✓✗✓✓ | 
    41140  | 
    if (rp->last != NULL &&  | 
    
314  | 
    ✓✓ | 20585  | 
    rp->last->col + 1 == tbl->opts.cols &&  | 
    
315  | 
    20555  | 
    tbl->opts.rvert < rp->last->vert)  | 
    |
316  | 
    999  | 
    tbl->opts.rvert = rp->last->vert;  | 
    |
317  | 
    |||
318  | 
    /* If the last line is empty, drop it. */  | 
    ||
319  | 
    |||
320  | 
    ✓✓✓✓ | 
    34278  | 
    if (rp->next != NULL &&  | 
    
321  | 
    13693  | 
    				    rp->next->first == NULL) { | 
    |
322  | 
    9  | 
    free(rp->next);  | 
    |
323  | 
    9  | 
    rp->next = NULL;  | 
    |
324  | 
    9  | 
    tbl->last_row = rp;  | 
    |
325  | 
    9  | 
    }  | 
    |
326  | 
    }  | 
    ||
327  | 
    6901  | 
    return;  | 
    |
328  | 
    default: /* Cell. */  | 
    ||
329  | 
    break;  | 
    ||
330  | 
    }  | 
    ||
331  | 
    |||
332  | 
    /*  | 
    ||
333  | 
    * If the last line had at least one cell,  | 
    ||
334  | 
    * start a new one; otherwise, continue it.  | 
    ||
335  | 
    */  | 
    ||
336  | 
    |||
337  | 
    ✓✓ | 53193  | 
    		if (rp == NULL) { | 
    
338  | 
    ✓✓✓✓ | 
    34305  | 
    if (tbl->last_row == NULL ||  | 
    
339  | 
    13702  | 
    			    tbl->last_row->first != NULL) { | 
    |
340  | 
    20594  | 
    rp = mandoc_calloc(1, sizeof(*rp));  | 
    |
341  | 
    ✓✓ | 20594  | 
    if (tbl->last_row)  | 
    
342  | 
    13693  | 
    tbl->last_row->next = rp;  | 
    |
343  | 
    else  | 
    ||
344  | 
    6901  | 
    tbl->first_row = rp;  | 
    |
345  | 
    20594  | 
    tbl->last_row = rp;  | 
    |
346  | 
    20594  | 
    } else  | 
    |
347  | 
    rp = tbl->last_row;  | 
    ||
348  | 
    }  | 
    ||
349  | 
    53193  | 
    cell(tbl, rp, ln, p, &pos);  | 
    |
350  | 
    }  | 
    ||
351  | 
    20594  | 
    }  | 
    |
352  | 
    |||
353  | 
    static struct tbl_cell *  | 
    ||
354  | 
    cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)  | 
    ||
355  | 
    { | 
    ||
356  | 
    struct tbl_cell *p, *pp;  | 
    ||
357  | 
    |||
358  | 
    106386  | 
    p = mandoc_calloc(1, sizeof(*p));  | 
    |
359  | 
    53193  | 
    p->spacing = SIZE_MAX;  | 
    |
360  | 
    53193  | 
    p->pos = pos;  | 
    |
361  | 
    |||
362  | 
    ✓✓ | 53193  | 
    	if ((pp = rp->last) != NULL) { | 
    
363  | 
    32590  | 
    pp->next = p;  | 
    |
364  | 
    32590  | 
    p->col = pp->col + 1;  | 
    |
365  | 
    32590  | 
    } else  | 
    |
366  | 
    20603  | 
    rp->first = p;  | 
    |
367  | 
    53193  | 
    rp->last = p;  | 
    |
368  | 
    |||
369  | 
    ✓✓ | 53193  | 
    if (tbl->opts.cols <= p->col)  | 
    
370  | 
    18324  | 
    tbl->opts.cols = p->col + 1;  | 
    |
371  | 
    |||
372  | 
    53193  | 
    return p;  | 
    |
373  | 
    }  | 
    
| Generated by: GCOVR (Version 3.3) |