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

ascii-boxes / boxes / 6816635106

09 Nov 2023 07:39PM UTC coverage: 83.954% (-0.2%) from 84.133%
6816635106

push

github

tsjensen
free

2443 of 3198 branches covered (0.0%)

Branch coverage included in aggregate %.

11 of 14 new or added lines in 1 file covered. (78.57%)

23 existing lines in 2 files now uncovered.

3820 of 4262 relevant lines covered (89.63%)

13341.38 hits per line

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

90.51
/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)
3✔
67
{
68
    bx_fprintf(st, "Usage: %s [options] [infile [outfile]]\n", PROJECT);
3✔
69
    bx_fprintf(st, "Try `%s -h' for more information.\n", PROJECT);
3✔
70
}
3✔
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)
1✔
79
{
80
    bxstr_t *config_file = discover_config_file(0);
1✔
81

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

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

112

113

114
static opt_t *create_new_opt()
215✔
115
{
116
    opt_t *result = (opt_t *) calloc(1, sizeof(opt_t));
215✔
117
    if (result != NULL) {
215!
118
        /* all values initialized with 0 or NULL */
119
        result->color = color_from_terminal;
215✔
120
        result->tabstop = DEF_TABSTOP;
215✔
121
        result->eol = "\n";      /* we must default to "\n" instead of EOL_DEFAULT as long as stdout is in text mode */
215✔
122
        result->tabexp = 'e';
215✔
123
        result->killblank = -1;
215✔
124
        for (int i = 0; i < NUM_SIDES; ++i) {
1,075✔
125
            result->padding[i] = -1;
860✔
126
        }
127
    }
128
    else {
129
        perror(PROJECT);
×
130
    }
131
    return result;
215✔
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)
70✔
143
{
144
    int errfl = 1;
70✔
145
    char *p = optarg;
70✔
146

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

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

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

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

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

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

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

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

208
        if (errfl) {
136✔
209
            break;
4✔
210
        } else {
211
            ++p;
132✔
212
        }
213
    }
214

215
    if (errfl) {
70✔
216
        bx_fprintf(stderr, "%s: Illegal text format -- %s\n", PROJECT, optarg);
6✔
217
        return 1;
6✔
218
    }
219
    return 0;
64✔
220
}
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)
5✔
231
{
232
    if (strlen(optarg) == 0) {
5✔
233
        bx_fprintf(stderr, "%s: empty command line design definition\n", PROJECT);
1✔
234
        return 2;
1✔
235
    }
236
    result->cld = (char *) strdup(optarg);
4✔
237
    if (result->cld == NULL) {
4!
238
        perror(PROJECT);
×
239
        return 1;
×
240
    }
241
    result->design_choice_by_user = 1;
4✔
242
    return 0;
4✔
243
}
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)
32✔
254
{
255
    BFREE (result->design);
32!
256
    result->design = (design_t *) ((char *) strdup(optarg));
32✔
257
    if (result->design == NULL) {
32!
258
        perror(PROJECT);
×
259
        return 1;
×
260
    }
261
    result->design_choice_by_user = 1;
32✔
262
    return 0;
32✔
263
}
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)
10✔
274
{
275
    result->eol_overridden = 1;
10✔
276
    if (strcasecmp(optarg, "CRLF") == 0) {
10✔
277
        result->eol = "\r\n";
4✔
278
    }
279
    else if (strcasecmp(optarg, "LF") == 0) {
6✔
280
        result->eol = "\n";
4✔
281
    }
282
    else if (strcasecmp(optarg, "CR") == 0) {
2✔
283
        result->eol = "\r";
1✔
284
    }
285
    else {
286
        bx_fprintf(stderr, "%s: invalid eol spec -- %s\n", PROJECT, optarg);
1✔
287
        return 1;
1✔
288
    }
289
    return 0;
9✔
290
}
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)
6✔
301
{
302
    size_t optlen = strlen(optarg);
6✔
303
    if (optlen <= 3 && !strncasecmp("box", optarg, optlen)) {
6✔
304
        result->indentmode = 'b';
2✔
305
    }
306
    else if (optlen <= 4 && !strncasecmp("text", optarg, optlen)) {
4✔
307
        result->indentmode = 't';
1✔
308
    }
309
    else if (optlen <= 4 && !strncasecmp("none", optarg, optlen)) {
3✔
310
        result->indentmode = 'n';
1✔
311
    }
312
    else {
313
        bx_fprintf(stderr, "%s: invalid indentation mode\n", PROJECT);
2✔
314
        return 1;
2✔
315
    }
316
    return 0;
4✔
317
}
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)
5✔
328
{
329
    if (result->killblank == -1) {
5✔
330
        if (strisyes(optarg)) {
4✔
331
            result->killblank = 1;
2✔
332
        }
333
        else if (strisno(optarg)) {
2✔
334
            result->killblank = 0;
1✔
335
        }
336
        else {
337
            bx_fprintf(stderr, "%s: -k: invalid parameter\n", PROJECT);
1✔
338
            return 1;
1✔
339
        }
340
    }
341
    return 0;
4✔
342
}
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)
17✔
353
{
354
    int errfl = 1;
17✔
355
    char *p = optarg;
17✔
356

357
    while (*p) {
35✔
358
        errfl = 0;
22✔
359
        if (p[1] == '\0') {
22✔
360
            errfl = 1;
2✔
361
            break;
2✔
362
        }
363
        char c = *p;
20✔
364
        errno = 0;
20✔
365
        int size = (int) strtol(p + 1, &p, 10);
20✔
366
        if (errno || size < 0) {
20!
367
            errfl = 1;
1✔
368
            break;
1✔
369
        }
370
        switch (c) {
19✔
371
            case 'a': case 'A':
2✔
372
                result->padding[BTOP] = size;
2✔
373
                result->padding[BBOT] = size;
2✔
374
                result->padding[BLEF] = size;
2✔
375
                result->padding[BRIG] = size;
2✔
376
                break;
2✔
377
            case 'h': case 'H':
4✔
378
                result->padding[BLEF] = size;
4✔
379
                result->padding[BRIG] = size;
4✔
380
                break;
4✔
381
            case 'v': case 'V':
1✔
382
                result->padding[BTOP] = size;
1✔
383
                result->padding[BBOT] = size;
1✔
384
                break;
1✔
385
            case 't': case 'T':
1✔
386
                result->padding[BTOP] = size;
1✔
387
                break;
1✔
388
            case 'l': case 'L':
6✔
389
                result->padding[BLEF] = size;
6✔
390
                break;
6✔
391
            case 'b': case 'B':
1✔
392
                result->padding[BBOT] = size;
1✔
393
                break;
1✔
394
            case 'r': case 'R':
3✔
395
                result->padding[BRIG] = size;
3✔
396
                break;
3✔
397
            default:
1✔
398
                errfl = 1;
1✔
399
                break;
1✔
400
        }
401
        if (errfl) {
19✔
402
            break;
1✔
403
        }
404
    }
405
    if (errfl) {
17✔
406
        bx_fprintf(stderr, "%s: invalid padding specification - %s\n", PROJECT, optarg);
5✔
407
        return 1;
5✔
408
    }
409
    return 0;
12✔
410
}
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)
12✔
421
{
422
    char **query = parse_query(optarg);
12✔
423
    result->query = query;
12✔
424
    return query != NULL ? 0 : 1;
12✔
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)
70✔
436
{
437
    char *p = strchr(optarg, 'x');
70✔
438
    if (!p) {
70✔
439
        p = strchr(optarg, 'X');
3✔
440
    }
441
    if (p) {
70✔
442
        *p = '\0';
67✔
443
    }
444
    errno = 0;
70✔
445
    if (optarg != p) {
70✔
446
        result->reqwidth = strtol(optarg, NULL, 10);
68✔
447
    }
448
    if (p) {
70✔
449
        result->reqheight = strtol(p + 1, NULL, 10);
67✔
450
        *p = 'x';
67✔
451
    }
452
    if (errno || (result->reqwidth == 0 && result->reqheight == 0) || result->reqwidth < 0 || result->reqheight < 0) {
70!
453
        bx_fprintf(stderr, "%s: invalid box size specification -- %s\n", PROJECT, optarg);
2✔
454
        return 1;
2✔
455
    }
456
    return 0;
68✔
457
}
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)
17✔
468
{
469
    char *p;
470
    int width = (int) strtol(optarg, &p, 10);
17✔
471
    if (width < 1 || width > MAX_TABSTOP) {
17✔
472
        bx_fprintf(stderr, "%s: invalid tab stop distance -- %d\n", PROJECT, width);
2✔
473
        return 1;
2✔
474
    }
475
    result->tabstop = width;
15✔
476

477
    int errfl = 0;
15✔
478
    if (*p != '\0') {
15✔
479
        if (p[1] != '\0') {
12✔
480
            errfl = 1;
1✔
481
        }
482
        else {
483
            switch (*p) {
11✔
484
                case 'e': case 'E':
1✔
485
                    result->tabexp = 'e';
1✔
486
                    break;
1✔
487
                case 'k': case 'K':
3✔
488
                    result->tabexp = 'k';
3✔
489
                    break;
3✔
490
                case 'u': case 'U':
6✔
491
                    result->tabexp = 'u';
6✔
492
                    break;
6✔
493
                default:
1✔
494
                    errfl = 1;
1✔
495
                    break;
1✔
496
            }
497
        }
498
    }
499
    if (errfl) {
15✔
500
        bx_fprintf(stderr, "%s: invalid tab handling specification - %s\n", PROJECT, optarg);
2✔
501
        return 1;
2✔
502
    }
503
    return 0;
13✔
504
}
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)
181✔
515
{
516
    if (result->eol_overridden) {
181✔
517
        #ifdef __MINGW32__
518
            int rc = _setmode(fileno(stdout), _O_BINARY);
519
            if (rc == -1) {
520
                perror(PROJECT);
521
            }
522
        #endif
523
    }
524
    return stdout;
181✔
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)
184✔
538
{
539
    if (argv[optind] == NULL) {                              /* neither infile nor outfile given */
184✔
540
        result->infile = stdin;
179✔
541
        result->outfile = get_stdout_configured(result);
179✔
542
    }
543

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

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

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

582

583

584
static void print_debug_info(opt_t *result)
182✔
585
{
586
    if (result != NULL) {
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
    }
617
}
182✔
618

619

620

621
opt_t *process_commandline(int argc, char *argv[])
215✔
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();
215✔
633

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

640
    optind = 1;   /* ensure that getopt() will process all arguments, even in unit test situations */
215✔
641
    int option_index = 0;
215✔
642
    const struct option long_options[] = {
215✔
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";
215✔
666

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

671
        switch (oc) {
544!
672

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

821
    print_debug_info(result);
182✔
822
    return result;
182✔
823
}
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