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

ascii-boxes / boxes / 9306133085

30 May 2024 04:40PM UTC coverage: 87.772%. Remained the same
9306133085

push

github

tsjensen
Use 'logging' module for first outputs in 'cmdline' module

2884 of 3481 branches covered (82.85%)

Branch coverage included in aggregate %.

2 of 32 new or added lines in 1 file covered. (6.25%)

17 existing lines in 1 file now uncovered.

4660 of 5114 relevant lines covered (91.12%)

186875.99 hits per line

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

79.01
/src/cmdline.c
1
/*
2
 * boxes - Command line filter to draw/remove ASCII boxes around text
3
 * Copyright (c) 1999-2024 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 "logging.h"
37
#include "query.h"
38
#include "tools.h"
39
#include "cmdline.h"
40

41

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

45

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

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

52

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

61

62

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

73

74

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

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

111
    bxs_free(config_file);
2✔
112
}
2✔
113

114

115

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

137

138

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

150
    while (*p) {
408✔
151
        errfl = 0;
276✔
152
        if (p[1] == '\0' && !strchr("lLcCrR", *p)) {
276✔
153
            errfl = 1;
2✔
154
            break;
2✔
155
        }
156

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

168
            case 'v': case 'V':
44✔
169
                switch (p[1]) {
88✔
170
                    case 'c': case 'C': result->valign = 'c'; break;
34✔
171
                    case 't': case 'T': result->valign = 't'; break;
24✔
172
                    case 'b': case 'B': result->valign = 'b'; break;
28✔
173
                    default:            errfl = 1;            break;
2✔
174
                }
175
                ++p;
88✔
176
                break;
88✔
177

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

188
            case 'l': case 'L':
4✔
189
                result->justify = 'l';
8✔
190
                result->halign = 'l';
8✔
191
                result->valign = 'c';
8✔
192
                break;
8✔
193

194
            case 'r': case 'R':
6✔
195
                result->justify = 'r';
12✔
196
                result->halign = 'r';
12✔
197
                result->valign = 'c';
12✔
198
                break;
12✔
199

200
            case 'c': case 'C':
11✔
201
                result->justify = 'c';
22✔
202
                result->halign = 'c';
22✔
203
                result->valign = 'c';
22✔
204
                break;
22✔
205

206
            default:
1✔
207
                errfl = 1;
2✔
208
                break;
2✔
209
        }
210

211
        if (errfl) {
274✔
212
            break;
8✔
213
        } else {
214
            ++p;
266✔
215
        }
216
    }
217

218
    if (errfl) {
142✔
219
        bx_fprintf(stderr, "%s: Illegal text format -- %s\n", PROJECT, optarg);
12✔
220
        return 1;
12✔
221
    }
222
    return 0;
130✔
223
}
71✔
224

225

226

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

248

249

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

268

269

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

295

296

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

322

323

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

347

348

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

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

415

416

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

430

431

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

462

463

464
static int debug_areas(opt_t *result, char *optarg)
×
465
{
466
    char *dup = NULL;
×
467
    if (optarg != NULL) {
×
468
        dup = strdup(optarg);   /* required because strtok() modifies its input */
×
469
    }
470
    else {
471
        dup = strdup(log_area_names[MAIN]);
×
472
    }
473

474
    for (char *a = strtok(dup, ","); a != NULL; a = strtok(NULL, ","))
×
475
    {
476
        char *trimmed = trimdup(a, a + strlen(a) - 1);
×
477
        if (strlen(trimmed) == 0) {
×
478
            BFREE(trimmed);
×
479
            continue;
×
480
        }
481
        int valid = 0;
×
482
        for (size_t i = ALL; i < NUM_LOG_AREAS + 2; i++) {
×
483
            if (strcasecmp(trimmed, log_area_names[i]) == 0) {
×
484
                valid = 1;
×
485
                if (i == ALL) {
×
486
                    for (size_t i = 0; i < NUM_LOG_AREAS; i++) {
×
487
                        result->debug[i] = 1;
×
488
                    }
489
                }
490
                else {
491
                    result->debug[i - 2] = 1;
×
492
                }
493
                break;
×
494
            }
495
        }
496
        if (!valid) {
×
497
            bx_fprintf(stderr, "%s: invalid debug area -- %s\n", PROJECT, trimmed);
×
498
            BFREE(trimmed);
×
499
            return 1;
×
500
        }
501
        BFREE(trimmed);
×
502
    }
503
    BFREE(dup);
×
504
    return 0;
×
505
}
506

507

508

509
/**
510
 * Tab handling. Format is `n[eku]`.
511
 * @param result the options struct we are building
512
 * @param optarg the argument to `-t` on the command line
513
 * @returns 0 on success, anything else on error
514
 */
515
static int tab_handling(opt_t *result, char *optarg)
34✔
516
{
517
    char *p;
518
    int width = (int) strtol(optarg, &p, 10);
34✔
519
    if (width < 1 || width > MAX_TABSTOP) {
34✔
520
        bx_fprintf(stderr, "%s: invalid tab stop distance -- %d\n", PROJECT, width);
4✔
521
        return 1;
4✔
522
    }
523
    result->tabstop = width;
30✔
524

525
    int errfl = 0;
30✔
526
    if (*p != '\0') {
30✔
527
        if (p[1] != '\0') {
24✔
528
            errfl = 1;
2✔
529
        }
1✔
530
        else {
531
            switch (*p) {
22✔
532
                case 'e': case 'E':
1✔
533
                    result->tabexp = 'e';
2✔
534
                    break;
2✔
535
                case 'k': case 'K':
3✔
536
                    result->tabexp = 'k';
6✔
537
                    break;
6✔
538
                case 'u': case 'U':
6✔
539
                    result->tabexp = 'u';
12✔
540
                    break;
12✔
541
                default:
1✔
542
                    errfl = 1;
2✔
543
                    break;
2✔
544
            }
545
        }
546
    }
12✔
547
    if (errfl) {
30✔
548
        bx_fprintf(stderr, "%s: invalid tab handling specification - %s\n", PROJECT, optarg);
4✔
549
        return 1;
4✔
550
    }
551
    return 0;
26✔
552
}
17✔
553

554

555

556
/**
557
 * Set *stdout* to binary mode, so that we can control the line terminator. This function only ever does anything on
558
 * Windows, because on Linux, we already do have control over line terminators.
559
 * @param result the options struct we are building
560
 * @return the *stdout* stream, reconfigured to binary if necessary
561
 */
562
static FILE *get_stdout_configured(opt_t *result)
800✔
563
{
564
    if (result->eol_overridden) {
800✔
565
        #ifdef __MINGW32__
566
            int rc = _setmode(fileno(stdout), _O_BINARY);
567
            if (rc == -1) {
568
                perror(PROJECT);
569
            }
570
        #endif
571
    }
9✔
572
    return stdout;
800✔
573
}
574

575

576

577
/**
578
 * Input and Output Files. After any command line options, an input file and an output file may be specified (in that
579
 * order). "-" may be substituted for standard input or output. A third file name would be invalid.
580
 * @param result the options struct we are building
581
 * @param argv the original command line options as specified
582
 * @param optind the index of the next element to be processed in `argv`
583
 * @returns 0 on success, anything else on error
584
 */
585
static int input_output_files(opt_t *result, char *argv[], int optind)
806✔
586
{
587
    if (argv[optind] == NULL) {                              /* neither infile nor outfile given */
806✔
588
        result->infile = stdin;
508✔
589
        result->outfile = get_stdout_configured(result);
508✔
590
    }
254✔
591

592
    else if (argv[optind + 1] && argv[optind + 2]) {         /* illegal third file */
298✔
593
        bx_fprintf(stderr, "%s: illegal parameter -- %s\n", PROJECT, argv[optind + 2]);
2✔
594
        usage_short(stderr);
2✔
595
        return 1;
2✔
596
    }
597

598
    else {
599
        if (strcmp(argv[optind], "-") == 0) {
296✔
600
            result->infile = stdin;                          /* use stdin for input */
4✔
601
        }
2✔
602
        else {
603
            result->infile = fopen(argv[optind], "r");
292✔
604
            if (result->infile == NULL) {
292✔
605
                bx_fprintf(stderr, "%s: Can\'t open input file -- %s\n", PROJECT, argv[optind]);
2✔
606
                return 9;                                    /* can't read infile */
2✔
607
            }
608
        }
609

610
        if (argv[optind + 1] == NULL) {
294✔
611
            result->outfile = get_stdout_configured(result); /* no outfile given */
290✔
612
        }
145✔
613
        else if (strcmp(argv[optind + 1], "-") == 0) {
4✔
614
            result->outfile = get_stdout_configured(result); /* use stdout for output */
2✔
615
        }
1✔
616
        else {
617
            result->outfile = fopen(argv[optind + 1], "wb");
2✔
618
            if (result->outfile == NULL) {
2✔
619
                perror(PROJECT);
×
620
                if (result->infile != stdin) {
×
621
                    fclose(result->infile);
×
622
                }
623
                return 10;
×
624
            }
625
        }
626
    }
627
    return 0;
802✔
628
}
403✔
629

630

631

632
static void print_debug_info(opt_t *result)
802✔
633
{
634
    if (result != NULL && is_debug_logging(MAIN)) {
802!
NEW
635
        log_debug(__FILE__, MAIN, "Command line option settings (excerpt):\n");
×
NEW
636
        log_debug(__FILE__, MAIN, "  - Alignment (-a): horiz %c, vert %c\n",
×
NEW
637
                result->halign ? result->halign : '?', result->valign ? result->valign : '?');
×
NEW
638
        log_debug(__FILE__, MAIN, "  - Line justification (-a): \'%c\'\n", result->justify ? result->justify : '?');
×
NEW
639
        log_debug(__FILE__, MAIN, "  - Design Definition W shape (-c): %s\n", result->cld ? result->cld : "n/a");
×
NEW
640
        log_debug(__FILE__, MAIN, "  - Color mode: %d\n", result->color);
×
641

NEW
642
        log_debug(__FILE__, MAIN, "  - Debug areas: ");
×
NEW
643
        int dbgfirst = 1;
×
NEW
644
        for (size_t i = 0; i < NUM_LOG_AREAS; i++) {
×
NEW
645
            if (result->debug[i]) {
×
NEW
646
                log_debug_cont(MAIN, "%s%s", dbgfirst ? "" : ", ", log_area_names[i + 2]);
×
NEW
647
                dbgfirst = 0;
×
648
            }
649
        }
NEW
650
        log_debug_cont(MAIN, "%s\n", dbgfirst ? "(off)" : "");
×
651

NEW
652
        log_debug(__FILE__, MAIN, "  - Line terminator used (-e): %s\n",
×
NEW
653
            strcmp(result->eol, "\r\n") == 0 ? "CRLF" : (strcmp(result->eol, "\r") == 0 ? "CR" : "LF"));
×
NEW
654
        log_debug(__FILE__, MAIN, "  - Explicit config file (-f): %s\n", result->f ? result->f : "no");
×
NEW
655
        log_debug(__FILE__, MAIN, "  - Indentmode (-i): \'%c\'\n", result->indentmode ? result->indentmode : '?');
×
NEW
656
        log_debug(__FILE__, MAIN, "  - Kill blank lines (-k): %d\n", result->killblank);
×
NEW
657
        log_debug(__FILE__, MAIN, "  - Mend box (-m): %d\n", result->mend);
×
NEW
658
        log_debug(__FILE__, MAIN, "  - Padding (-p): l:%d t:%d r:%d b:%d\n",
×
659
                result->padding[BLEF], result->padding[BTOP], result->padding[BRIG], result->padding[BBOT]);
660

NEW
661
        log_debug(__FILE__, MAIN, "  - Tag Query / Special handling for Web UI (-q): ");
×
NEW
662
        if (result->query != NULL) {
×
NEW
663
            for (size_t qidx = 0; result->query[qidx] != NULL; ++qidx) {
×
NEW
664
                log_debug_cont(MAIN, "%s%s", qidx > 0 ? ", " : "", result->query[qidx]);
×
665
            }
666
        } else {
NEW
667
            log_debug_cont(MAIN, "(none)");
×
668
        }
NEW
669
        log_debug_cont(MAIN, "\n");
×
670

NEW
671
        log_debug(__FILE__, MAIN, "  - Remove box (-r): %d\n", result->r);
×
NEW
672
        log_debug(__FILE__, MAIN, "  - Requested box size (-s): %ldx%ld\n", result->reqwidth, result->reqheight);
×
NEW
673
        log_debug(__FILE__, MAIN, "  - Tabstop distance (-t): %d\n", result->tabstop);
×
NEW
674
        log_debug(__FILE__, MAIN, "  - Tab handling (-t): \'%c\'\n", result->tabexp);
×
675
    }
676
}
802✔
677

678

679

680
opt_t *process_commandline(int argc, char *argv[])
868✔
681
{
682
    #ifdef DEBUG
683
        fprintf(stderr, "argc = %d\n", argc);
684
        fprintf(stderr, "argv = [");
685
        for(int i=0; i<=argc; i++) {
686
            fprintf(stderr, "%s%s", argv[i], i < argc ? ", " : "");
687
        }
688
        fprintf(stderr, "]\n");
689
    #endif
690

691
    opt_t *result = create_new_opt();
868✔
692

693
    /* Intercept '-?' case first, as it is not supported by getopt_long() */
694
    if (argc >= 2 && argv[1] != NULL && strcmp(argv[1], "-?") == 0) {
868!
UNCOV
695
        result->help = 1;
×
UNCOV
696
        return result;
×
697
    }
698

699
    optind = 1;   /* ensure that getopt() will process all arguments, even in unit test situations */
868✔
700
    int option_index = 0;
868✔
701
    const struct option long_options[] = {
868✔
702
        { "align",         required_argument, NULL, 'a' },
703
        { "create",        required_argument, NULL, 'c' },
704
        { "color",         no_argument,       NULL, OPT_COLOR },
705
        { "no-color",      no_argument,       NULL, OPT_NO_COLOR },
706
        { "debug",         optional_argument, NULL, 'g' },
707
        { "design",        required_argument, NULL, 'd' },
708
        { "eol",           required_argument, NULL, 'e' },
709
        { "config",        required_argument, NULL, 'f' },
710
        { "help",          no_argument,       NULL, 'h' },
711
        { "indent",        required_argument, NULL, 'i' },
712
        { "kill-blank",    no_argument,       NULL, OPT_KILLBLANK },
713
        { "no-kill-blank", no_argument,       NULL, OPT_NO_KILLBLANK },
714
        { "list",          no_argument,       NULL, 'l' },
715
        { "mend",          no_argument,       NULL, 'm' },
716
        { "encoding",      required_argument, NULL, 'n' },
717
        { "padding",       required_argument, NULL, 'p' },
718
        { "tag-query",     required_argument, NULL, 'q' },
719
        { "remove",        no_argument,       NULL, 'r' },
720
        { "size",          required_argument, NULL, 's' },
721
        { "tabs",          required_argument, NULL, 't' },
722
        { "version",       no_argument,       NULL, 'v' },
723
        { NULL,            0,                 NULL,  0  }
724
    };
725
    const char *short_options = "a:c:d:e:f:g::hi:k:lmn:p:q:rs:t:v";
868✔
726

727
    int oc;   /* option character */
728
    do {
434✔
729
        oc = getopt_long(argc, argv, short_options, long_options, &option_index);
2,696✔
730

731
        switch (oc) {
2,696✔
732

733
            case 'a':
71✔
734
                if (alignment(result, optarg) != 0) {
142✔
735
                    BFREE(result);
12!
736
                    return NULL;
12✔
737
                }
738
                break;
130✔
739

740
            case 'c':
5✔
741
                if (command_line_design(result, optarg) != 0) {
10✔
742
                    BFREE(result);
2!
743
                    return NULL;
2✔
744
                }
745
                break;
8✔
746
            
747
            case OPT_COLOR:
1✔
748
                result->color = force_ansi_color;
2✔
749
                break;
2✔
750

751
            case OPT_NO_COLOR:
UNCOV
752
                result->color = force_monochrome;
×
UNCOV
753
                break;
×
754

755
            case 'd':
249✔
756
                if (design_choice(result, optarg) != 0) {
498✔
UNCOV
757
                    BFREE(result);
×
UNCOV
758
                    return NULL;
×
759
                }
760
                break;
498✔
761

762
            case 'e':
10✔
763
                if (eol_override(result, optarg) != 0) {
20✔
764
                    BFREE(result);
2!
765
                    return NULL;
2✔
766
                }
767
                break;
18✔
768

769
            case 'f':
270✔
770
                result->f = strdup(optarg);   /* input file */
540✔
771
                break;
540✔
772
            
773
            case 'g':
UNCOV
774
                if (debug_areas(result, optarg) != 0) {
×
UNCOV
775
                    BFREE(result);
×
UNCOV
776
                    return NULL;
×
777
                }
UNCOV
778
                activate_debug_logging(result->debug);
×
UNCOV
779
                break;
×
780

781
            case 'h':
2✔
782
                result->help = 1;
4✔
783
                return result;
4✔
784

785
            case 'i':
7✔
786
                if (indentation_mode(result, optarg) != 0) {
14✔
787
                    BFREE(result);
4!
788
                    return NULL;
4✔
789
                }
790
                break;
10✔
791

792
            case 'k':
5✔
793
                if (killblank(result, optarg) != 0) {
10✔
794
                    BFREE(result);
2!
795
                    return NULL;
2✔
796
                }
797
                break;
8✔
798
            
799
            case OPT_KILLBLANK:
2✔
800
                if (result->killblank == -1) {
4✔
801
                    result->killblank = 1;
4✔
802
                }
2✔
803
                break;
4✔
804

805
            case OPT_NO_KILLBLANK:
1✔
806
                if (result->killblank == -1) {
2✔
807
                    result->killblank = 0;
2✔
808
                }
1✔
809
                break;
2✔
810

811
            case 'l':
25✔
812
                result->l = 1;   /* list available box styles */
50✔
813
                break;
50✔
814

815
            case 'm':
73✔
816
                result->mend = 2;   /*  Mend box: remove, then redraw */
146✔
817
                result->r = 1;
146✔
818
                result->killblank = 0;
146✔
819
                break;
146✔
820

821
            case 'n':
12✔
822
                result->encoding = strdup(optarg);   /* character encoding */
24✔
823
                if (result->encoding == NULL) {
24✔
UNCOV
824
                    perror(PROJECT);
×
UNCOV
825
                    BFREE(result);
×
UNCOV
826
                    return NULL;
×
827
                }
828
                break;
24✔
829

830
            case 'p':
18✔
831
                if (padding(result, optarg) != 0) {
36✔
832
                    BFREE(result);
10!
833
                    return NULL;
10✔
834
                }
835
                break;
26✔
836

837
            case 'q':
13✔
838
                if (query(result, optarg) != 0) {
26✔
839
                    BFREE(result);
8!
840
                    return NULL;
8✔
841
                }
842
                break;
18✔
843

844
            case 'r':
90✔
845
                result->r = 1;   /* remove box */
180✔
846
                break;
180✔
847

848
            case 's':
71✔
849
                if (size_of_box(result, optarg) != 0) {
142✔
850
                    BFREE(result);
4!
851
                    return NULL;
4✔
852
                }
853
                break;
138✔
854

855
            case 't':
17✔
856
                if (tab_handling(result, optarg) != 0) {
34✔
857
                    BFREE(result);
8!
858
                    return NULL;
8✔
859
                }
860
                break;
26✔
861

862
            case 'v':
1✔
863
                result->version_requested = 1;   /* print version number */
2✔
864
                return result;
2✔
865

866
            case ':':
2✔
867
            case '?':
868
                /* Missing argument or illegal option - do nothing else */
869
                usage_short(stderr);
4✔
870
                BFREE(result);
4✔
871
                return NULL;
4✔
872

873
            case EOF:
403✔
874
                /* End of list, do nothing more */
875
                break;
806✔
876

877
            default:
UNCOV
878
                bx_fprintf(stderr, "%s: internal error\n", PROJECT);
×
UNCOV
879
                BFREE(result);
×
UNCOV
880
                return NULL;
×
881
        }
882
    } while (oc != EOF);
2,634✔
883

884
    if (input_output_files(result, argv, optind) != 0) {
806✔
885
        BFREE(result);
4✔
886
        return NULL;
4✔
887
    }
888

889
    print_debug_info(result);
802✔
890
    return result;
802✔
891
}
434✔
892

893

894
/*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