• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In
Build has been canceled!

ascii-boxes / boxes / 6518013212

14 Oct 2023 01:37PM UTC coverage: 81.211% (-0.4%) from 81.608%
6518013212

push

github

tsjensen
remove

2349 of 3210 branches covered (0.0%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

3767 of 4321 relevant lines covered (87.18%)

7801.63 hits per line

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

92.76
/src/bxstring.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
 * The boxes-internal representation of strings.
18
 */
19

20
#include "config.h"
21

22
#include <stdarg.h>
23
#include <string.h>
24
#include <unictype.h>
25
#include <unistdio.h>
26
#include <unistr.h>
27
#include <uniwidth.h>
28

29
#include "bxstring.h"
30
#include "tools.h"
31
#include "unicode.h"
32

33

34

35
bxstr_t *bxs_from_ascii(char *pAscii)
1,194✔
36
{
37
    if (pAscii == NULL) {
1,194✔
38
        bx_fprintf(stderr, "%s: internal error: from_ascii() called with NULL\n", PROJECT);
1✔
39
        return NULL;
1✔
40
    }
41

42
    bxstr_t *result = (bxstr_t *) calloc(1, sizeof(bxstr_t));
1,193✔
43
    result->memory = u32_strconv_from_arg(pAscii, "ASCII");
1,193✔
44
    if (result->memory == NULL) {
1,193!
45
        BFREE(result);
×
46
        return NULL;
×
47
    }
48
    result->ascii = strdup(pAscii);
1,193✔
49

50
    size_t error_pos = 0;
1,193✔
51
    if (!bxs_valid_anywhere(result, &error_pos)) {
1,193✔
52
        ucs4_t c = result->memory[error_pos];
1✔
53
        bx_fprintf(stderr, "%s: illegal character '%lc' (%#010x) encountered in string\n", PROJECT, c, (int) c);
1✔
54
        bxs_free(result);
1✔
55
        return NULL;
1✔
56
    }
57

58
    size_t num_esc = 0;
1,192✔
59
    char *ascii_copy;
60
    size_t *map;
61
    result->num_chars_invisible = count_invisible_chars(result->memory, &num_esc, &ascii_copy, &(map));
1,192✔
62
    BFREE(ascii_copy);
1,192!
63

64
    result->num_chars = strlen(pAscii);
1,192✔
65
    result->num_columns = result->num_chars;
1,192✔
66
    result->num_chars_visible = result->num_chars - result->num_chars_invisible;
1,192✔
67

68
    result->indent = strspn(pAscii, " ");
1,192✔
69
    result->trailing = my_strrspn(pAscii, " ");
1,192✔
70

71
    result->first_char = calloc(result->num_chars_visible + 1, sizeof(size_t));
1,192✔
72
    result->visible_char = calloc(result->num_chars_visible + 1, sizeof(size_t));
1,192✔
73
    for (size_t i = 0; i <= result->num_chars_visible; i++) {
5,881✔
74
        result->first_char[i] = i;
4,689✔
75
        result->visible_char[i] = i;
4,689✔
76
    }
77

78
    return result;
1,192✔
79
}
80

81

82

83
bxstr_t *bxs_from_unicode(uint32_t *pInput)
19,360✔
84
{
85
    if (pInput == NULL) {
19,360✔
86
        bx_fprintf(stderr, "%s: internal error: bxs_from_unicode() called with NULL\n", PROJECT);
1✔
87
        return NULL;
1✔
88
    }
89

90
    bxstr_t *result = (bxstr_t *) calloc(1, sizeof(bxstr_t));
19,359✔
91
    result->memory = u32_strdup(pInput);
19,359✔
92
    result->num_chars = u32_strlen(pInput);
19,359✔
93
    size_t ascii_len = ((size_t) u32_strwidth(pInput, encoding)) + 1;
19,359✔
94
    result->ascii = (char *) calloc(ascii_len, sizeof(char));
19,359✔
95
    size_t map_size = 5;
19,359✔
96
    result->first_char = (size_t *) calloc(map_size, sizeof(size_t));
19,359✔
97
    result->visible_char = (size_t *) calloc(map_size, sizeof(size_t));
19,359✔
98
    char *ascii_ptr = result->ascii;
19,359✔
99

100
    const uint32_t *rest = pInput;
19,359✔
101
    size_t step_invis = 0;
19,359✔
102
    int indent_active = 1;
19,359✔
103
    size_t blank_streak = 0;
19,359✔
104
    int first_candidate = -1;
19,359✔
105
    int non_blank_encountered = 0;
19,359✔
106
    size_t idx = 0;
19,359✔
107

108
    for (ucs4_t c = pInput[0]; c != char_nul; c = rest[0]) {
612,373✔
109
        if (result->num_chars_visible >= map_size - 2) {
593,015✔
110
            map_size = map_size * 2 + 1;
26,954✔
111
            result->first_char = (size_t *) realloc(result->first_char, map_size * sizeof(size_t));
26,954✔
112
            result->visible_char = (size_t *) realloc(result->visible_char, map_size * sizeof(size_t));
26,954✔
113
        }
114

115
        if (!is_allowed_anywhere(c)) { /* currently used for config only, reconsider when using on input data */
593,015✔
116
            bx_fprintf(stderr, "%s: illegal character '%lc' (%#010x) encountered in string\n", PROJECT, c, (int) c);
1✔
117
            bxs_free(result);
1✔
118
            return NULL;
1✔
119
        }
120
        else if (c == char_esc) {
593,014✔
121
            if (is_csi_reset(rest)) {
8,024✔
122
                first_candidate = -1;
3,139✔
123
            }
124
            else {
125
                first_candidate = idx;
4,885✔
126
            }
127
        }
128
        else {
129
            int cols = 1;
584,990✔
130
            if (is_ascii_printable(c)) {
584,990✔
131
                *ascii_ptr = c & 0xff;
573,007✔
132
                ++ascii_ptr;
573,007✔
133
            }
134
            else if (c == char_tab) {
11,983✔
135
                *ascii_ptr = ' ';
55✔
136
                ++ascii_ptr;
55✔
137
            }
138
            else {
139
                cols = BMAX(0, uc_width(c, encoding));
11,928✔
140
                if (cols > 0) {
11,928✔
141
                    memset(ascii_ptr, (int) (uc_is_blank(c) ? ' ' : 'x'), cols);
2,974✔
142
                    ascii_ptr += cols;
2,974✔
143
                }
144
            }
145
            if (is_blank(c)) {
584,990✔
146
                if (indent_active) {
258,739✔
147
                    result->indent += cols;
26,802✔
148
                }
149
                blank_streak++;
258,739✔
150
            }
151
            result->num_columns += BMAX(0, cols);
584,990✔
152
            result->visible_char[result->num_chars_visible] = idx;
584,990✔
153
            result->first_char[result->num_chars_visible] = first_candidate < 0 ? idx : (size_t) first_candidate;
584,990✔
154
            first_candidate = -1;
584,990✔
155
        }
156

157
        if (!is_blank(c) && c != char_esc) {
593,014✔
158
            indent_active = 0;
326,251✔
159
            blank_streak = 0;
326,251✔
160
            non_blank_encountered = 1;
326,251✔
161
        }
162

163
        rest = advance_next32(rest, &step_invis);
593,014✔
164

165
        if (step_invis == 0) {
593,014✔
166
            result->num_chars_visible++;
584,990✔
167
            idx++;
584,990✔
168
        }
169
        else {
170
            result->num_chars_invisible += step_invis;
8,024✔
171
            idx += step_invis;
8,024✔
172
        }
173
    }
174

175
    *ascii_ptr = '\0';
19,358✔
176
    result->visible_char[result->num_chars_visible] = idx;  // both point to the terminator
19,358✔
177
    result->first_char[result->num_chars_visible] = idx;
19,358✔
178
    result->trailing = non_blank_encountered ? blank_streak : 0;
19,358✔
179
    return result;
19,358✔
180
}
181

182

183

184
bxstr_t *bxs_new_empty_string()
52✔
185
{
186
    return bxs_from_ascii("");
52✔
187
}
188

189

190

191
bxstr_t *bxs_strdup(bxstr_t *pString)
8,654✔
192
{
193
    if (pString == NULL) {
8,654✔
194
        return NULL;
1✔
195
    }
196
    bxstr_t *result = (bxstr_t *) calloc(1, sizeof(bxstr_t));
8,653✔
197
    if (result != NULL) {
8,653!
198
        result->memory = u32_strdup(pString->memory);
8,653✔
199
        result->ascii = strdup(pString->ascii);
8,653✔
200
        result->indent = pString->indent;
8,653✔
201
        result->num_columns = pString->num_columns;
8,653✔
202
        result->num_chars = pString->num_chars;
8,653✔
203
        result->num_chars_visible = pString->num_chars_visible;
8,653✔
204
        result->num_chars_invisible = pString->num_chars_invisible;
8,653✔
205
        result->trailing = pString->trailing;
8,653✔
206
        result->first_char = malloc((pString->num_chars_visible + 1) * sizeof(size_t));
8,653✔
207
        memcpy(result->first_char, pString->first_char, (pString->num_chars_visible + 1) * sizeof(size_t));
8,653✔
208
        result->visible_char = malloc((pString->num_chars_visible + 1) * sizeof(size_t));
8,653✔
209
        memcpy(result->visible_char, pString->visible_char, (pString->num_chars_visible + 1) * sizeof(size_t));
8,653✔
210
    }
211
    return result;
8,653✔
212
}
213

214

215

216
bxstr_t *bxs_trimdup(bxstr_t *pString, size_t start_idx, size_t end_idx, int trim_left)
742✔
217
{
218
    if (pString == NULL) {
742✔
219
        return NULL;
1✔
220
    }
221
    if (start_idx > pString->num_chars_visible) {
741✔
222
        /* a start_idx on the terminating NUL is a valid input */
223
        bx_fprintf(stderr, "%s: internal error: start_idx out of bounds in bxs_trimdup()\n", PROJECT);
1✔
224
        return NULL;
1✔
225
    }
226
    if (end_idx > pString->num_chars_visible) {
740✔
227
        bx_fprintf(stderr, "%s: internal error: end_idx out of bounds in bxs_trimdup()\n", PROJECT);
1✔
228
        return NULL;
1✔
229
    }
230
    if (end_idx < start_idx) {
739✔
231
        bx_fprintf(stderr, "%s: internal error: end_idx before start_idx in bxs_trimdup()\n", PROJECT);
1✔
232
        return NULL;
1✔
233
    }
234

235
    while (trim_left && start_idx < end_idx && uc_is_blank(pString->memory[pString->visible_char[start_idx]])) {
1,316✔
236
        start_idx++;
578✔
237
    }
238
    while (start_idx < end_idx && uc_is_blank(pString->memory[pString->visible_char[end_idx - 1]])) {
897✔
239
        end_idx--;
159✔
240
    }
241

242
    ucs4_t save = char_nul;
738✔
243
    if (end_idx < pString->num_chars_visible) {
738✔
244
        save = pString->memory[pString->first_char[end_idx]];
447✔
245
        set_char_at(pString->memory, pString->first_char[end_idx], char_nul);
447✔
246
    }
247

248
    bxstr_t *result = bxs_from_unicode(pString->memory + pString->first_char[start_idx]);
738✔
249
    if (end_idx < pString->num_chars_visible) {
738✔
250
        set_char_at(pString->memory, pString->first_char[end_idx], save);
447✔
251
    }
252
    return result;
738✔
253
}
254

255

256

257
bxstr_t *bxs_substr(bxstr_t *pString, size_t start_idx, size_t end_idx)
33✔
258
{
259
    if (pString == NULL) {
33!
260
        return NULL;
×
261
    }
262
    if (start_idx > pString->num_chars) {
33!
263
        start_idx = pString->num_chars;
×
264
    }
265
    if (end_idx > pString->num_chars) {
33!
266
        end_idx = pString->num_chars;
×
267
    }
268
    if (end_idx < start_idx) {
33!
269
        bx_fprintf(stderr, "%s: internal error: end_idx before start_idx in bxs_substr()\n", PROJECT);
×
270
        return NULL;
×
271
    }
272

273
    ucs4_t save = pString->memory[end_idx];
33✔
274
    set_char_at(pString->memory, end_idx, char_nul);
33✔
275
    bxstr_t *result = bxs_from_unicode(pString->memory + start_idx);
33✔
276
    set_char_at(pString->memory, end_idx, save);
33✔
277
    return result;
33✔
278
}
279

280

281

282
bxstr_t *bxs_strcat(bxstr_t *pString, uint32_t *pToAppend)
598✔
283
{
284
    if (pToAppend == NULL) {
598✔
285
        return bxs_strdup(pString);
1✔
286
    }
287
    size_t appened_num_chars = u32_strlen(pToAppend);
597✔
288
    if (appened_num_chars == 0) {
597✔
289
        return bxs_strdup(pString);
1✔
290
    }
291
    if (pString == NULL || pString->num_chars == 0) {
596✔
292
        return bxs_from_unicode(pToAppend);
2✔
293
    }
294

295
    size_t combined_num_chars = pString->num_chars + appened_num_chars;
594✔
296
    uint32_t *s = (uint32_t *) malloc((combined_num_chars + 1) * sizeof(uint32_t));
594✔
297
    memcpy(s, pString->memory, pString->num_chars * sizeof(uint32_t));
594✔
298
    memcpy(s + pString->num_chars, pToAppend, appened_num_chars * sizeof(uint32_t));
594✔
299
    set_char_at(s, combined_num_chars, char_nul);
594✔
300

301
    bxstr_t *result = bxs_from_unicode(s);
594✔
302
    BFREE(s);
594!
303
    return result;
594✔
304
}
305

306

307

308
bxstr_t *bxs_concat(size_t count, ...)
1,046✔
309
{
310
    if (count < 1) {
1,046✔
311
        return bxs_from_ascii("");
1✔
312
    }
313

314
    size_t total_len = 0;
1,045✔
315
    uint32_t *src;
316
    va_list va;
317

318
    va_start(va, count);
1,045✔
319
    for (size_t i = 0; i < count; i++) {
7,646✔
320
        src = va_arg(va, uint32_t *);
6,601✔
321
        if (src != NULL) {
6,601✔
322
            total_len += u32_strlen(src);
6,600✔
323
        } else {
324
            total_len += 6;  /* strlen("(NULL)") == 6 */
1✔
325
        }
326
    }
327
    va_end(va);
1,045✔
328

329
    uint32_t *utf32 = (uint32_t *) malloc((total_len + 1) * sizeof(uint32_t));
1,045✔
330
    char *format = repeat("%llU", count);   /* "%llU" stands for a UTF-32 string */
1,045✔
331

332
    va_start(va, count);
1,045✔
333
    u32_vsnprintf(utf32, total_len + 1, format, va);
1,045✔
334
    va_end(va);
1,045✔
335

336
    bxstr_t *result = bxs_from_unicode(utf32);
1,045✔
337
    BFREE(format);
1,045!
338
    BFREE(utf32);
1,045!
339
    return result;
1,045✔
340
}
341

342

343

344
uint32_t *bxs_strchr(bxstr_t *pString, ucs4_t c, int *cursor)
972✔
345
{
346
    uint32_t *result = NULL;
972✔
347
    if (pString != NULL && pString->num_chars_visible > 0) {
972✔
348
        size_t start_idx = cursor != NULL ? *cursor + 1 : 0;
970✔
349
        for (size_t i = start_idx; i < pString->num_chars_visible; i++) {
7,708✔
350
            if (pString->memory[pString->visible_char[i]] == c) {
7,389✔
351
                result = pString->memory + pString->visible_char[i];
651✔
352
                if (cursor != NULL) {
651✔
353
                    *cursor = (int) i;
419✔
354
                }
355
                break;
651✔
356
            }
357
        }
358
    }
359
    return result;
972✔
360
}
361

362

363

364
bxstr_t *bxs_cut_front(bxstr_t *pString, size_t n)
1,214✔
365
{
366
    if (pString == NULL) {
1,214✔
367
        return NULL;
1✔
368
    }
369
    if (n >= pString->num_chars_visible) {
1,213✔
370
        return bxs_new_empty_string();
33✔
371
    }
372
    if (n == 0) {
1,180✔
373
        return bxs_strdup(pString);
978✔
374
    }
375
    uint32_t *s = pString->memory + pString->first_char[n];
202✔
376
    return bxs_from_unicode(s);
202✔
377
}
378

379

380

381
uint32_t *bxs_first_char_ptr(bxstr_t *pString, size_t n)
25✔
382
{
383
    if (pString == NULL) {
25!
384
        return NULL;
×
385
    }
386
    if (n >= pString->num_chars_visible) {
25!
387
        return pString->memory + pString->first_char[pString->num_chars_visible];  /* pointer to NUL terminator */
×
388
    }
389
    return pString->memory + pString->first_char[n];
25✔
390
}
391

392

393

394
uint32_t *bxs_last_char_ptr(bxstr_t *pString)
5✔
395
{
396
    if (pString == NULL) {
5✔
397
        return NULL;
1✔
398
    }
399
    return pString->memory + pString->first_char[pString->num_chars_visible];
4✔
400
}
401

402

403

404
uint32_t *bxs_unindent_ptr(bxstr_t *pString)
6,450✔
405
{
406
    if (pString == NULL) {
6,450!
407
        return NULL;
×
408
    }
409
    return pString->memory + pString->first_char[pString->indent];
6,450✔
410
}
411

412

413

414
bxstr_t *bxs_trim(bxstr_t *pString)
17✔
415
{
416
    if (pString == NULL) {
17✔
417
        return NULL;
1✔
418
    }
419
    if (pString->indent == 0 && pString->trailing == 0) {
16!
420
        return bxs_strdup(pString);
1✔
421
    }
422
    if (pString->indent + pString->trailing == pString->num_chars_visible) {
15✔
423
        return bxs_new_empty_string();
1✔
424
    }
425

426
    uint32_t *e = u32_strdup(pString->memory);
14✔
427
    set_char_at(e, pString->first_char[pString->num_chars_visible - pString->trailing], char_nul);
14✔
428
    uint32_t *s = e + pString->first_char[pString->indent];
14✔
429
    bxstr_t *result = bxs_from_unicode(s);
14✔
430
    BFREE(e);
14!
431
    return result;
14✔
432
}
433

434

435

436
uint32_t *bxs_ltrim(bxstr_t *pString, size_t max)
5✔
437
{
438
    if (pString == NULL) {
5✔
439
        return NULL;
1✔
440
    }
441

442
    size_t num_trimmed = BMIN(max, pString->num_chars_visible);
4✔
443
    for (size_t i = 0; i < max; i++) {
14✔
444
        if (!is_blank(pString->memory[pString->visible_char[i]])) {
12✔
445
            num_trimmed = i;
2✔
446
            break;
2✔
447
        }
448
    }
449
    return u32_strdup(pString->memory + pString->first_char[num_trimmed]);
4✔
450
}
451

452

453

454
bxstr_t *bxs_rtrim(bxstr_t *pString)
1,703✔
455
{
456
    if (pString == NULL) {
1,703✔
457
        return NULL;
1✔
458
    }
459
    if (pString->trailing == 0) {
1,702✔
460
        return bxs_strdup(pString);
1,573✔
461
    }
462

463
    uint32_t *s = u32_strdup(pString->memory);
129✔
464
    set_char_at(s, pString->first_char[pString->num_chars_visible - pString->trailing], char_nul);
129✔
465
    bxstr_t *result = bxs_from_unicode(s);
129✔
466
    BFREE(s);
129!
467
    return result;
129✔
468
}
469

470

471

472
bxstr_t *bxs_prepend_spaces(bxstr_t *pString, size_t n)
33✔
473
{
474
    bxstr_t *result = NULL;
33✔
475
    if (n == 0) {
33✔
476
        result = bxs_strdup(pString);
25✔
477
    }
478
    else if (pString == NULL) {
8!
479
        uint32_t *s = u32_nspaces(n);
×
480
        result = bxs_from_unicode(s);
×
481
        BFREE(s);
×
482
    }
483
    else if (n > 0) {
8!
484
        result = (bxstr_t *) calloc(1, sizeof(bxstr_t));
8✔
485

486
        result->memory = (uint32_t *) malloc((pString->num_chars + n + 1) * sizeof(uint32_t));
8✔
487
        uint32_t *s = u32_nspaces(n);
8✔
488
        u32_cpy(result->memory, s, n);
8✔
489
        BFREE(s);
8!
490
        u32_cpy(result->memory + n, pString->memory, pString->num_chars);
8✔
491
        set_char_at(result->memory, pString->num_chars + n, char_nul);
8✔
492

493
        result->ascii = (char *) malloc((pString->num_columns + n + 1) * sizeof(char));
8✔
494
        memset(result->ascii, ' ', n);
8✔
495
        strcpy(result->ascii + n, pString->ascii);
8✔
496

497
        result->indent = pString->indent + n;
8✔
498
        result->num_columns = pString->num_columns + n;
8✔
499
        result->num_chars = pString->num_chars + n;
8✔
500
        result->num_chars_visible = pString->num_chars_visible + n;
8✔
501
        result->num_chars_invisible = pString->num_chars_invisible;
8✔
502
        result->trailing = pString->trailing;
8✔
503

504
        result->first_char = (size_t *) malloc((pString->num_chars_visible + n + 1) * sizeof(size_t));
8✔
505
        result->visible_char = (size_t *) malloc((pString->num_chars_visible + n + 1) * sizeof(size_t));
8✔
506
        for (size_t i=0; i < n; i++) {
36✔
507
            result->first_char[i] = i;
28✔
508
            result->visible_char[i] = i;
28✔
509
        }
510
        for (size_t i=0; i <= pString->num_chars_visible; i++) {
169✔
511
            result->first_char[i + n] = pString->first_char[i] + n;
161✔
512
            result->visible_char[i + n] = pString->visible_char[i] + n;
161✔
513
        }
514
    }
515
    return result;
33✔
516
}
517

518

519

520
void bxs_append_spaces(bxstr_t *pString, size_t n)
3✔
521
{
522
    if (pString == NULL || n == 0) {
3✔
523
        return;
2✔
524
    }
525

526
    pString->memory = (uint32_t *) realloc(pString->memory, (pString->num_chars + n + 1) * sizeof(uint32_t));
1✔
527
    u32_set(pString->memory + pString->num_chars, char_space, n);
1✔
528
    set_char_at(pString->memory, pString->num_chars + n, char_nul);
1✔
529

530
    pString->ascii = (char *) realloc(pString->ascii, (pString->num_columns + n + 1) * sizeof(char));
1✔
531
    memset(pString->ascii + pString->num_columns, ' ', n);
1✔
532
    pString->ascii[pString->num_columns + n] = '\0';
1✔
533

534
    pString->first_char =
1✔
535
            (size_t *) realloc(pString->first_char, (pString->num_chars_visible + n + 1) * sizeof(size_t));
1✔
536
    pString->visible_char =
1✔
537
            (size_t *) realloc(pString->visible_char, (pString->num_chars_visible + n + 1) * sizeof(size_t));
1✔
538
    for (size_t i = 0; i <= n; i++) {
5✔
539
        pString->first_char[pString->num_chars_visible + i] = pString->num_chars + i;
4✔
540
        pString->visible_char[pString->num_chars_visible + i] = pString->num_chars + i;
4✔
541
    }
542

543
    pString->num_chars += n;
1✔
544
    pString->num_chars_visible += n;
1✔
545
    pString->num_columns += n;
1✔
546
    pString->trailing += n;
1✔
547
}
548

549

550

551
char *bxs_to_output(bxstr_t *pString)
1,258✔
552
{
553
    if (pString == NULL) {
1,258✔
554
        return strdup("NULL");
1✔
555
    }
556

557
    if (color_output_enabled) {
1,257✔
558
        return u32_strconv_to_output(pString->memory);
1,256✔
559
    }
560

561
    uint32_t *vis = bxs_filter_visible(pString);
1✔
562
    char *result = u32_strconv_to_output(vis);
1✔
563
    BFREE(vis);
1!
564
    return result;
1✔
565
}
566

567

568

569
int bxs_is_empty(bxstr_t *pString)
5,809✔
570
{
571
    if (pString == NULL) {
5,809✔
572
        return 1;
2✔
573
    }
574
    return pString->num_chars > 0 ? 0 : 1;
5,807✔
575
}
576

577

578

579
int bxs_is_blank(bxstr_t *pString)
5,467✔
580
{
581
    if (bxs_is_empty(pString)) {
5,467✔
582
        return 1;
18✔
583
    }
584
    for (size_t i = 0; i < pString->num_chars_visible; i++) {
11,270✔
585
        ucs4_t c = pString->memory[pString->visible_char[i]];
10,016✔
586
        if (c != char_tab && c != char_cr && !uc_is_blank(c)) {
10,016!
587
            return 0;
4,195✔
588
        }
589
    }
590
    return 1;
1,254✔
591
}
592

593

594

595
int bxs_is_visible_char(bxstr_t *pString, size_t idx)
10✔
596
{
597
    int result = 0;
10✔
598
    if (pString != NULL) {
10✔
599
        for (size_t i = 0; i <= idx && i < pString->num_chars_visible; i++) {
24!
600
            if (pString->visible_char[i] == idx) {
20✔
601
                result = 1;
3✔
602
                break;
3✔
603
            }
604
            else if (pString->visible_char[i] > idx) {
17✔
605
                break;
2✔
606
            }
607
        }
608
    }
609
    return result;
10✔
610
}
611

612

613

614
uint32_t *bxs_filter_visible(bxstr_t *pString)
28✔
615
{
616
    uint32_t *result = NULL;
28✔
617
    if (pString != NULL) {
28✔
618
        if (pString->num_chars_invisible == 0) {
27✔
619
            result = u32_strdup(pString->memory);
18✔
620
        }
621
        else {
622
            result = (uint32_t *) calloc(pString->num_chars_visible + 1, sizeof(uint32_t));
9✔
623
            for (size_t i = 0; i < pString->num_chars_visible; i++) {
220✔
624
                set_char_at(result, i, pString->memory[pString->visible_char[i]]);
211✔
625
            }
626
            set_char_at(result, pString->num_chars_visible, char_nul);
9✔
627
        }
628
    }
629
    return result;
28✔
630
}
631

632

633

634
int bxs_strcmp(bxstr_t *s1, bxstr_t *s2)
19✔
635
{
636
    if (s1 == NULL) {
19✔
637
        if (s2 == NULL) {
2✔
638
            return 0;
1✔
639
        }
640
        else {
641
            return 1;
1✔
642
        }
643
    }
644
    if (s2 == NULL) {
17✔
645
        return -1;
1✔
646
    }
647
    return u32_strcmp(s1->memory, s2->memory);
16✔
648
}
649

650

651

652
static int bxs_valid_in_context(bxstr_t *pString, size_t *error_pos, int (*predicate)(const ucs4_t))
7,294✔
653
{
654
    if (pString == NULL) {
7,294✔
655
        if (error_pos != NULL) {
2✔
656
            *error_pos = 0;
1✔
657
        }
658
        return 0;   /* invalid */
2✔
659
    }
660

661
    for (size_t i = 0; pString->memory[i] != char_nul; i++) {
126,896✔
662
        if ((*predicate)(pString->memory[i]) == 0) {
119,606✔
663
            if (error_pos != NULL) {
2✔
664
                *error_pos = i;
1✔
665
            }
666
            return 0;   /* invalid */
2✔
667
        }
668
    }
669

670
    return 1;   /* valid */
7,290✔
671
}
672

673

674

675
int bxs_valid_anywhere(bxstr_t *pString, size_t *error_pos)
1,196✔
676
{
677
    return bxs_valid_in_context(pString, error_pos, &is_allowed_anywhere);
1,196✔
678
}
679

680

681

682
int bxs_valid_in_shape(bxstr_t *pString, size_t *error_pos)
4,631✔
683
{
684
    return pString->num_chars_visible > 0 && bxs_valid_in_context(pString, error_pos, &is_allowed_in_shape);
4,631!
685
}
686

687

688

689
int bxs_valid_in_sample(bxstr_t *pString, size_t *error_pos)
328✔
690
{
691
    return pString->num_chars_visible > 0 && bxs_valid_in_context(pString, error_pos, &is_allowed_in_sample);
328!
692
}
693

694

695

696
int bxs_valid_in_filename(bxstr_t *pString, size_t *error_pos)
15✔
697
{
698
    return pString->num_chars_visible > 0 && pString->num_chars_invisible == 0
14✔
699
            && bxs_valid_in_context(pString, error_pos, &is_allowed_in_filename);
29!
700
}
701

702

703

704
int bxs_valid_in_kv_string(bxstr_t *pString, size_t *error_pos)
1,126✔
705
{
706
    return bxs_valid_in_context(pString, error_pos, &is_allowed_in_kv_string);
1,126✔
707
}
708

709

710

711
void bxs_free(bxstr_t *pString)
6,398✔
712
{
713
    if (pString != NULL) {
6,398✔
714
        BFREE(pString->memory);
6,361✔
715
        BFREE(pString->ascii);
6,361✔
716
        BFREE(pString->first_char);
6,361✔
717
        BFREE(pString->visible_char);
6,361✔
718
        BFREE(pString);
6,361!
719
    }
720
}
6,398✔
721

722

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

© 2025 Coveralls, Inc