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

ascii-boxes / boxes / 6597578609

21 Oct 2023 12:39PM UTC coverage: 83.876% (+0.07%) from 83.808%
6597578609

push

github

tsjensen
remove tests

2394 of 3136 branches covered (0.0%)

Branch coverage included in aggregate %.

3791 of 4238 relevant lines covered (89.45%)

8237.66 hits per line

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

92.75
/src/detect.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
 * Autodetect design used by box in input.
18
 *
19
 * When detecting box shapes in input lines, we can find (in order of precedence):
20
 * 1. (box design: colored, input: colored)
21
 *    Colored boxes which are colored as per their design. In that case, matching all the invisible characters
22
 *    increases our confidence that we have found the right shape.
23
 *    -> use both shapes and input as-is, comparison type `literal`
24
 * 2. (box design: monochrome, input: monochrome)
25
 *    Boxes which have no invisible characters because color was never involved. This one is the classic case.
26
 *    -> use both shapes and input as-is, comparison type `literal` (same as 1.)
27
 * 3. (box design: monochrome, input: colored)
28
 *    Colored boxes which are colored because of lolcat processing or similar. In that case, we can ignore the
29
 *    invisible characters in the input.
30
 *    -> use shapes as-is, and ignore invisible characters in input, comparison type `ignore_invisible_input`
31
 * 4. (box design: colored, input: monochrome)
32
 *    Boxes which have no invisible characters because they have been removed (for example via --no-color), even though
33
 *    the original design was colored. In that case, we must ignore the invisible characters in the design.
34
 *    -> ignore invisible characters in shapes, use input as-is, comparison type `ignore_invisible_shape`
35
 * 5. Fallback: We assume to never see a colored box design PLUS lolcat-induced codes, or a case where a colored box
36
 *    design had its color removed and replaced with lolcat colors. That's just messy and we will treat it as case
37
 *    number two, where we ignore colors on both input and box design.
38
 *    -> ignore invisible characters in both shapes and input, comparison type `ignore_invisible_all`
39
 */
40

41
#include "config.h"
42

43
#include <unistr.h>
44
#include <unitypes.h>
45

46
#include "boxes.h"
47
#include "bxstring.h"
48
#include "shape.h"
49
#include "tools.h"
50
#include "unicode.h"
51
#include "detect.h"
52

53

54

55
char *comparison_name[] = {
56
        "literal", "ignore_invisible_input", "ignore_invisible_shape", "ignore_invisible_all"
57
};
58

59

60

61
int input_is_mono()
15✔
62
{
63
    int result = 1;
15✔
64
    for (size_t line_no = 0; line_no < input.num_lines; line_no++) {
87✔
65
        if (input.lines[line_no].text->num_chars_invisible > 0) {
82✔
66
            result = 0;
10✔
67
            break;
10✔
68
        }
69
    }
70
    #ifdef DEBUG
71
        fprintf(stderr, "Input is %s\n", result ? "mono" : "potentially colored");
72
    #endif
73
    return result;
15✔
74
}
75

76

77

78
int design_is_mono(design_t *design)
199✔
79
{
80
    for (shape_t scnt = 0; scnt < NUM_SHAPES; ++scnt) {
3,231✔
81
        if (isempty(design->shape + scnt)) {
3,042✔
82
            continue;
1,154✔
83
        }
84
        for (size_t line_no = 0; line_no < design->shape[scnt].height; line_no++) {
7,008✔
85
            bxstr_t *shape_line = design->shape[scnt].mbcs[line_no];
5,130✔
86
            if (shape_line->num_chars_invisible > 0) {
5,130✔
87
                #ifdef DEBUG
88
                    fprintf(stderr, "Design is potentially colored\n");
89
                #endif
90
                return 0;
10✔
91
            }
92
        }
93
    }
94
    #ifdef DEBUG
95
        fprintf(stderr, "Design is mono\n");
96
    #endif
97
    return 1;
189✔
98
}
99

100

101

102
int comp_type_is_viable(comparison_t comp_type, int mono_input, int mono_design)
353✔
103
{
104
    int result = 1;
353✔
105
    if ((comp_type == literal && mono_input != mono_design)
353✔
106
            || (comp_type == ignore_invisible_input && (mono_input || !mono_design))
262✔
107
            || (comp_type == ignore_invisible_shape && (!mono_input || mono_design))
231!
108
            || (comp_type == ignore_invisible_all && (mono_input || mono_design)))
215!
109
    {
110
        result = 0;
138✔
111
    }
112
    return result;
353✔
113
}
114

115

116

117
static int *determine_empty_sides(design_t *current_design)
126✔
118
{
119
    int *result = (int *) calloc(NUM_SIDES, sizeof(int));
126✔
120

121
    for (size_t j = 0; j < NUM_SIDES; ++j) {
630✔
122
        result[j] = empty_side(current_design->shape, j);
504✔
123
    }
124
    #ifdef DEBUG
125
        fprintf (stderr, "Empty sides: TOP %d, LEFT %d, BOTTOM %d, RIGHT %d\n",
126
            result[BTOP], result[BLEF], result[BBOT], result[BRIG]);
127
    #endif
128
    return result;
126✔
129
}
130

131

132

133
static uint32_t *get_visible_text(line_t *line)
1,829✔
134
{
135
    uint32_t *result = NULL;
1,829✔
136
    if (line != NULL) {
1,829!
137
        if (line->cache_visible == NULL) {
1,829✔
138
            line->cache_visible = bxs_filter_visible(line->text);
39✔
139
        }
140
        result = line->cache_visible;
1,829✔
141
    }
142
    return result;
1,829✔
143
}
144

145

146

147
uint32_t *prepare_comp_shape(
3,943✔
148
        design_t *design, shape_t shape, size_t shape_line_idx, comparison_t comp_type, int trim_left, int trim_right)
149
{
150
    sentry_t shape_def = design->shape[shape];
3,943✔
151
    if (shape_line_idx >= shape_def.height) {
3,943!
152
        bx_fprintf(stderr, "%s: prepare_comp_shape(\"%s\", %s, %d, %s, %d, %d): Index out of bounds\n", PROJECT,
×
153
                design->name, shape, (int) shape_line_idx, comparison_name[comp_type], trim_left, trim_right);
154
        return NULL;
×
155
    }
156

157
    bxstr_t *shape_line = shape_def.mbcs[shape_line_idx];
3,943✔
158
    uint32_t *result = NULL;
3,943✔
159

160
    if ((comp_type == ignore_invisible_shape || comp_type == ignore_invisible_all)
3,943✔
161
            && shape_line->num_chars_invisible > 0)
167✔
162
    {
69✔
163
        size_t ltrim = trim_left ? shape_line->indent : 0;
69✔
164
        uint32_t *visible = bxs_filter_visible(shape_line);
69✔
165
        result = u32_strdup(visible + ltrim);
69✔
166
        BFREE(visible);
69!
167

168
        if (trim_right && shape_line->trailing > 0) {
69✔
169
            set_char_at(result, shape_line->num_chars_visible - ltrim - shape_line->trailing, char_nul);
6✔
170
        }
171
    }
172
    else {
173
        result = u32_strdup(trim_left ? bxs_unindent_ptr(shape_line) : shape_line->memory);
3,874✔
174

175
        if (trim_right && shape_line->trailing > 0) {
3,874✔
176
            size_t x = shape_line->num_chars_visible - (trim_left ? shape_line->indent : 0) - shape_line->trailing;
218✔
177
            set_char_at(result, shape_line->first_char[x], char_nul);
218✔
178
        }
179
    }
180
    return result;
3,943✔
181
}
182

183

184

185
uint32_t *prepare_comp_input(size_t input_line_idx, int trim_left, comparison_t comp_type, size_t offset_right,
8,220✔
186
    size_t *out_indent, size_t *out_trailing)
187
{
188
    if (input_line_idx >= input.num_lines) {
8,220!
189
        bx_fprintf(stderr, "%s: prepare_comp_input(%d, %d, %s, %d): Index out of bounds\n", PROJECT,
×
190
                (int) input_line_idx, trim_left, comparison_name[comp_type], (int) offset_right);
191
        return NULL;
×
192
    }
193
    bxstr_t *input_line = input.lines[input_line_idx].text;
8,220✔
194

195
    uint32_t *result = NULL;
8,220✔
196
    if (comp_type == ignore_invisible_input || comp_type == ignore_invisible_all) {
8,220✔
197
        if (offset_right > 0) {
1,829✔
198
            uint32_t *visible = get_visible_text(input.lines + input_line_idx);
370✔
199
            uint32_t *p = visible + input_line->num_chars_visible - input_line->trailing - offset_right;
370✔
200
            if (p >= visible) {
370!
201
                result = p;
370✔
202
                if (out_indent != NULL) {
370!
203
                    *out_indent = BMAX(input_line->indent - (size_t) (p - visible), (size_t) 0);
×
204
                }
205
            }
206
        }
207
        else {
208
            size_t ltrim = trim_left ? input_line->indent : 0;
1,459✔
209
            result = get_visible_text(input.lines + input_line_idx) + ltrim;
1,459✔
210
            if (out_indent != NULL) {
1,459✔
211
                *out_indent = trim_left ? 0 : input_line->indent;
13!
212
            }
213
        }
214
        if (out_trailing != NULL) {
1,829✔
215
            *out_trailing = input_line->trailing;
13✔
216
        }
217
    }
218
    else {
219
        if (offset_right > 0) {
6,391✔
220
            int idx = (int) input_line->first_char[input_line->num_chars_visible - input_line->trailing]
2,033✔
221
                        - offset_right;
2,033✔
222
            if (idx >= 0) {
2,033✔
223
                result = input_line->memory + idx;
2,030✔
224
                if (out_indent != NULL) {
2,030!
225
                    *out_indent = BMAX(input_line->first_char[input_line->indent] - (size_t) idx, (size_t) 0);
×
226
                }
227
            }
228
        }
229
        else {
230
            result = trim_left ? bxs_unindent_ptr(input_line) : input_line->memory;
4,358✔
231
            if (out_indent != NULL) {
4,358✔
232
                *out_indent = trim_left ? 0 : input_line->first_char[input_line->indent];
23!
233
            }
234
        }
235
        if (out_trailing != NULL) {
6,391✔
236
            *out_trailing = input_line->num_chars
23✔
237
                    - input_line->first_char[input_line->num_chars_visible - input_line->trailing];
23✔
238
        }
239
    }
240
    return result;
8,220✔
241
}
242

243

244

245
/**
246
 * Try and find west corner shapes. Every non-empty shape line is searched for on every input line. A hit is generated
247
 * whenever a match is found.
248
 * @param current_design the current design to check
249
 * @param comp_type the comparison type (how to compare colored strings)
250
 * @param empty information on which box sides are empty in that design
251
 * @param corner which west corner to search for
252
 * @return the number of hits for this corner
253
 */
254
static size_t find_west_corner(design_t *current_design, comparison_t comp_type, int *empty, shape_t corner)
252✔
255
{
256
    size_t hits = 0;
252✔
257
    if (empty[BLEF] || (empty[BTOP] && corner == NW) || (empty[BBOT] && corner == SW)) {
252!
258
        return hits;
42✔
259
    }
260

261
    for (size_t j = 0; j < current_design->shape[corner].height; ++j) {
858✔
262
        bxstr_t *shape_line = current_design->shape[corner].mbcs[j];
648✔
263
        if (bxs_is_blank(shape_line)) {
648✔
264
            continue;
320✔
265
        }
266

267
        uint32_t *shape_relevant = prepare_comp_shape(current_design, corner, j, comp_type, 1, 0);
328✔
268
        size_t length_relevant = u32_strlen(shape_relevant);
328✔
269

270
        for (size_t k = 0; k < current_design->shape[corner].height; ++k) {
1,255✔
271
            size_t a = k;
982✔
272
            if (corner == SW) {
982✔
273
                a += input.num_lines - current_design->shape[corner].height;
438✔
274
            }
275
            if (a >= input.num_lines) {
982✔
276
                break;
55✔
277
            }
278

279
            uint32_t *input_relevant = prepare_comp_input(a, 1, comp_type, 0, NULL, NULL);
927✔
280
            if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
927✔
281
                ++hits; /* CHECK more hit points for longer matches, or simple boxes might match too easily */
64✔
282
            }
283
        }
284
        BFREE(shape_relevant);
328!
285
    }
286

287
    #ifdef DEBUG
288
        fprintf(stderr, "Checking %s corner produced %d hits.\n", shape_name[corner], (int) hits);
289
    #endif
290
    return hits;
210✔
291
}
292

293

294

295
/**
296
 * Try and find east corner shapes. Every non-empty shape line is searched for on every input line. A hit is generated
297
 * whenever a match is found.
298
 * @param current_design the current design to check
299
 * @param comp_type the comparison type (how to compare colored strings)
300
 * @param empty information on which box sides are empty in that design
301
 * @param corner which west corner to search for
302
 * @return the number of hits for this corner
303
 */
304
static size_t find_east_corner(design_t *current_design, comparison_t comp_type, int *empty, shape_t corner)
252✔
305
{
306
    size_t hits = 0;
252✔
307
    if (empty[BRIG] || (empty[BTOP] && corner == NE) || (empty[BBOT] && corner == SE)) {
252!
308
        return hits;
56✔
309
    }
310

311
    for (size_t j = 0; j < current_design->shape[corner].height; ++j) {
830✔
312
        bxstr_t *shape_line = current_design->shape[corner].mbcs[j];
634✔
313
        if (bxs_is_blank(shape_line)) {
634✔
314
            continue;
292✔
315
        }
316

317
        uint32_t *shape_relevant = prepare_comp_shape(current_design, corner, j, comp_type, 0, 1);
342✔
318
        size_t length_relevant = u32_strlen(shape_relevant);
342✔
319

320
        for (size_t k = 0; k < current_design->shape[corner].height; ++k) {
1,391✔
321
            size_t a = k;
1,120✔
322
            if (corner == SE) {
1,120✔
323
                a += input.num_lines - current_design->shape[corner].height;
578✔
324
            }
325
            if (a >= input.num_lines) {
1,120✔
326
                break;
71✔
327
            }
328

329
            uint32_t *input_relevant = prepare_comp_input(a, 0, comp_type, length_relevant, NULL, NULL);
1,049✔
330
            if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
1,049✔
331
                ++hits; /* CHECK more hit points for longer matches, or simple boxes might match too easily */
45✔
332
            }
333
        }
334
        BFREE(shape_relevant);
342!
335
    }
336

337
    #ifdef DEBUG
338
        fprintf(stderr, "Checking %s corner produced %d hits.\n", shape_name[corner], (int) hits);
339
    #endif
340
    return hits;
196✔
341
}
342

343

344

345
/**
346
 * Try and find a horizontal shape between the box corners. Every non-empty shape line is searched for on every input
347
 * line. Elastic shapes must occur twice in an uninterrupted row to generate a hit.
348
 * @param current_design the current design to check
349
 * @param comp_type the comparison type (how to compare colored strings)
350
 * @param empty information on which box sides are empty in that design
351
 * @param hshape which horizontal shape to search for
352
 * @return the number of hits for this horizontal shape
353
 */
354
static size_t find_horizontal_shape(design_t *current_design, comparison_t comp_type, int *empty, shape_t hshape)
756✔
355
{
356
    size_t hits = 0;
756✔
357
    if (empty[BTOP] || empty[BBOT]) {
756!
358
        return 0;   /* horizontal box part is empty */
132✔
359
    }
360

361
    for (size_t j = 0; j < current_design->shape[hshape].height; ++j) {
2,160✔
362
        bxstr_t *shape_line = current_design->shape[hshape].mbcs[j];
1,536✔
363
        if (bxs_is_blank(shape_line)) {
1,536✔
364
            continue;
666✔
365
        }
366

367
        uint32_t *shape_relevant = prepare_comp_shape(current_design, hshape, j, comp_type, 0, 0);
870✔
368
        size_t length_relevant = u32_strlen(shape_relevant);
870✔
369

370
        for (size_t k = 0; k < current_design->shape[hshape].height; ++k) {
4,329✔
371
            size_t a = k;
3,723✔
372
            if (hshape >= SSE && hshape <= SSW) {
3,723!
373
                a += input.num_lines - current_design->shape[hshape].height;
1,506✔
374
            }
375
            if (a >= input.num_lines) {
3,723✔
376
                break;
264✔
377
            }
378

379
            uint32_t *input_relevant = prepare_comp_input(a, 1, comp_type, 0, NULL, NULL);
3,459✔
380
                                       /* CHECK this eats blank NW corners */
381
            uint32_t *p = u32_strstr(input_relevant, shape_relevant);
3,459✔
382
            if (p) {
3,459✔
383
                if (current_design->shape[hshape].elastic) {
419✔
384
                    p += length_relevant;
342✔
385
                    if (p - input_relevant >= (long) u32_strlen(input_relevant)) {
342!
386
                        continue;
×
387
                    }
388
                    if (u32_strncmp(p, shape_relevant, length_relevant) == 0) {
342✔
389
                        ++hits;
202✔
390
                    }
391
                }
392
                else {
393
                    ++hits;
77✔
394
                }
395
            }
396
        }
397
        BFREE(shape_relevant);
870!
398
    }
399

400
    #ifdef DEBUG
401
        fprintf(stderr, "Checking %s shape produced %d hits.\n", shape_name[hshape], (int) hits);
402
    #endif
403
    return hits;
624✔
404
}
405

406

407

408
/**
409
 * Iterate over all input lines except for potential top and bottom box parts. Check if west line starts match a
410
 * non-empty shape line. If so, generate a hit.
411
 * @param current_design the current design to check
412
 * @param comp_type the comparison type (how to compare colored strings)
413
 * @param empty information on which box sides are empty in that design
414
 * @param vshape which vertical shape to search for
415
 * @return the number of hits for this vertical shape
416
 */
417
static size_t find_vertical_west(design_t *current_design, comparison_t comp_type, int *empty, shape_t vshape)
378✔
418
{
419
    size_t hits = 0;
378✔
420
    if (((empty[BTOP] ? 0 : current_design->shape[NW].height) + (empty[BBOT] ? 0 : current_design->shape[SW].height))
378✔
421
            >= input.num_lines) {
378✔
422
        return hits;
87✔
423
    }
424
    if (isempty(current_design->shape + vshape)) {
291✔
425
        return hits;
172✔
426
    }
427

428
    for (size_t k = empty[BTOP] ? 0 : current_design->shape[NW].height;
119✔
429
            k < input.num_lines - (empty[BBOT] ? 0 : current_design->shape[SW].height); ++k)
1,436✔
430
    {
431
        uint32_t *input_relevant = prepare_comp_input(k, 1, comp_type, 0, NULL, NULL);
1,317✔
432

433
        for (size_t j = 0; j < current_design->shape[vshape].height; ++j) {
3,029✔
434
            bxstr_t *shape_line = current_design->shape[vshape].mbcs[j];
1,859✔
435
            if (bxs_is_blank(shape_line)) {
1,859✔
436
                continue;
25✔
437
            }
438

439
            uint32_t *shape_relevant = prepare_comp_shape(current_design, vshape, j, comp_type, 1, 0);
1,834✔
440
            size_t length_relevant = u32_strlen(shape_relevant);
1,834✔
441

442
            if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
1,834✔
443
                ++hits;
147✔
444
                break;
147✔
445
            }
446
            BFREE(shape_relevant);
1,687!
447
        }
448
    }
449

450
    #ifdef DEBUG
451
        fprintf(stderr, "Checking %s shape produced %d hits.\n", shape_name[vshape], (int) hits);
452
    #endif
453
    return hits;
119✔
454
}
455

456

457

458
/**
459
 * Iterate over all input lines except for potential top and bottom box parts. Check if east line ends match a
460
 * non-empty shape line. If so, generate a hit.
461
 * @param current_design the current design to check
462
 * @param comp_type the comparison type (how to compare colored strings)
463
 * @param empty information on which box sides are empty in that design
464
 * @param vshape which vertical shape to search for
465
 * @return the number of hits for this vertical shape
466
 */
467
static size_t find_vertical_east(design_t *current_design, comparison_t comp_type, int *empty, shape_t vshape)
378✔
468
{
469
    size_t hits = 0;
378✔
470
    if (((empty[BTOP] ? 0 : current_design->shape[NW].height) + (empty[BBOT] ? 0 : current_design->shape[SW].height))
378✔
471
            >= input.num_lines) {
378✔
472
        return hits;
87✔
473
    }
474
    if (isempty(current_design->shape + vshape)) {
291✔
475
        return hits;
172✔
476
    }
477

478
    for (size_t j = 0; j < current_design->shape[vshape].height; ++j) {
292✔
479
        bxstr_t *shape_line = current_design->shape[vshape].mbcs[j];
173✔
480
        if (bxs_is_blank(shape_line)) {
173✔
481
            continue;
26✔
482
        }
483

484
        uint32_t *shape_relevant = prepare_comp_shape(current_design, vshape, j, comp_type, 1, 1);
147✔
485
        size_t length_relevant = u32_strlen(shape_relevant);
147✔
486

487
        for (size_t k = empty[BTOP] ? 0 : current_design->shape[NW].height;
147✔
488
                k < input.num_lines - (empty[BBOT] ? 0 : current_design->shape[SW].height); ++k)
1,468✔
489
        {
490
            uint32_t *input_relevant = prepare_comp_input(k, 0, comp_type, length_relevant, NULL, NULL);
1,354✔
491
            if (input_relevant != NULL && u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
1,354✔
492
                ++hits;
33✔
493
                break;
33✔
494
            }
495
        }
496
        BFREE(shape_relevant);
147!
497
    }
498

499
    #ifdef DEBUG
500
        fprintf(stderr, "Checking %s shape produced %d hits.\n", shape_name[vshape], (int) hits);
501
    #endif
502
    return hits;
119✔
503
}
504

505

506

507
static long match_design(design_t *current_design, comparison_t comp_type)
126✔
508
{
509
    int *empty = determine_empty_sides(current_design);
126✔
510
    long hits = 0;
126✔
511

512
    for (shape_t scnt = 0; scnt < NUM_SHAPES; ++scnt) {
2,142✔
513
        switch (scnt) {
2,016!
514
            case NW:
252✔
515
            case SW:
516
                hits += find_west_corner(current_design, comp_type, empty, scnt);
252✔
517
                break;
252✔
518

519
            case NE:
252✔
520
            case SE:
521
                hits += find_east_corner(current_design, comp_type, empty, scnt);
252✔
522
                break;
252✔
523

524
            case NNW: case N: case NNE:
756✔
525
            case SSE: case S: case SSW:
526
                hits += find_horizontal_shape(current_design, comp_type, empty, scnt);
756✔
527
                break;
756✔
528

529
            case ENE: case E: case ESE:
378✔
530
                hits += find_vertical_east(current_design, comp_type, empty, scnt);
378✔
531
                break;
378✔
532

533
            case WSW: case W: case WNW:
378✔
534
                hits += find_vertical_west(current_design, comp_type, empty, scnt);
378✔
535
                break;
378✔
536

537
            default:
×
538
                fprintf(stderr, "%s: internal error (scnt=%d)\n", PROJECT, (int) scnt);
×
539
                return 0;
×
540
        }
541
    }
542

543
    BFREE(empty);
126!
544
    return hits;
126✔
545
}
546

547

548

549
design_t *autodetect_design()
5✔
550
{
551
    design_t *current_design;           /* ptr to currently tested design */
552
    long maxhits = 0;                   /* maximum no. of hits so far */
5✔
553
    design_t *result = NULL;            /* ptr to design with the most hits */
5✔
554
    int mono_input = input_is_mono();
5✔
555
    (void) comparison_name;             /* used only in debug statements */
556

557
    for (comparison_t comp_type = 0; comp_type < NUM_COMPARISON_TYPES; comp_type++) {
9!
558
        current_design = designs;
9✔
559
        for (size_t dcnt = 0; ((int) dcnt) < num_designs; ++dcnt, ++current_design) {
198✔
560
            int mono_design = design_is_mono(current_design);
189✔
561
            if (!comp_type_is_viable(comp_type, mono_input, mono_design)) {
189✔
562
                #ifdef DEBUG
563
                    fprintf(stderr, "Design \"%s\" skipped for comparison type '%s' because mono_input=%d and "
564
                        "mono_design=%d\n", current_design->name, comparison_name[comp_type], mono_input, mono_design);
565
                #endif
566
                continue;
63✔
567
            }
568

569
            #ifdef DEBUG
570
                fprintf(stderr, "CONSIDERING DESIGN ---- \"%s\" ---------------\n", current_design->name);
571
                fprintf(stderr, "    comparison_type = '%s'\n", comparison_name[comp_type]);
572
            #endif
573
            long hits = match_design(current_design, comp_type);
126✔
574
            #ifdef DEBUG
575
                fprintf(stderr, "Design \"%s\" scored %ld points\n", current_design->name, hits);
576
            #endif
577
            if (hits > maxhits) {
126✔
578
                maxhits = hits;
10✔
579
                result = current_design;
10✔
580
            }
581
        }
582
        if (maxhits > 2) {
9✔
583
            break;   /* do not try other comparison types if one found something */
5✔
584
        }
585
    }
586

587
    #ifdef DEBUG
588
        if (result) {
589
            fprintf(stderr, "CHOOSING \"%s\" design (%ld hits).\n", result->name, maxhits);
590
        }
591
        else {
592
            fprintf(stderr, "NO DESIGN FOUND WITH EVEN ONE HIT POINT!\n");
593
        }
594
    #endif
595
    return result;
5✔
596
}
597

598

599
/* vim: set cindent 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