• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ascii-boxes / boxes / 11084497071

28 Sep 2024 01:00PM UTC coverage: 87.312% (-1.6%) from 88.939%
11084497071

push

github

tsjensen
Remove unused function array_contains() from 'tools' module

3132 of 3809 branches covered (82.23%)

Branch coverage included in aggregate %.

5091 of 5609 relevant lines covered (90.76%)

175335.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.18
/src/parser.y
1
%code requires {
2
/*
3
 * boxes - Command line filter to draw/remove ASCII boxes around text
4
 * Copyright (c) 1999-2024 Thomas Jensen and the boxes contributors
5
 *
6
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
7
 * License, version 3, as published by the Free Software Foundation.
8
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
9
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
10
 * details.
11
 * You should have received a copy of the GNU General Public License along with this program.
12
 * If not, see <https://www.gnu.org/licenses/>.
13
 *
14
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15
 */
16

17
/*
18
 * Yacc parser for boxes configuration files
19
 */
20

21
#include "config.h"
22
#include "boxes.h"
23
#include "bxstring.h"
24

25

26
/** all the arguments which we pass to the bison parser */
27
typedef struct {
28
    /** bison will store the parsed designs here, also allocating memory as required */
29
    design_t *designs;
30

31
    /** the size of `*designs` */
32
    size_t num_designs;
33

34
    /** index into `*designs` */
35
    int design_idx;
36

37
    /** Box designs already parsed from child config files, if any. Else NULL */
38
    design_t *child_configs;
39

40
    /** the size of `*child_configs` */
41
    size_t num_child_configs;
42

43
    /** the path to the config file we are parsing */
44
    bxstr_t *config_file;
45

46
    int num_mandatory;
47

48
    int time_for_se_check;
49

50
    /** number of user-specified shapes */
51
    int num_shapespec;
52

53
    /** used to limit "skipping" msgs */
54
    int skipping;
55

56
    /** true if we're skipping designs, but no error */
57
    int speeding;
58

59
    /** names of config files specified via "parent" */
60
    bxstr_t **parent_configs;
61

62
    /** number of parent config files (size of parent_configs array) */
63
    size_t num_parent_configs;
64

65
    /** the flex scanner state, which is explicitly passed to reentrant bison */
66
    void *lexer_state;
67
} pass_to_bison;
68

69
}
70

71
%code {
72

73
#include "config.h"
74
#include <stdio.h>
75
#include <stdlib.h>
76
#include <unictype.h>
77

78
#include "logging.h"
79
#include "shape.h"
80
#include "tools.h"
81
#include "parsing.h"
82
#include "parser.h"
83
#include "lex.yy.h"
84
#include "parsecode.h"
85
#include "unicode.h"
86

87

88
/** required for bison-flex bridge */
89
#define scanner bison_args->lexer_state
90

91
/** invoke a parsecode action and react to its return code */
92
#define invoke_action(action) {   \
93
    int rc = (action);            \
94
    if (rc == RC_ERROR) {         \
95
        YYERROR;                  \
96
    } else if (rc == RC_ABORT) {  \
97
        YYABORT;                  \
98
    } else if (rc == RC_ACCEPT) { \
99
        YYACCEPT;                 \
100
    }                             \
101
}
102

103
}
104

105

106
/*\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\
107
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|
108
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
109
|  |                                                                                            |  |
110
|  |                              B i s o n  D e f i n i t i o n s                              |  |
111
|  |                                                                                            |  |
112
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|
113
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|_*/
114

115
%define api.pure true
116
%lex-param {void *scanner}
117
%parse-param {pass_to_bison *bison_args}
118

119
%union {
120
    bxstr_t *s;
121
    char *ascii;
122
    char c;
123
    shape_t shape;
124
    sentry_t sentry;
125
    int num;
126
}
127

128
%token YPARENT YSHAPES YELASTIC YPADDING YSAMPLE YENDSAMPLE YBOX YEND YUNREC
129
%token YREPLACE YREVERSE YTO YWITH YCHGDEL YTAGS
130
%token <ascii> KEYWORD
131
%token <s> BXWORD
132
%token <ascii> ASCII_ID
133
%token <s> STRING
134
%token <s> FILENAME
135
%token <shape> SHAPE
136
%token <num> YNUMBER
137
%token <c> YRXPFLAG
138
%token <s> YDELIMSPEC
139

140
%type <sentry> shape_def
141
%type <sentry> shape_lines
142
%type <c> rflag
143

144
%start first_rule
145

146

147
%%
148

149
/*\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\
150
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|
151
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
152
|  |                                                                                            |  |
153
|  |                             G r a m m a r   &   A c t i o n s                              |  |
154
|  |                                                                                            |  |
155
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|
156
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|_*/
157

158

159
first_rule:
160
    {
161
        invoke_action(action_init_parser(bison_args));
397!
162
    }
163

164
config_file
165
    {
166
        /*
167
         *  Clean up parser data structures
168
         */
169
        design_t *tmp;
170

171
        if (bison_args->design_idx == 0) {
48✔
172
            BFREE (bison_args->designs);
8!
173
            bison_args->num_designs = 0;
8✔
174
            if (!opt.design_choice_by_user && bison_args->num_parent_configs == 0) {
8✔
175
                fprintf(stderr, "%s: no valid data in config file -- %s\n", PROJECT,
3✔
176
                        bxs_to_output(bison_args->config_file));
177
                YYABORT;
3✔
178
            }
179
            YYACCEPT;
5✔
180
        }
181

182
        --(bison_args->design_idx);
40✔
183
        bison_args->num_designs = bison_args->design_idx + 1;
40✔
184
        tmp = (design_t *) realloc (bison_args->designs, (bison_args->num_designs) * sizeof(design_t));
40✔
185
        if (!tmp) {
40!
186
            perror (PROJECT);
×
187
            YYABORT;
×
188
        }
189
        bison_args->designs = tmp;
40✔
190
    }
191

192
parent_def: YPARENT FILENAME
193
    {
194
        invoke_action(action_parent_config(bison_args, $2));
15!
195
    }
196

197
config_file: config_file design_or_error | design_or_error | config_file parent_def | parent_def ;
198

199

200
design_or_error: design | error
201
    {
202
        /* reset alias list, as those are collected even when speedmode is on */
203
        log_debug(__FILE__, PARSER, " Parser: Discarding token [skipping=%s, speeding=%s]\n",
1,663,248✔
204
                bison_args->skipping ? "true" : "false", bison_args->speeding ? "true" : "false");
1,663,248✔
205
        if (curdes.aliases[0] != NULL) {
831,624✔
206
            BFREE(curdes.aliases);
254!
207
            curdes.aliases = (char **) calloc(1, sizeof(char *));
254✔
208
        }
209
        if (!bison_args->speeding && !bison_args->skipping) {
831,624✔
210
            recover(bison_args);
9✔
211
            yyerror(bison_args, "skipping to next design");
9✔
212
            bison_args->skipping = 1;
9✔
213
        }
214
    }
215

216

217
alias: ASCII_ID
218
    {
219
        invoke_action(action_add_alias(bison_args, $1));
587!
220
    }
221

222
alias_list: alias | alias_list ',' alias;
223

224
design_id: ASCII_ID | ASCII_ID ',' alias_list
225

226
| BXWORD
227
    {
228
        yyerror(bison_args, "box design name must consist of printable standard ASCII characters.");
1✔
229
        YYERROR;
1✔
230
    }
231
;
232

233
design: YBOX design_id
234
    {
235
        invoke_action(action_start_parsing_design(bison_args, $<ascii>2));
9,056!
236
    }
237
layout YEND ASCII_ID
238
    {
239
        invoke_action(action_add_design(bison_args, $<ascii>2, $6));
862!
240
    }
241
;
242

243

244
layout: layout entry | layout block | entry | block ;
245

246

247
tag_entry: STRING
248
    {
249
        tag_record(bison_args, $1);    /* discard return code (we print warnings, but tolerate the problem) */
2,197✔
250
    }
251

252
tag_list: tag_entry | tag_list ',' tag_entry;
253

254

255
entry: KEYWORD STRING
256
    {
257
        invoke_action(action_record_keyword(bison_args, $1, $2));
1,477!
258
    }
259

260
| YPARENT FILENAME
261
    {
262
        /*
263
         * Called when PARENT appears as a key inside a box design. That's a user mistake, but not an error.
264
         */
265
        bxstr_t *filename = $2;
×
266
        if (filename->memory[0] != filename->memory[filename->num_chars - 1] || uc_is_alnum(filename->memory[0])) {
×
267
            yyerror(bison_args, "string expected");
×
268
            YYERROR;
×
269
        }
270
        else if (is_debug_logging(PARSER)) {
×
271
            char *out_filename = bxs_to_output(filename);
×
272
            log_debug(__FILE__, PARSER, " Parser: Discarding entry [%s = %s].\n", "parent", out_filename);
×
273
            BFREE(out_filename);
×
274
        }
275
    }
276

277
| YCHGDEL YDELIMSPEC
278
    {
279
        /* string delimiters were changed - this is a lexer thing. ignore here. */
280
    }
281

282
| YTAGS '(' tag_list ')' | YTAGS tag_entry
283

284
| BXWORD STRING | ASCII_ID STRING
285
    {
286
        if (is_debug_logging(PARSER)) {
5!
287
            char *out_string = bxs_to_output($2);
×
288
            log_debug(__FILE__, PARSER, " Parser: Discarding entry [%s = %s].\n", $1, out_string);
×
289
            BFREE(out_string);
×
290
        }
291
    }
292
;
293

294

295
block: YSAMPLE STRING YENDSAMPLE
296
    {
297
        invoke_action(action_sample_block(bison_args, $2));
865!
298
    }
299

300
| YSHAPES  '{' slist  '}'
301
    {
302
        invoke_action(action_finalize_shapes(bison_args));
864!
303
    }
304

305
| YELASTIC '(' elist ')'
306
    {
307
        ++(bison_args->num_mandatory);
861✔
308
        if (++(bison_args->time_for_se_check) > 1) {
861!
309
            if (perform_se_check(bison_args) != 0) {
861!
310
                YYERROR;
×
311
            }
312
        }
313
    }
314

315
| YREPLACE rflag STRING YWITH STRING
316
    {
317
        invoke_action(action_add_regex_rule(bison_args, "rep", &curdes.reprules, &curdes.num_reprules, $3, $5, $2));
215!
318
    }
319

320
| YREVERSE rflag STRING YTO STRING
321
    {
322
        invoke_action(action_add_regex_rule(bison_args, "rev", &curdes.revrules, &curdes.num_revrules, $3, $5, $2));
263!
323
    }
324

325
| YPADDING '{' wlist '}'
326
    {
327
        log_debug(__FILE__, PARSER, "Padding set to (l%d o%d r%d u%d)\n",
741✔
328
                curdes.padding[BLEF], curdes.padding[BTOP], curdes.padding[BRIG], curdes.padding[BBOT]);
741✔
329
    }
330
;
331

332

333
rflag: YRXPFLAG
334
    {
335
        $$ = $1;
×
336
    }
337
| %empty
338
    {
339
        $$ = 'g';
478✔
340
    }
341
;
342

343

344
elist: elist ',' elist_entry | elist_entry;
345

346

347
elist_entry: SHAPE
348
    {
349
        log_debug(__FILE__, PARSER, "Marked \'%s\' shape as elastic\n", shape_name[(int) $1]);
3,057✔
350
        curdes.shape[$1].elastic = 1;
3,057✔
351
    }
352
;
353

354

355
slist: slist slist_entry | slist_entry;
356

357

358
slist_entry: SHAPE shape_def
359
    {
360
        log_debug(__FILE__, PARSER, "Adding shape spec for \'%s\' (width %d height %d)\n",
6,644✔
361
                shape_name[$1], (int) $2.width, (int) $2.height);
6,644✔
362

363
        if (isempty (curdes.shape + $1)) {
6,644!
364
            curdes.shape[$1] = $2;
6,644✔
365
            if (!isdeepempty(&($2))) {
6,644✔
366
                ++(bison_args->num_shapespec);
6,478✔
367
            }
368
        }
369
        else {
370
            yyerror(bison_args, "duplicate specification for %s shape", shape_name[$1]);
×
371
            YYERROR;
×
372
        }
373
    }
374
;
375

376

377
shape_def: '(' shape_lines ')'
378
    {
379
        if ($2.width == 0 || $2.height == 0) {
6,626!
380
            yyerror(bison_args, "minimum shape dimension is 1x1 - clearing");
×
381
            freeshape (&($2));
×
382
        }
383
        $$ = $2;
6,626✔
384
    }
385

386
| '(' ')'
387
    {
388
        $$ = SENTRY_INITIALIZER;
18✔
389
    }
390
;
391

392

393
shape_lines: shape_lines ',' STRING
394
    {
395
        sentry_t rval = $1;
10,326✔
396
        invoke_action(action_add_shape_line(bison_args, &rval, $3));
10,326!
397
        $$ = rval;
10,326✔
398
    }
399

400
| STRING
401
    {
402
        sentry_t rval;
403
        invoke_action(action_first_shape_line(bison_args, $1, &rval));
6,626!
404
        $$ = rval;
6,626✔
405
    }
406
;
407

408

409
wlist: wlist wlist_entry | wlist_entry;
410

411
wlist_entry: ASCII_ID YNUMBER
412
    {
413
        invoke_action(action_padding_entry(bison_args, $1, $2));
931!
414
    }
415
;
416

417

418
%%
419

420

421
/* vim: set sw=4 cindent: */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc