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

ascii-boxes / boxes / 6683464098

29 Oct 2023 12:48PM UTC coverage: 83.972%. Remained the same
6683464098

push

github

tsjensen
Test and fix handling of line comment removal

2421 of 3166 branches covered (0.0%)

Branch coverage included in aggregate %.

48 of 48 new or added lines in 2 files covered. (100.0%)

3803 of 4246 relevant lines covered (89.57%)

11500.46 hits per line

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

92.52
/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()
20✔
62
{
63
    int result = 1;
20✔
64
    for (size_t line_no = 0; line_no < input.num_lines; line_no++) {
110✔
65
        if (input.lines[line_no].text->num_chars_invisible > 0) {
103✔
66
            result = 0;
13✔
67
            break;
13✔
68
        }
69
    }
70
    #ifdef DEBUG
71
        fprintf(stderr, "Input is %s\n", result ? "mono" : "potentially colored");
72
    #endif
73
    return result;
20✔
74
}
75

76

77

78
int design_is_mono(design_t *design)
276✔
79
{
80
    for (shape_t scnt = 0; scnt < NUM_SHAPES; ++scnt) {
4,332✔
81
        if (isempty(design->shape + scnt)) {
4,079✔
82
            continue;
1,548✔
83
        }
84
        for (size_t line_no = 0; line_no < design->shape[scnt].height; line_no++) {
9,373✔
85
            bxstr_t *shape_line = design->shape[scnt].mbcs[line_no];
6,865✔
86
            if (shape_line->num_chars_invisible > 0) {
6,865✔
87
                #ifdef DEBUG
88
                    fprintf(stderr, "Design is potentially colored\n");
89
                #endif
90
                return 0;
23✔
91
            }
92
        }
93
    }
94
    #ifdef DEBUG
95
        fprintf(stderr, "Design is mono\n");
96
    #endif
97
    return 1;
253✔
98
}
99

100

101

102
int comp_type_is_viable(comparison_t comp_type, int mono_input, int mono_design)
464✔
103
{
104
    int result = 1;
464✔
105
    if ((comp_type == literal && mono_input != mono_design)
464✔
106
            || (comp_type == ignore_invisible_input && (mono_input || !mono_design))
294✔
107
            || (comp_type == ignore_invisible_shape && (!mono_input || mono_design))
259!
108
            || (comp_type == ignore_invisible_all && (mono_input || mono_design)))
242!
109
    {
110
        result = 0;
222✔
111
    }
112
    return result;
464✔
113
}
114

115

116

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

121
    for (size_t j = 0; j < NUM_SIDES; ++j) {
660✔
122
        result[j] = empty_side(current_design->shape, j);
528✔
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;
132✔
129
}
130

131

132

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

145

146

147
uint32_t *prepare_comp_shape(
4,093✔
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];
4,093✔
151
    if (shape_line_idx >= shape_def.height) {
4,093!
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];
4,093✔
158
    uint32_t *result = NULL;
4,093✔
159

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

168
        if (trim_right && shape_line->trailing > 0) {
73✔
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);
4,020✔
174

175
        if (trim_right && shape_line->trailing > 0) {
4,020✔
176
            size_t x = shape_line->num_chars_visible - (trim_left ? shape_line->indent : 0) - shape_line->trailing;
220✔
177
            set_char_at(result, shape_line->first_char[x], char_nul);
220✔
178
        }
179
    }
180
    return result;
4,093✔
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,330✔
186
    size_t *out_indent, size_t *out_trailing)
187
{
188
    #ifdef DEBUG
189
        fprintf(stderr, "prepare_comp_input(%d, %s, %s, %d, %p, %p)", (int) input_line_idx,
190
                trim_left ? "true" : "false", comparison_name[comp_type], (int) offset_right, out_indent, out_trailing);
191
    #endif
192
    if (input_line_idx >= input.num_lines) {
8,330!
193
        bx_fprintf(stderr, "%s: prepare_comp_input(%d, %d, %s, %d): Index out of bounds\n", PROJECT,
×
194
                (int) input_line_idx, trim_left, comparison_name[comp_type], (int) offset_right);
195
        #ifdef DEBUG
196
            fprintf(stderr, " -> (null)\n");
197
        #endif
198
        return NULL;
×
199
    }
200
    bxstr_t *input_line = input.lines[input_line_idx].text;
8,330✔
201

202
    uint32_t *result = NULL;
8,330✔
203
    if (comp_type == ignore_invisible_input || comp_type == ignore_invisible_all) {
8,330✔
204
        if (offset_right > 0) {
1,846✔
205
            uint32_t *visible = get_visible_text(input.lines + input_line_idx);
370✔
206
            uint32_t *p = visible + input_line->num_chars_visible - input_line->trailing - offset_right;
370✔
207
            if (p >= visible) {
370!
208
                result = p;
370✔
209
                if (out_indent != NULL) {
370!
210
                    *out_indent = BMAX(input_line->indent - (size_t) (p - visible), (size_t) 0);
×
211
                }
212
            }
213
        }
214
        else {
215
            size_t ltrim = trim_left ? input_line->indent : 0;
1,476✔
216
            result = get_visible_text(input.lines + input_line_idx) + ltrim;
1,476✔
217
            if (out_indent != NULL) {
1,476✔
218
                *out_indent = trim_left ? 0 : input_line->indent;
15!
219
            }
220
        }
221
        if (out_trailing != NULL) {
1,846✔
222
            *out_trailing = input_line->trailing;
15✔
223
        }
224
    }
225
    else {
226
        if (offset_right > 0) {
6,484✔
227
            int idx = (int) input_line->first_char[input_line->num_chars_visible - input_line->trailing]
2,058✔
228
                        - offset_right;
2,058✔
229
            if (idx >= 0) {
2,058✔
230
                result = input_line->memory + idx;
2,055✔
231
                if (out_indent != NULL) {
2,055!
232
                    *out_indent = BMAX(input_line->first_char[input_line->indent] - (size_t) idx, (size_t) 0);
×
233
                }
234
            }
235
        }
236
        else {
237
            result = trim_left ? bxs_unindent_ptr(input_line) : input_line->memory;
4,426✔
238
            if (out_indent != NULL) {
4,426✔
239
                *out_indent = trim_left ? 0 : input_line->first_char[input_line->indent];
44!
240
            }
241
        }
242
        if (out_trailing != NULL) {
6,484✔
243
            *out_trailing = input_line->num_chars
44✔
244
                    - input_line->first_char[input_line->num_chars_visible - input_line->trailing];
44✔
245
        }
246
    }
247
    #ifdef DEBUG
248
        char *out_result = u32_strconv_to_output(result);
249
        fprintf(stderr, " -> \"%s\"\n", out_result);
250
        BFREE(out_result);
251
    #endif
252
    return result;
8,330✔
253
}
254

255

256

257
/**
258
 * Try and find west corner shapes. Every non-empty shape line is searched for on every input line. A hit is generated
259
 * whenever a match is found.
260
 * @param current_design the current design to check
261
 * @param comp_type the comparison type (how to compare colored strings)
262
 * @param empty information on which box sides are empty in that design
263
 * @param corner which west corner to search for
264
 * @return the number of hits for this corner
265
 */
266
static size_t find_west_corner(design_t *current_design, comparison_t comp_type, int *empty, shape_t corner)
264✔
267
{
268
    size_t hits = 0;
264✔
269
    if (empty[BLEF] || (empty[BTOP] && corner == NW) || (empty[BBOT] && corner == SW)) {
264!
270
        return hits;
42✔
271
    }
272

273
    for (size_t j = 0; j < current_design->shape[corner].height; ++j) {
882✔
274
        bxstr_t *shape_line = current_design->shape[corner].mbcs[j];
660✔
275
        if (bxs_is_blank(shape_line)) {
660✔
276
            continue;
320✔
277
        }
278

279
        uint32_t *shape_relevant = prepare_comp_shape(current_design, corner, j, comp_type, 1, 0);
340✔
280
        size_t length_relevant = u32_strlen(shape_relevant);
340✔
281

282
        for (size_t k = 0; k < current_design->shape[corner].height; ++k) {
1,279✔
283
            size_t a = k;
994✔
284
            if (corner == SW) {
994✔
285
                a += input.num_lines - current_design->shape[corner].height;
444✔
286
            }
287
            if (a >= input.num_lines) {
994✔
288
                break;
55✔
289
            }
290

291
            uint32_t *input_relevant = prepare_comp_input(a, 1, comp_type, 0, NULL, NULL);
939✔
292
            if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
939✔
293
                ++hits; /* CHECK more hit points for longer matches, or simple boxes might match too easily */
66✔
294
            }
295
        }
296
        BFREE(shape_relevant);
340!
297
    }
298

299
    #ifdef DEBUG
300
        fprintf(stderr, "Checking %s corner produced %d hits.\n", shape_name[corner], (int) hits);
301
    #endif
302
    return hits;
222✔
303
}
304

305

306

307
/**
308
 * Try and find east corner shapes. Every non-empty shape line is searched for on every input line. A hit is generated
309
 * whenever a match is found.
310
 * @param current_design the current design to check
311
 * @param comp_type the comparison type (how to compare colored strings)
312
 * @param empty information on which box sides are empty in that design
313
 * @param corner which west corner to search for
314
 * @return the number of hits for this corner
315
 */
316
static size_t find_east_corner(design_t *current_design, comparison_t comp_type, int *empty, shape_t corner)
264✔
317
{
318
    size_t hits = 0;
264✔
319
    if (empty[BRIG] || (empty[BTOP] && corner == NE) || (empty[BBOT] && corner == SE)) {
264!
320
        #ifdef DEBUG
321
            fprintf(stderr, "Checking %s corner produced %d hits.\n", shape_name[corner], (int) hits);
322
        #endif
323
        return hits;
56✔
324
    }
325

326
    for (size_t j = 0; j < current_design->shape[corner].height; ++j) {
854✔
327
        bxstr_t *shape_line = current_design->shape[corner].mbcs[j];
646✔
328
        if (bxs_is_blank(shape_line)) {
646✔
329
            continue;
292✔
330
        }
331

332
        uint32_t *shape_relevant = prepare_comp_shape(current_design, corner, j, comp_type, 0, 1);
354✔
333
        size_t length_relevant = u32_strlen(shape_relevant);
354✔
334

335
        for (size_t k = 0; k < current_design->shape[corner].height; ++k) {
1,415✔
336
            size_t a = k;
1,132✔
337
            if (corner == SE) {
1,132✔
338
                a += input.num_lines - current_design->shape[corner].height;
584✔
339
            }
340
            if (a >= input.num_lines) {
1,132✔
341
                break;
71✔
342
            }
343

344
            uint32_t *input_relevant = prepare_comp_input(a, 0, comp_type, length_relevant, NULL, NULL);
1,061✔
345
            if (input_relevant && (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0)) {
1,061!
346
                ++hits; /* CHECK more hit points for longer matches, or simple boxes might match too easily */
46✔
347
            }
348
        }
349
        BFREE(shape_relevant);
354!
350
    }
351

352
    #ifdef DEBUG
353
        fprintf(stderr, "Checking %s corner produced %d hits.\n", shape_name[corner], (int) hits);
354
    #endif
355
    return hits;
208✔
356
}
357

358

359

360
/**
361
 * Try and find a horizontal shape between the box corners. Every non-empty shape line is searched for on every input
362
 * line. Elastic shapes must occur twice in an uninterrupted row to generate a hit.
363
 * @param current_design the current design to check
364
 * @param comp_type the comparison type (how to compare colored strings)
365
 * @param empty information on which box sides are empty in that design
366
 * @param hshape which horizontal shape to search for
367
 * @return the number of hits for this horizontal shape
368
 */
369
static size_t find_horizontal_shape(design_t *current_design, comparison_t comp_type, int *empty, shape_t hshape)
792✔
370
{
371
    size_t hits = 0;
792✔
372
    if (empty[BTOP] || empty[BBOT]) {
792!
373
        /* horizontal box part is empty */
374
        #ifdef DEBUG
375
            fprintf(stderr, "Checking %-3s shape produced %d hits.\n", shape_name[hshape], (int) hits);
376
        #endif
377
        return hits;
132✔
378
    }
379

380
    for (size_t j = 0; j < current_design->shape[hshape].height; ++j) {
2,214✔
381
        bxstr_t *shape_line = current_design->shape[hshape].mbcs[j];
1,554✔
382
        if (bxs_is_blank(shape_line)) {
1,554✔
383
            continue;
666✔
384
        }
385

386
        uint32_t *shape_relevant = prepare_comp_shape(current_design, hshape, j, comp_type, 0, 0);
888✔
387
        size_t length_relevant = u32_strlen(shape_relevant);
888✔
388

389
        for (size_t k = 0; k < current_design->shape[hshape].height; ++k) {
4,365✔
390
            size_t a = k;
3,741✔
391
            if (hshape >= SSE && hshape <= SSW) {
3,741!
392
                a += input.num_lines - current_design->shape[hshape].height;
1,512✔
393
            }
394
            if (a >= input.num_lines) {
3,741✔
395
                break;
264✔
396
            }
397

398
            uint32_t *input_relevant = prepare_comp_input(a, 1, comp_type, 0, NULL, NULL);
3,477✔
399
                                       /* CHECK this eats blank NW corners */
400
            uint32_t *p = u32_strstr(input_relevant, shape_relevant);
3,477✔
401
            if (p) {
3,477✔
402
                if (current_design->shape[hshape].elastic) {
422✔
403
                    p += length_relevant;
344✔
404
                    if (p - input_relevant >= (long) u32_strlen(input_relevant)) {
344!
405
                        continue;
×
406
                    }
407
                    if (u32_strncmp(p, shape_relevant, length_relevant) == 0) {
344✔
408
                        ++hits;
203✔
409
                    }
410
                }
411
                else {
412
                    ++hits;
78✔
413
                }
414
            }
415
        }
416
        BFREE(shape_relevant);
888!
417
    }
418

419
    #ifdef DEBUG
420
        fprintf(stderr, "Checking %-3s shape produced %d hits.\n", shape_name[hshape], (int) hits);
421
    #endif
422
    return hits;
660✔
423
}
424

425

426

427
/**
428
 * Iterate over all input lines except for potential top and bottom box parts. Check if west line starts match a
429
 * non-empty shape line. If so, generate a hit.
430
 * @param current_design the current design to check
431
 * @param comp_type the comparison type (how to compare colored strings)
432
 * @param empty information on which box sides are empty in that design
433
 * @param vshape which vertical shape to search for
434
 * @return the number of hits for this vertical shape
435
 */
436
static size_t find_vertical_west(design_t *current_design, comparison_t comp_type, int *empty, shape_t vshape)
396✔
437
{
438
    size_t hits = 0;
396✔
439
    if (((empty[BTOP] ? 0 : current_design->shape[NW].height) + (empty[BBOT] ? 0 : current_design->shape[SW].height))
396✔
440
            >= input.num_lines) {
396✔
441
        /* no hits */
442
    }
443
    else if (isempty(current_design->shape + vshape)) {
309✔
444
        /* no hits */
445
    }
446
    else {
447
        for (size_t k = empty[BTOP] ? 0 : current_design->shape[NW].height;
125✔
448
                k < input.num_lines - (empty[BBOT] ? 0 : current_design->shape[SW].height); ++k)
1,457✔
449
        {
450
            uint32_t *input_relevant = prepare_comp_input(k, 1, comp_type, 0, NULL, NULL);
1,332✔
451

452
            for (size_t j = 0; j < current_design->shape[vshape].height; ++j) {
3,056✔
453
                bxstr_t *shape_line = current_design->shape[vshape].mbcs[j];
1,874✔
454
                if (bxs_is_blank(shape_line)) {
1,874✔
455
                    continue;
25✔
456
                }
457

458
                uint32_t *shape_relevant = prepare_comp_shape(current_design, vshape, j, comp_type, 1, 0);
1,849✔
459
                size_t length_relevant = u32_strlen(shape_relevant);
1,849✔
460

461
                if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
1,849✔
462
                    ++hits;
150✔
463
                    break;
150✔
464
                }
465
                BFREE(shape_relevant);
1,699!
466
            }
467
        }
468
    }
469

470
    #ifdef DEBUG
471
        fprintf(stderr, "Checking %-3s shape produced %d hits.\n", shape_name[vshape], (int) hits);
472
    #endif
473
    return hits;
396✔
474
}
475

476

477

478
/**
479
 * Iterate over all input lines except for potential top and bottom box parts. Check if east line ends match a
480
 * non-empty shape line. If so, generate a hit.
481
 * @param current_design the current design to check
482
 * @param comp_type the comparison type (how to compare colored strings)
483
 * @param empty information on which box sides are empty in that design
484
 * @param vshape which vertical shape to search for
485
 * @return the number of hits for this vertical shape
486
 */
487
static size_t find_vertical_east(design_t *current_design, comparison_t comp_type, int *empty, shape_t vshape)
396✔
488
{
489
    size_t hits = 0;
396✔
490
    if (((empty[BTOP] ? 0 : current_design->shape[NW].height) + (empty[BBOT] ? 0 : current_design->shape[SW].height))
396✔
491
            >= input.num_lines) {
396✔
492
        /* no hits */
493
    }
494
    else if (isempty(current_design->shape + vshape)) {
309✔
495
        /* no hits */
496
    }
497
    else {
498
        for (size_t j = 0; j < current_design->shape[vshape].height; ++j) {
304✔
499
            bxstr_t *shape_line = current_design->shape[vshape].mbcs[j];
179✔
500
            if (bxs_is_blank(shape_line)) {
179✔
501
                continue;
26✔
502
            }
503

504
            uint32_t *shape_relevant = prepare_comp_shape(current_design, vshape, j, comp_type, 1, 1);
153✔
505
            size_t length_relevant = u32_strlen(shape_relevant);
153✔
506

507
            for (size_t k = empty[BTOP] ? 0 : current_design->shape[NW].height;
153✔
508
                    k < input.num_lines - (empty[BBOT] ? 0 : current_design->shape[SW].height); ++k)
1,486✔
509
            {
510
                uint32_t *input_relevant = prepare_comp_input(k, 0, comp_type, length_relevant, NULL, NULL);
1,367✔
511
                if (input_relevant != NULL && u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
1,367✔
512
                    ++hits;
34✔
513
                    break;
34✔
514
                }
515
            }
516
            BFREE(shape_relevant);
153!
517
        }
518
    }
519

520
    #ifdef DEBUG
521
        fprintf(stderr, "Checking %-3s shape produced %d hits.\n", shape_name[vshape], (int) hits);
522
    #endif
523
    return hits;
396✔
524
}
525

526

527

528
static long match_design(design_t *current_design, comparison_t comp_type)
132✔
529
{
530
    int *empty = determine_empty_sides(current_design);
132✔
531
    long hits = 0;
132✔
532

533
    for (shape_t scnt = 0; scnt < NUM_SHAPES; ++scnt) {
2,244✔
534
        switch (scnt) {
2,112!
535
            case NW:
264✔
536
            case SW:
537
                hits += find_west_corner(current_design, comp_type, empty, scnt);
264✔
538
                break;
264✔
539

540
            case NE:
264✔
541
            case SE:
542
                hits += find_east_corner(current_design, comp_type, empty, scnt);
264✔
543
                break;
264✔
544

545
            case NNW: case N: case NNE:
792✔
546
            case SSE: case S: case SSW:
547
                hits += find_horizontal_shape(current_design, comp_type, empty, scnt);
792✔
548
                break;
792✔
549

550
            case ENE: case E: case ESE:
396✔
551
                hits += find_vertical_east(current_design, comp_type, empty, scnt);
396✔
552
                break;
396✔
553

554
            case WSW: case W: case WNW:
396✔
555
                hits += find_vertical_west(current_design, comp_type, empty, scnt);
396✔
556
                break;
396✔
557

558
            default:
×
559
                fprintf(stderr, "%s: internal error (scnt=%d)\n", PROJECT, (int) scnt);
×
560
                return 0;
×
561
        }
562
    }
563

564
    BFREE(empty);
132!
565
    return hits;
132✔
566
}
567

568

569

570
design_t *autodetect_design()
6✔
571
{
572
    design_t *current_design;           /* ptr to currently tested design */
573
    long maxhits = 0;                   /* maximum no. of hits so far */
6✔
574
    design_t *result = NULL;            /* ptr to design with the most hits */
6✔
575
    int mono_input = input_is_mono();
6✔
576
    (void) comparison_name;             /* used only in debug statements */
577

578
    for (comparison_t comp_type = 0; comp_type < NUM_COMPARISON_TYPES; comp_type++) {
10!
579
        current_design = designs;
10✔
580
        for (size_t dcnt = 0; ((int) dcnt) < num_designs; ++dcnt, ++current_design) {
272✔
581
            int mono_design = design_is_mono(current_design);
262✔
582
            if (!comp_type_is_viable(comp_type, mono_input, mono_design)) {
262✔
583
                #ifdef DEBUG
584
                    fprintf(stderr, "Design \"%s\" skipped for comparison type '%s' because mono_input=%d and "
585
                        "mono_design=%d\n", current_design->name, comparison_name[comp_type], mono_input, mono_design);
586
                #endif
587
                continue;
130✔
588
            }
589

590
            #ifdef DEBUG
591
                fprintf(stderr, "CONSIDERING DESIGN ---- \"%s\" ---------------\n", current_design->name);
592
                fprintf(stderr, "    comparison_type = %s\n", comparison_name[comp_type]);
593
            #endif
594
            long hits = match_design(current_design, comp_type);
132✔
595
            #ifdef DEBUG
596
                fprintf(stderr, "Design \"%s\" scored %ld points\n", current_design->name, hits);
597
            #endif
598
            if (hits > maxhits) {
132✔
599
                maxhits = hits;
11✔
600
                result = current_design;
11✔
601
            }
602
        }
603
        if (maxhits > 2) {
10✔
604
            break;   /* do not try other comparison types if one found something */
6✔
605
        }
606
    }
607

608
    #ifdef DEBUG
609
        if (result) {
610
            fprintf(stderr, "CHOOSING \"%s\" design (%ld hits).\n", result->name, maxhits);
611
        }
612
        else {
613
            fprintf(stderr, "NO DESIGN FOUND WITH EVEN ONE HIT POINT!\n");
614
        }
615
    #endif
616
    return result;
6✔
617
}
618

619

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