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

ascii-boxes / boxes / 25991660202

17 May 2026 01:04PM UTC coverage: 82.822%. Remained the same
25991660202

push

github

tsjensen
Fix a Heisenbug in u32_insert_space_at() in unicode.c

2776 of 3695 branches covered (75.13%)

Branch coverage included in aggregate %.

5 of 7 new or added lines in 1 file covered. (71.43%)

297 existing lines in 19 files now uncovered.

4345 of 4903 relevant lines covered (88.62%)

98937.49 hits per line

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

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

17
/*
18
 * Functions related to querying the design list by tag.
19
 */
20

21
#include "config.h"
22
#include <stdio.h>
23
#include <string.h>
24
#include <strings.h>
25

26
#include "boxes.h"
27
#include "list.h"
28
#include "logging.h"
29
#include "tools.h"
30
#include "query.h"
31

32

33

34
#define QUERY_ALL "(all)"
35

36

37

38
static int validate_tag(char *tag)
19✔
39
{
40
    if (strcmp(tag, QUERY_ALL) == 0) {
19✔
41
        return 1;
2✔
42
    }
43
    return tag_is_valid(tag);
17✔
44
}
45

46

47

48
char **parse_query(char *optarg)
13✔
49
{
50
    /* CAUTION: This function cannot use `opt`, because it is involved in its construction. */
51

52
    char **query = NULL;
13✔
53
    char *dup = strdup(optarg);   /* required because strtok() modifies its input */
13✔
54

55
    int contains_positive_element = 0;
13✔
56
    size_t num_expr = 0;
13✔
57
    for (char *q = strtok(dup, ","); q != NULL; q = strtok(NULL, ","))
29✔
58
    {
59
        char *trimmed = trimdup(q, q + strlen(q) - 1);
19✔
60
        if (strlen(trimmed) == 0) {
19!
61
            BFREE(trimmed);
×
UNCOV
62
            continue;
×
63
        }
64

65
        if (trimmed[0] != '-') {
19✔
66
            contains_positive_element = 1;
13✔
67
        }
68

69
        char *raw_tag = (trimmed[0] == '+' || trimmed[0] == '-') ? (trimmed + 1) : trimmed;
19✔
70
        if (!validate_tag(raw_tag)) {
19✔
71
            fprintf(stderr, "%s: not a tag -- %s\n", PROJECT, raw_tag);
1✔
72
            BFREE(trimmed);
1!
73
            BFREE(query);
1!
74
            return NULL;
1✔
75
        }
76
        if (query != NULL) {
18✔
77
            for (size_t i = 0; query[i] != NULL; ++i) {
12✔
78
                char *restag = (query[i][0] == '+' || query[i][0] == '-') ? (query[i] + 1) : query[i];
7✔
79
                if (strcasecmp(restag, raw_tag) == 0) {
7✔
80
                    fprintf(stderr, "%s: duplicate query expression -- %s\n", PROJECT, trimmed);
2✔
81
                    BFREE(trimmed);
2!
82
                    BFREE(query);
2!
83
                    return NULL;
2✔
84
                }
85
            }
86
        }
87

88
        ++num_expr;
16✔
89
        query = (char **) realloc(query, (num_expr + 1) * sizeof(char *));
16✔
90
        if (query == NULL) {
16!
91
            perror(PROJECT);
×
UNCOV
92
            break;
×
93
        }
94
        query[num_expr - 1] = trimmed;
16✔
95
        query[num_expr] = NULL;
16✔
96
    }
97
    BFREE(dup);
10!
98

99
    if (num_expr == 0) {
10✔
100
        fprintf(stderr, "%s: empty tag query -- %s\n", PROJECT, optarg);
1✔
101
        return NULL;
1✔
102
    }
103

104
    if (!contains_positive_element) {
9✔
105
        ++num_expr;
2✔
106
        query = (char **) realloc(query, (num_expr + 1) * sizeof(char *));
2✔
107
        if (query == NULL) {
2!
UNCOV
108
            perror(PROJECT);
×
109
        }
110
        else {
111
            query[num_expr - 1] = QUERY_ALL;
2✔
112
            query[num_expr] = NULL;
2✔
113
        }
114
    }
115

116
    return query;
9✔
117
}
118

119

120

121
static int filter_by_tag(char **tags)
104✔
122
{
123
    if (is_debug_logging(MAIN)) {
104!
124
        log_debug(__FILE__, MAIN, "filter_by_tag(");
×
125
        for (size_t tidx = 0; tags[tidx] != NULL; ++tidx) {
×
UNCOV
126
            log_debug_cont(MAIN, "%s%s", tidx > 0 ? ", " : "", tags[tidx]);
×
127
        }
128
    }
129

130
    int result = array_contains0(opt.query, QUERY_ALL);
104✔
131
    if (opt.query != NULL) {
104!
132
        for (size_t qidx = 0; opt.query[qidx] != NULL; ++qidx) {
211✔
133
            if (opt.query[qidx][0] == '+') {
119✔
134
                result = array_contains0(tags, opt.query[qidx] + 1);
10✔
135
                if (!result) {
10✔
136
                    break;
5✔
137
                }
138
            }
139
            else if (opt.query[qidx][0] == '-') {
109✔
140
                if (array_contains0(tags, opt.query[qidx] + 1)) {
14✔
141
                    result = 0;
7✔
142
                    break;
7✔
143
                }
144
            }
145
            else if (array_contains0(tags, opt.query[qidx])) {
95✔
146
                result = 1;
8✔
147
            }
148
        }
149
    }
150

151
    log_debug_cont(MAIN, ") -> %d\n", result);
104✔
152
    return result;
104✔
153
}
154

155

156

157
int query_by_tag()
9✔
158
{
159
    design_t **list = sort_designs_by_name();                 /* temp list for sorting */
9✔
160
    if (list == NULL) {
9!
UNCOV
161
        return 1;
×
162
    }
163
    for (int i = 0; i < num_designs; ++i) {
113✔
164
        if (filter_by_tag(list[i]->tags)) {
104✔
165
            fprintf(opt.outfile, "%s%s", list[i]->name, opt.eol);
86✔
166
            for (size_t aidx = 0; list[i]->aliases[aidx] != NULL; ++aidx) {
102✔
167
                fprintf(opt.outfile, "%s (alias)%s", list[i]->aliases[aidx], opt.eol);
16✔
168
            }
169
        }
170
    }
171
    BFREE(list);
9!
172
    return 0;
9✔
173
}
174

175

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