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

ascii-boxes / boxes / 7314850954

24 Dec 2023 01:12PM UTC coverage: 88.826% (+2.5%) from 86.336%
7314850954

push

github

tsjensen
Use -ggdb3 option for more detailed debug info

2869 of 3408 branches covered (0.0%)

Branch coverage included in aggregate %.

4619 of 5022 relevant lines covered (91.98%)

202175.9 hits per line

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

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

16
/*
17
 * Processing of command line options.
18
 */
19

20
#include "config.h"
21
#include <errno.h>
22
#include <getopt.h>
23
#include <stdio.h>
24
#include <string.h>
25
#include <strings.h>
26
#include <uniconv.h>
27
#include <unistd.h>
28

29
#ifdef __MINGW32__
30
#include <fcntl.h>  /* _O_BINARY */
31
#include <io.h>     /* _setmode() */
32
#endif
33

34
#include "boxes.h"
35
#include "discovery.h"
36
#include "query.h"
37
#include "tools.h"
38
#include "cmdline.h"
39

40

41
extern char *optarg;   /* for getopt() */
42
extern int optind;     /* for getopt() */
43

44

45
/* default tab stop distance (part of -t) */
46
#define DEF_TABSTOP 8
47

48
/* max. allowed tab stop distance */
49
#define MAX_TABSTOP 16
50

51

52
/* System default line terminator.
53
 * Used only for display in usage info. The real default is always "\n", with stdout in text mode. */
54
#ifdef __MINGW32__
55
    #define EOL_DEFAULT "\r\n"
56
#else
57
    #define EOL_DEFAULT "\n"
58
#endif
59

60

61

62
/**
63
 * Print abbreviated usage information on stream `st`.
64
 * @param st the stream to print to
65
 */
66
static void usage_short(FILE *st)
6✔
67
{
68
    bx_fprintf(st, "Usage: %s [options] [infile [outfile]]\n", PROJECT);
6✔
69
    bx_fprintf(st, "Try `%s -h' for more information.\n", PROJECT);
6✔
70
}
6✔
71

72

73

74
/**
75
 * Print usage information on stream `st`, including a header text.
76
 * @param st the stream to print to
77
 */
78
void usage_long(FILE *st)
2✔
79
{
80
    bxstr_t *config_file = discover_config_file(0);
2✔
81

82
    fprintf(st, "%s - draws any kind of box around your text (or removes it)\n", PROJECT);
2✔
83
    fprintf(st, "        Website: https://boxes.thomasjensen.com/\n");
2✔
84
    fprintf(st, "Usage:  %s [options] [infile [outfile]]\n", PROJECT);
2✔
85
    fprintf(st, "  -a, --align <fmt>     Alignment/positioning of text inside box [default: hlvt]\n");
2✔
86
    fprintf(st, "  -c, --create <str>    Use single shape box design where str is the W shape\n");
2✔
87
    fprintf(st, "      --color           Force output of ANSI sequences if present\n");
2✔
88
    fprintf(st, "      --no-color        Force monochrome output (no ANSI sequences)\n");
2✔
89
    fprintf(st, "  -d, --design <name>   Box design [default: first one in file]\n");
2✔
90
    fprintf(st, "  -e, --eol <eol>       Override line break type (experimental) [default: %s]\n",
2✔
91
                                         strcmp(EOL_DEFAULT, "\r\n") == 0 ? "CRLF" : "LF");
92
    fprintf(st, "  -f, --config <file>   Configuration file [default: %s]\n",
4!
93
                                         config_file != NULL ? bxs_to_output(config_file) : "none");
2!
94
    fprintf(st, "  -h, --help            Print usage information\n");
2✔
95
    fprintf(st, "  -i, --indent <mode>   Indentation mode [default: box]\n");
2✔
96
    fprintf(st, "  -k <bool>             Leading/trailing blank line retention on removal\n");
2✔
97
    fprintf(st, "      --kill-blank      Kill leading/trailing blank lines on removal (like -k true)\n");
2✔
98
    fprintf(st, "      --no-kill-blank   Retain leading/trailing blank lines on removal (like -k false)\n");
2✔
99
    fprintf(st, "  -l, --list            List available box designs w/ samples\n");
2✔
100
    fprintf(st, "  -m, --mend            Mend (repair) box\n");
2✔
101
    fprintf(st, "  -n, --encoding <enc>  Character encoding of input and output [default: %s]\n", locale_charset());
2✔
102
    fprintf(st, "  -p, --padding <fmt>   Padding [default: none]\n");
2✔
103
    fprintf(st, "  -q, --tag-query <qry> Query the list of designs by tag\n"); /* with "(undoc)" as query, trigger undocumented webui stuff instead */
2✔
104
    fprintf(st, "  -r, --remove          Remove box\n");
2✔
105
    fprintf(st, "  -s, --size <wxh>      Box size (width w and/or height h)\n");
2✔
106
    fprintf(st, "  -t, --tabs <str>      Tab stop distance and expansion [default: %de]\n", DEF_TABSTOP);
2✔
107
    fprintf(st, "  -v, --version         Print version information\n");
2✔
108

109
    bxs_free(config_file);
2✔
110
}
2✔
111

112

113

114
static opt_t *create_new_opt()
866✔
115
{
116
    opt_t *result = (opt_t *) calloc(1, sizeof(opt_t));
866✔
117
    if (result != NULL) {
866✔
118
        /* all values initialized with 0 or NULL */
119
        result->color = color_from_terminal;
866✔
120
        result->tabstop = DEF_TABSTOP;
866✔
121
        result->eol = "\n";      /* we must default to "\n" instead of EOL_DEFAULT as long as stdout is in text mode */
866✔
122
        result->tabexp = 'e';
866✔
123
        result->killblank = -1;
866✔
124
        for (int i = 0; i < NUM_SIDES; ++i) {
4,330✔
125
            result->padding[i] = -1;
3,464✔
126
        }
1,732✔
127
    }
433✔
128
    else {
129
        perror(PROJECT);
×
130
    }
131
    return result;
866✔
132
}
133

134

135

136
/**
137
 * Alignment/positioning of text inside box.
138
 * @param result the options struct we are building
139
 * @param optarg the argument to `-a` on the command line
140
 * @returns 0 on success, anything else on error
141
 */
142
static int alignment(opt_t *result, char *optarg)
140✔
143
{
144
    int errfl = 1;
140✔
145
    char *p = optarg;
140✔
146

147
    while (*p) {
404✔
148
        errfl = 0;
274✔
149
        if (p[1] == '\0' && !strchr("lLcCrR", *p)) {
274✔
150
            errfl = 1;
2✔
151
            break;
2✔
152
        }
153

154
        switch (*p) {
272✔
155
            case 'h': case 'H':
41✔
156
                switch (p[1]) {
82✔
157
                    case 'c': case 'C': result->halign = 'c'; break;
26✔
158
                    case 'l': case 'L': result->halign = 'l'; break;
24✔
159
                    case 'r': case 'R': result->halign = 'r'; break;
30✔
160
                    default:            errfl = 1;            break;
2✔
161
                }
162
                ++p;
82✔
163
                break;
82✔
164

165
            case 'v': case 'V':
43✔
166
                switch (p[1]) {
86✔
167
                    case 'c': case 'C': result->valign = 'c'; break;
32✔
168
                    case 't': case 'T': result->valign = 't'; break;
24✔
169
                    case 'b': case 'B': result->valign = 'b'; break;
28✔
170
                    default:            errfl = 1;            break;
2✔
171
                }
172
                ++p;
86✔
173
                break;
86✔
174

175
            case 'j': case 'J':
30✔
176
                switch (p[1]) {
60✔
177
                    case 'l': case 'L': result->justify = 'l'; break;
18✔
178
                    case 'c': case 'C': result->justify = 'c'; break;
18✔
179
                    case 'r': case 'R': result->justify = 'r'; break;
22✔
180
                    default:            errfl = 1;             break;
2✔
181
                }
182
                ++p;
60✔
183
                break;
60✔
184

185
            case 'l': case 'L':
4✔
186
                result->justify = 'l';
8✔
187
                result->halign = 'l';
8✔
188
                result->valign = 'c';
8✔
189
                break;
8✔
190

191
            case 'r': case 'R':
6✔
192
                result->justify = 'r';
12✔
193
                result->halign = 'r';
12✔
194
                result->valign = 'c';
12✔
195
                break;
12✔
196

197
            case 'c': case 'C':
11✔
198
                result->justify = 'c';
22✔
199
                result->halign = 'c';
22✔
200
                result->valign = 'c';
22✔
201
                break;
22✔
202

203
            default:
1✔
204
                errfl = 1;
2✔
205
                break;
2✔
206
        }
207

208
        if (errfl) {
272✔
209
            break;
8✔
210
        } else {
211
            ++p;
264✔
212
        }
213
    }
214

215
    if (errfl) {
140✔
216
        bx_fprintf(stderr, "%s: Illegal text format -- %s\n", PROJECT, optarg);
12✔
217
        return 1;
12✔
218
    }
219
    return 0;
128✔
220
}
70✔
221

222

223

224
/**
225
 * Command line design definition.
226
 * @param result the options struct we are building
227
 * @param optarg the argument to `-c` on the command line
228
 * @returns 0 on success, anything else on error
229
 */
230
static int command_line_design(opt_t *result, char *optarg)
10✔
231
{
232
    if (strlen(optarg) == 0) {
10✔
233
        bx_fprintf(stderr, "%s: empty command line design definition\n", PROJECT);
2✔
234
        return 2;
2✔
235
    }
236
    result->cld = (char *) strdup(optarg);
8✔
237
    if (result->cld == NULL) {
8!
238
        perror(PROJECT);
×
239
        return 1;
×
240
    }
241
    result->design_choice_by_user = 1;
8✔
242
    return 0;
8✔
243
}
5✔
244

245

246

247
/**
248
 * Box design selection.
249
 * @param result the options struct we are building
250
 * @param optarg the argument to `-d` on the command line
251
 * @returns 0 on success, anything else on error
252
 */
253
static int design_choice(opt_t *result, char *optarg)
496✔
254
{
255
    BFREE (result->design);
496✔
256
    result->design = (design_t *) ((char *) strdup(optarg));
496✔
257
    if (result->design == NULL) {
496!
258
        perror(PROJECT);
×
259
        return 1;
×
260
    }
261
    result->design_choice_by_user = 1;
496✔
262
    return 0;
496✔
263
}
248✔
264

265

266

267
/**
268
 * EOL Override.
269
 * @param result the options struct we are building
270
 * @param optarg the argument to `-e` on the command line
271
 * @returns 0 on success, anything else on error
272
 */
273
static int eol_override(opt_t *result, char *optarg)
20✔
274
{
275
    result->eol_overridden = 1;
20✔
276
    if (strcasecmp(optarg, "CRLF") == 0) {
20✔
277
        result->eol = "\r\n";
8✔
278
    }
4✔
279
    else if (strcasecmp(optarg, "LF") == 0) {
12✔
280
        result->eol = "\n";
8✔
281
    }
4✔
282
    else if (strcasecmp(optarg, "CR") == 0) {
4✔
283
        result->eol = "\r";
2✔
284
    }
1✔
285
    else {
286
        bx_fprintf(stderr, "%s: invalid eol spec -- %s\n", PROJECT, optarg);
2✔
287
        return 1;
2✔
288
    }
289
    return 0;
18✔
290
}
10✔
291

292

293

294
/**
295
 * Indentation mode.
296
 * @param result the options struct we are building
297
 * @param optarg the argument to `-i` on the command line
298
 * @returns 0 on success, anything else on error
299
 */
300
static int indentation_mode(opt_t *result, char *optarg)
14✔
301
{
302
    size_t optlen = strlen(optarg);
14✔
303
    if (optlen <= 3 && !strncasecmp("box", optarg, optlen)) {
14✔
304
        result->indentmode = 'b';
4✔
305
    }
2✔
306
    else if (optlen <= 4 && !strncasecmp("text", optarg, optlen)) {
10✔
307
        result->indentmode = 't';
2✔
308
    }
1✔
309
    else if (optlen <= 4 && !strncasecmp("none", optarg, optlen)) {
8✔
310
        result->indentmode = 'n';
4✔
311
    }
2✔
312
    else {
313
        bx_fprintf(stderr, "%s: invalid indentation mode\n", PROJECT);
4✔
314
        return 1;
4✔
315
    }
316
    return 0;
10✔
317
}
7✔
318

319

320

321
/**
322
 * Kill blank lines or not [default: design-dependent].
323
 * @param result the options struct we are building
324
 * @param optarg the argument to `-k` on the command line
325
 * @returns 0 on success, anything else on error
326
 */
327
static int killblank(opt_t *result, char *optarg)
10✔
328
{
329
    if (result->killblank == -1) {
10✔
330
        if (strisyes(optarg)) {
8✔
331
            result->killblank = 1;
4✔
332
        }
2✔
333
        else if (strisno(optarg)) {
4✔
334
            result->killblank = 0;
2✔
335
        }
1✔
336
        else {
337
            bx_fprintf(stderr, "%s: -k: invalid parameter\n", PROJECT);
2✔
338
            return 1;
2✔
339
        }
340
    }
3✔
341
    return 0;
8✔
342
}
5✔
343

344

345

346
/**
347
 * Padding. Format is `([ahvtrbl]n)+`.
348
 * @param result the options struct we are building
349
 * @param optarg the argument to `-p` on the command line
350
 * @returns 0 on success, anything else on error
351
 */
352
static int padding(opt_t *result, char *optarg)
34✔
353
{
354
    int errfl = 1;
34✔
355
    char *p = optarg;
34✔
356

357
    while (*p) {
69✔
358
        errfl = 0;
43✔
359
        if (p[1] == '\0') {
43✔
360
            errfl = 1;
3✔
361
            break;
3✔
362
        }
363
        char c = *p;
40✔
364
        errno = 0;
40✔
365
        int size = (int) strtol(p + 1, &p, 10);
40✔
366
        if (errno || size < 0) {
40✔
367
            errfl = 1;
4✔
368
            break;
4✔
369
        }
370
        switch (c) {
36✔
371
            case 'a': case 'A':
2✔
372
                result->padding[BTOP] = size;
4✔
373
                result->padding[BBOT] = size;
4✔
374
                result->padding[BLEF] = size;
4✔
375
                result->padding[BRIG] = size;
4✔
376
                break;
4✔
377
            case 'h': case 'H':
4✔
378
                result->padding[BLEF] = size;
8✔
379
                result->padding[BRIG] = size;
8✔
380
                break;
8✔
381
            case 'v': case 'V':
1✔
382
                result->padding[BTOP] = size;
2✔
383
                result->padding[BBOT] = size;
2✔
384
                break;
2✔
385
            case 't': case 'T':
1✔
386
                result->padding[BTOP] = size;
2✔
387
                break;
2✔
388
            case 'l': case 'L':
6✔
389
                result->padding[BLEF] = size;
12✔
390
                break;
12✔
391
            case 'b': case 'B':
1✔
392
                result->padding[BBOT] = size;
2✔
393
                break;
2✔
394
            case 'r': case 'R':
3✔
395
                result->padding[BRIG] = size;
5✔
396
                break;
5✔
397
            default:
1✔
398
                errfl = 1;
1✔
399
                break;
1✔
400
        }
401
        if (errfl) {
36✔
402
            break;
1✔
403
        }
404
    }
405
    if (errfl) {
34✔
406
        bx_fprintf(stderr, "%s: invalid padding specification - %s\n", PROJECT, optarg);
10✔
407
        return 1;
10✔
408
    }
409
    return 0;
24✔
410
}
17✔
411

412

413

414
/**
415
 * Parse the tag query specified with `-q`.
416
 * @param result the options struct we are building
417
 * @param optarg the argument to `-q` on the command line
418
 * @returns 0 on success, anything else on error
419
 */
420
static int query(opt_t *result, char *optarg)
26✔
421
{
422
    char **query = parse_query(optarg);
26✔
423
    result->query = query;
26✔
424
    return query != NULL ? 0 : 1;
26✔
425
}
426

427

428

429
/**
430
 * Specify desired box target size.
431
 * @param result the options struct we are building
432
 * @param optarg the argument to `-s` on the command line
433
 * @returns 0 on success, anything else on error
434
 */
435
static int size_of_box(opt_t *result, char *optarg)
140✔
436
{
437
    char *p = strchr(optarg, 'x');
140✔
438
    if (!p) {
140✔
439
        p = strchr(optarg, 'X');
6✔
440
    }
3✔
441
    if (p) {
140✔
442
        *p = '\0';
134✔
443
    }
67✔
444
    errno = 0;
140✔
445
    if (optarg != p) {
140✔
446
        result->reqwidth = strtol(optarg, NULL, 10);
136✔
447
    }
68✔
448
    if (p) {
140✔
449
        result->reqheight = strtol(p + 1, NULL, 10);
134✔
450
        *p = 'x';
134✔
451
    }
67✔
452
    if (errno || (result->reqwidth == 0 && result->reqheight == 0) || result->reqwidth < 0 || result->reqheight < 0) {
140!
453
        bx_fprintf(stderr, "%s: invalid box size specification -- %s\n", PROJECT, optarg);
4✔
454
        return 1;
4✔
455
    }
456
    return 0;
136✔
457
}
70✔
458

459

460

461
/**
462
 * Tab handling. Format is `n[eku]`.
463
 * @param result the options struct we are building
464
 * @param optarg the argument to `-t` on the command line
465
 * @returns 0 on success, anything else on error
466
 */
467
static int tab_handling(opt_t *result, char *optarg)
34✔
468
{
469
    char *p;
470
    int width = (int) strtol(optarg, &p, 10);
34✔
471
    if (width < 1 || width > MAX_TABSTOP) {
34✔
472
        bx_fprintf(stderr, "%s: invalid tab stop distance -- %d\n", PROJECT, width);
4✔
473
        return 1;
4✔
474
    }
475
    result->tabstop = width;
30✔
476

477
    int errfl = 0;
30✔
478
    if (*p != '\0') {
30✔
479
        if (p[1] != '\0') {
24✔
480
            errfl = 1;
2✔
481
        }
1✔
482
        else {
483
            switch (*p) {
22✔
484
                case 'e': case 'E':
1✔
485
                    result->tabexp = 'e';
2✔
486
                    break;
2✔
487
                case 'k': case 'K':
3✔
488
                    result->tabexp = 'k';
6✔
489
                    break;
6✔
490
                case 'u': case 'U':
6✔
491
                    result->tabexp = 'u';
12✔
492
                    break;
12✔
493
                default:
1✔
494
                    errfl = 1;
2✔
495
                    break;
2✔
496
            }
497
        }
498
    }
12✔
499
    if (errfl) {
30✔
500
        bx_fprintf(stderr, "%s: invalid tab handling specification - %s\n", PROJECT, optarg);
4✔
501
        return 1;
4✔
502
    }
503
    return 0;
26✔
504
}
17✔
505

506

507

508
/**
509
 * Set *stdout* to binary mode, so that we can control the line terminator. This function only ever does anything on
510
 * Windows, because on Linux, we already do have control over line terminators.
511
 * @param result the options struct we are building
512
 * @return the *stdout* stream, reconfigured to binary if necessary
513
 */
514
static FILE *get_stdout_configured(opt_t *result)
798✔
515
{
516
    if (result->eol_overridden) {
798✔
517
        #ifdef __MINGW32__
518
            int rc = _setmode(fileno(stdout), _O_BINARY);
519
            if (rc == -1) {
520
                perror(PROJECT);
521
            }
522
        #endif
523
    }
9✔
524
    return stdout;
798✔
525
}
526

527

528

529
/**
530
 * Input and Output Files. After any command line options, an input file and an output file may be specified (in that
531
 * order). "-" may be substituted for standard input or output. A third file name would be invalid.
532
 * @param result the options struct we are building
533
 * @param argv the original command line options as specified
534
 * @param optind the index of the next element to be processed in `argv`
535
 * @returns 0 on success, anything else on error
536
 */
537
static int input_output_files(opt_t *result, char *argv[], int optind)
804✔
538
{
539
    if (argv[optind] == NULL) {                              /* neither infile nor outfile given */
804✔
540
        result->infile = stdin;
506✔
541
        result->outfile = get_stdout_configured(result);
506✔
542
    }
253✔
543

544
    else if (argv[optind + 1] && argv[optind + 2]) {         /* illegal third file */
298✔
545
        bx_fprintf(stderr, "%s: illegal parameter -- %s\n", PROJECT, argv[optind + 2]);
2✔
546
        usage_short(stderr);
2✔
547
        return 1;
2✔
548
    }
549

550
    else {
551
        if (strcmp(argv[optind], "-") == 0) {
296✔
552
            result->infile = stdin;                          /* use stdin for input */
4✔
553
        }
2✔
554
        else {
555
            result->infile = fopen(argv[optind], "r");
292✔
556
            if (result->infile == NULL) {
292✔
557
                bx_fprintf(stderr, "%s: Can\'t open input file -- %s\n", PROJECT, argv[optind]);
2✔
558
                return 9;                                    /* can't read infile */
2✔
559
            }
560
        }
561

562
        if (argv[optind + 1] == NULL) {
294✔
563
            result->outfile = get_stdout_configured(result); /* no outfile given */
290✔
564
        }
145✔
565
        else if (strcmp(argv[optind + 1], "-") == 0) {
4✔
566
            result->outfile = get_stdout_configured(result); /* use stdout for output */
2✔
567
        }
1✔
568
        else {
569
            result->outfile = fopen(argv[optind + 1], "wb");
2✔
570
            if (result->outfile == NULL) {
2✔
571
                perror(PROJECT);
×
572
                if (result->infile != stdin) {
×
573
                    fclose(result->infile);
×
574
                }
575
                return 10;
×
576
            }
577
        }
578
    }
579
    return 0;
800✔
580
}
402✔
581

582

583

584
static void print_debug_info(opt_t *result)
800✔
585
{
586
    if (result != NULL) {
400!
587
        #if defined(DEBUG)
588
            fprintf (stderr, "Command line option settings (excerpt):\n");
589
            fprintf (stderr, "- Alignment (-a): horiz %c, vert %c\n",
590
                    result->halign ? result->halign : '?', result->valign ? result->valign : '?');
591
            fprintf (stderr, "- Line justification (-a): \'%c\'\n", result->justify ? result->justify : '?');
592
            fprintf (stderr, "- Design Definition W shape (-c): %s\n", result->cld ? result->cld : "n/a");
593
            fprintf (stderr, "- Color mode: %d\n", result->color);
594
            fprintf (stderr, "- Line terminator used (-e): %s\n",
595
                strcmp(result->eol, "\r\n") == 0 ? "CRLF" : (strcmp(result->eol, "\r") == 0 ? "CR" : "LF"));
596
            fprintf (stderr, "- Explicit config file (-f): %s\n", result->f ? result->f : "no");
597
            fprintf (stderr, "- Indentmode (-i): \'%c\'\n", result->indentmode ? result->indentmode : '?');
598
            fprintf (stderr, "- Kill blank lines (-k): %d\n", result->killblank);
599
            fprintf (stderr, "- Mend box (-m): %d\n", result->mend);
600
            fprintf (stderr, "- Padding (-p): l:%d t:%d r:%d b:%d\n",
601
                    result->padding[BLEF], result->padding[BTOP], result->padding[BRIG], result->padding[BBOT]);
602
            fprintf (stderr, "- Tag Query / Special handling for Web UI (-q): ");
603
            if (result->query != NULL) {
604
                for (size_t qidx = 0; result->query[qidx] != NULL; ++qidx) {
605
                    fprintf(stderr, "%s%s", qidx > 0 ? ", " : "", result->query[qidx]);
606
                }
607
            } else {
608
                fprintf (stderr, "(none)");
609
            }
610
            fprintf (stderr, "\n");
611
            fprintf (stderr, "- Remove box (-r): %d\n", result->r);
612
            fprintf (stderr, "- Requested box size (-s): %ldx%ld\n", result->reqwidth, result->reqheight);
613
            fprintf (stderr, "- Tabstop distance (-t): %d\n", result->tabstop);
614
            fprintf (stderr, "- Tab handling (-t): \'%c\'\n", result->tabexp);
615
        #endif
616
    }
400✔
617
}
800✔
618

619

620

621
opt_t *process_commandline(int argc, char *argv[])
866✔
622
{
623
    #ifdef DEBUG
624
        fprintf(stderr, "argc = %d\n", argc);
625
        fprintf(stderr, "argv = [");
626
        for(int i=0; i<=argc; i++) {
627
            fprintf(stderr, "%s%s", argv[i], i < argc ? ", " : "");
628
        }
629
        fprintf(stderr, "]\n");
630
    #endif
631

632
    opt_t *result = create_new_opt();
866✔
633

634
    /* Intercept '-?' case first, as it is not supported by getopt_long() */
635
    if (argc >= 2 && argv[1] != NULL && strcmp(argv[1], "-?") == 0) {
866!
636
        result->help = 1;
×
637
        return result;
×
638
    }
639

640
    optind = 1;   /* ensure that getopt() will process all arguments, even in unit test situations */
866✔
641
    int option_index = 0;
866✔
642
    const struct option long_options[] = {
866✔
643
        { "align",         required_argument, NULL, 'a' },
644
        { "create",        required_argument, NULL, 'c' },
645
        { "color",         no_argument,       NULL, OPT_COLOR },
646
        { "no-color",      no_argument,       NULL, OPT_NO_COLOR },
647
        { "design",        required_argument, NULL, 'd' },
648
        { "eol",           required_argument, NULL, 'e' },
649
        { "config",        required_argument, NULL, 'f' },
650
        { "help",          no_argument,       NULL, 'h' },
651
        { "indent",        required_argument, NULL, 'i' },
652
        { "kill-blank",    no_argument,       NULL, OPT_KILLBLANK },
653
        { "no-kill-blank", no_argument,       NULL, OPT_NO_KILLBLANK },
654
        { "list",          no_argument,       NULL, 'l' },
655
        { "mend",          no_argument,       NULL, 'm' },
656
        { "encoding",      required_argument, NULL, 'n' },
657
        { "padding",       required_argument, NULL, 'p' },
658
        { "tag-query",     required_argument, NULL, 'q' },
659
        { "remove",        no_argument,       NULL, 'r' },
660
        { "size",          required_argument, NULL, 's' },
661
        { "tabs",          required_argument, NULL, 't' },
662
        { "version",       no_argument,       NULL, 'v' },
663
        { NULL,            0,                 NULL,  0  }
664
    };
665
    const char *short_options = "a:c:d:e:f:hi:k:lmn:p:q:rs:t:v";
866✔
666

667
    int oc;   /* option character */
668
    do {
433✔
669
        oc = getopt_long(argc, argv, short_options, long_options, &option_index);
2,684✔
670

671
        switch (oc) {
2,684✔
672

673
            case 'a':
70✔
674
                if (alignment(result, optarg) != 0) {
140✔
675
                    BFREE(result);
12!
676
                    return NULL;
12✔
677
                }
678
                break;
128✔
679

680
            case 'c':
5✔
681
                if (command_line_design(result, optarg) != 0) {
10✔
682
                    BFREE(result);
2!
683
                    return NULL;
2✔
684
                }
685
                break;
8✔
686
            
687
            case OPT_COLOR:
1✔
688
                result->color = force_ansi_color;
2✔
689
                break;
2✔
690

691
            case OPT_NO_COLOR:
692
                result->color = force_monochrome;
×
693
                break;
×
694

695
            case 'd':
248✔
696
                if (design_choice(result, optarg) != 0) {
496✔
697
                    BFREE(result);
×
698
                    return NULL;
×
699
                }
700
                break;
496✔
701

702
            case 'e':
10✔
703
                if (eol_override(result, optarg) != 0) {
20✔
704
                    BFREE(result);
2!
705
                    return NULL;
2✔
706
                }
707
                break;
18✔
708

709
            case 'f':
269✔
710
                result->f = strdup(optarg);   /* input file */
538✔
711
                break;
538✔
712

713
            case 'h':
2✔
714
                result->help = 1;
4✔
715
                return result;
4✔
716

717
            case 'i':
7✔
718
                if (indentation_mode(result, optarg) != 0) {
14✔
719
                    BFREE(result);
4!
720
                    return NULL;
4✔
721
                }
722
                break;
10✔
723

724
            case 'k':
5✔
725
                if (killblank(result, optarg) != 0) {
10✔
726
                    BFREE(result);
2!
727
                    return NULL;
2✔
728
                }
729
                break;
8✔
730
            
731
            case OPT_KILLBLANK:
2✔
732
                if (result->killblank == -1) {
4✔
733
                    result->killblank = 1;
4✔
734
                }
2✔
735
                break;
4✔
736

737
            case OPT_NO_KILLBLANK:
1✔
738
                if (result->killblank == -1) {
2✔
739
                    result->killblank = 0;
2✔
740
                }
1✔
741
                break;
2✔
742

743
            case 'l':
25✔
744
                result->l = 1;   /* list available box styles */
50✔
745
                break;
50✔
746

747
            case 'm':
73✔
748
                result->mend = 2;   /*  Mend box: remove, then redraw */
146✔
749
                result->r = 1;
146✔
750
                result->killblank = 0;
146✔
751
                break;
146✔
752

753
            case 'n':
12✔
754
                result->encoding = strdup(optarg);   /* character encoding */
24✔
755
                if (result->encoding == NULL) {
24✔
756
                    perror(PROJECT);
×
757
                    BFREE(result);
×
758
                    return NULL;
×
759
                }
760
                break;
24✔
761

762
            case 'p':
17✔
763
                if (padding(result, optarg) != 0) {
34✔
764
                    BFREE(result);
10!
765
                    return NULL;
10✔
766
                }
767
                break;
24✔
768

769
            case 'q':
13✔
770
                if (query(result, optarg) != 0) {
26✔
771
                    BFREE(result);
8!
772
                    return NULL;
8✔
773
                }
774
                break;
18✔
775

776
            case 'r':
90✔
777
                result->r = 1;   /* remove box */
180✔
778
                break;
180✔
779

780
            case 's':
70✔
781
                if (size_of_box(result, optarg) != 0) {
140✔
782
                    BFREE(result);
4!
783
                    return NULL;
4✔
784
                }
785
                break;
136✔
786

787
            case 't':
17✔
788
                if (tab_handling(result, optarg) != 0) {
34✔
789
                    BFREE(result);
8!
790
                    return NULL;
8✔
791
                }
792
                break;
26✔
793

794
            case 'v':
1✔
795
                result->version_requested = 1;   /* print version number */
2✔
796
                return result;
2✔
797

798
            case ':':
2✔
799
            case '?':
800
                /* Missing argument or illegal option - do nothing else */
801
                usage_short(stderr);
4✔
802
                BFREE(result);
4✔
803
                return NULL;
4✔
804

805
            case EOF:
402✔
806
                /* End of list, do nothing more */
807
                break;
804✔
808

809
            default:
810
                bx_fprintf(stderr, "%s: internal error\n", PROJECT);
×
811
                BFREE(result);
×
812
                return NULL;
×
813
        }
814
    } while (oc != EOF);
2,622✔
815

816
    if (input_output_files(result, argv, optind) != 0) {
804✔
817
        BFREE(result);
4✔
818
        return NULL;
4✔
819
    }
820

821
    print_debug_info(result);
800✔
822
    return result;
800✔
823
}
433✔
824

825

826
/*EOF*/                                                  /* vim: set sw=4: */
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