Coverage Report

Created: 2026-11-12 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/htslib/kstring.c
Line
Count
Source
1
/* The MIT License
2
3
   Copyright (C) 2011 by Attractive Chaos <attractor@live.co.uk>
4
   Copyright (C) 2013-2018, 2020-2021, 2023, 2025-2026 Genome Research Ltd.
5
6
   Permission is hereby granted, free of charge, to any person obtaining
7
   a copy of this software and associated documentation files (the
8
   "Software"), to deal in the Software without restriction, including
9
   without limitation the rights to use, copy, modify, merge, publish,
10
   distribute, sublicense, and/or sell copies of the Software, and to
11
   permit persons to whom the Software is furnished to do so, subject to
12
   the following conditions:
13
14
   The above copyright notice and this permission notice shall be
15
   included in all copies or substantial portions of the Software.
16
17
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21
   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22
   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
   SOFTWARE.
25
*/
26
27
#define HTS_BUILDING_LIBRARY // Enables HTSLIB_EXPORT, see htslib/hts_defs.h
28
#include <config.h>
29
30
#include <stdarg.h>
31
#include <stdio.h>
32
#include <ctype.h>
33
#include <string.h>
34
#include <stdint.h>
35
#include <math.h>
36
#include "htslib/kstring.h"
37
#include "htslib/hts_alloc.h"
38
39
99.4k
int kputd(double d, kstring_t *s) {
40
99.4k
  int len = 0;
41
99.4k
  char buf[21], *cp = buf+20, *ep;
42
99.4k
  if (d == 0) {
43
72.4k
    if (signbit(d)) {
44
50
      kputsn("-0",2,s);
45
50
      return 2;
46
72.4k
    } else {
47
72.4k
      kputsn("0",1,s);
48
72.4k
      return 1;
49
72.4k
    }
50
72.4k
  }
51
52
27.0k
  if (d < 0) {
53
3.24k
    kputc('-',s);
54
3.24k
    len = 1;
55
3.24k
    d=-d;
56
3.24k
  }
57
27.0k
  if (!(d >= 0.0001 && d <= 999999)) {
58
4.27k
    if (ks_resize(s, s->l + 50) < 0)
59
0
      return EOF;
60
    // We let stdio handle the exponent cases
61
4.27k
    int s2 = snprintf(s->s + s->l, s->m - s->l, "%g", d);
62
4.27k
    len += s2;
63
4.27k
    s->l += s2;
64
4.27k
    return len;
65
4.27k
  }
66
67
  // Correction for rounding - rather ugly
68
  // Optimised for small numbers.
69
70
22.7k
  uint32_t i;
71
22.7k
  if (d<0.001)         i = rint(d*1000000000), cp -= 1;
72
21.9k
  else if (d < 0.01)   i = rint(d*100000000),  cp -= 2;
73
21.6k
  else if (d < 0.1)    i = rint(d*10000000),   cp -= 3;
74
21.5k
  else if (d < 1)      i = rint(d*1000000),    cp -= 4;
75
20.7k
  else if (d < 10)     i = rint(d*100000),     cp -= 5;
76
17.9k
  else if (d < 100)    i = rint(d*10000),      cp -= 6;
77
16.8k
  else if (d < 1000)   i = rint(d*1000),       cp -= 7;
78
8.47k
  else if (d < 10000)  i = rint(d*100),        cp -= 8;
79
5.02k
  else if (d < 100000) i = rint(d*10),         cp -= 9;
80
1.64k
  else                 i = rint(d),            cp -= 10;
81
82
  // integer i is always 6 digits, so print it 2 at a time.
83
22.7k
  static const char kputuw_dig2r[] =
84
22.7k
    "00010203040506070809"
85
22.7k
    "10111213141516171819"
86
22.7k
    "20212223242526272829"
87
22.7k
    "30313233343536373839"
88
22.7k
    "40414243444546474849"
89
22.7k
    "50515253545556575859"
90
22.7k
    "60616263646566676869"
91
22.7k
    "70717273747576777879"
92
22.7k
    "80818283848586878889"
93
22.7k
    "90919293949596979899";
94
95
22.7k
  memcpy(cp-=2, &kputuw_dig2r[2*(i%100)], 2); i /= 100;
96
22.7k
  memcpy(cp-=2, &kputuw_dig2r[2*(i%100)], 2); i /= 100;
97
22.7k
  memcpy(cp-=2, &kputuw_dig2r[2*(i%100)], 2);
98
99
  // Except when it rounds up (d=0.009999999 is i=1000000)
100
22.7k
  if (i >= 100)
101
280
    *--cp = '0' + (i/100);
102
103
104
22.7k
  int p = buf+20-cp;
105
22.7k
  if (p <= 10) { /* d < 1 */
106
    // 0.00123 is 123, so add leading zeros and 0.
107
2.02k
    ep = cp+5; // 6 precision
108
4.74k
    while (p < 10) { // aka d < 1
109
2.72k
      *--cp = '0';
110
2.72k
      p++;
111
2.72k
    }
112
2.02k
    *--cp = '.';
113
2.02k
    *--cp = '0';
114
20.7k
  } else {
115
    // 123.001 is 123001 with p==13, so move 123 down and add "."
116
    // Equiv to memmove(cp-1, cp, p-10); cp--;
117
20.7k
    char *xp = --cp;
118
20.7k
    ep = cp+6;
119
91.3k
    while (p > 10) {
120
70.6k
      xp[0] = xp[1];
121
70.6k
      xp++;
122
70.6k
      p--;
123
70.6k
    }
124
20.7k
    xp[0] = '.';
125
20.7k
  }
126
127
  // Cull trailing zeros
128
78.6k
  while (*ep == '0' && ep > cp)
129
55.9k
    ep--;
130
131
  // End can be 1 out due to the mostly-6 but occasionally 7 (i==1) case.
132
  // Also code with "123." which should be "123"
133
22.7k
  if (*ep && *ep != '.')
134
2.32k
    ep++;
135
22.7k
  *ep = 0;
136
137
22.7k
  int sl = ep-cp;
138
22.7k
  len += sl;
139
22.7k
  kputsn(cp, sl, s);
140
22.7k
  return len;
141
27.0k
}
142
143
int kvsprintf(kstring_t *s, const char *fmt, va_list ap)
144
160k
{
145
160k
  va_list args;
146
160k
  int l;
147
160k
  va_copy(args, ap);
148
149
160k
  if (fmt[0] == '%' && fmt[1] == 'g' && fmt[2] == 0) {
150
0
    double d = va_arg(args, double);
151
0
    l = kputd(d, s);
152
0
    va_end(args);
153
0
    return l;
154
0
  }
155
156
160k
  if (!s->s) {
157
85.7k
    const size_t sz = 64;
158
85.7k
    s->s = malloc(sz);
159
85.7k
    if (!s->s)
160
0
      return -1;
161
85.7k
    s->m = sz;
162
85.7k
    s->l = 0;
163
85.7k
  }
164
165
160k
  l = vsnprintf(s->s + s->l, s->m - s->l, fmt, args); // This line does not work with glibc 2.0. See `man snprintf'.
166
160k
  va_end(args);
167
160k
  if (l + 1 > s->m - s->l) {
168
35.8k
    if (ks_resize(s, s->l + l + 2) < 0)
169
0
      return -1;
170
35.8k
    va_copy(args, ap);
171
35.8k
    l = vsnprintf(s->s + s->l, s->m - s->l, fmt, args);
172
35.8k
    va_end(args);
173
35.8k
  }
174
160k
  s->l += l;
175
160k
  return l;
176
160k
}
177
178
int ksprintf(kstring_t *s, const char *fmt, ...)
179
160k
{
180
160k
  va_list ap;
181
160k
  int l;
182
160k
  va_start(ap, fmt);
183
160k
  l = kvsprintf(s, fmt, ap);
184
160k
  va_end(ap);
185
160k
  return l;
186
160k
}
187
188
char *kstrtok(const char *str, const char *sep_in, ks_tokaux_t *aux)
189
3.38M
{
190
3.38M
  const unsigned char *p, *start, *sep = (unsigned char *) sep_in;
191
3.38M
  if (sep) { // set up the table
192
62.2k
    if (str == 0 && aux->finished) return 0; // no need to set up if we have finished
193
62.2k
    aux->finished = 0;
194
62.2k
    if (sep[0] && sep[1]) {
195
0
      aux->sep = -1;
196
0
      aux->tab[0] = aux->tab[1] = aux->tab[2] = aux->tab[3] = 0;
197
0
      for (p = sep; *p; ++p) aux->tab[*p>>6] |= 1ull<<(*p&0x3f);
198
62.2k
    } else aux->sep = sep[0];
199
62.2k
  }
200
3.38M
  if (aux->finished) return 0;
201
3.34M
  else if (str) start = (unsigned char *) str, aux->finished = 0;
202
3.28M
  else start = (unsigned char *) aux->p + 1;
203
3.34M
  if (aux->sep < 0) {
204
0
    for (p = start; *p; ++p)
205
0
      if (aux->tab[*p>>6]>>(*p&0x3f)&1) break;
206
3.34M
  } else {
207
    // Using strchr is fast for next token, but slower for
208
    // last token due to extra pass from strlen.  Overall
209
    // on a VCF parse this func was 146% faster with // strchr.
210
    // Equiv to:
211
    // for (p = start; *p; ++p) if (*p == aux->sep) break;
212
213
    // NB: We could use strchrnul() here from glibc if detected,
214
    // which is ~40% faster again, but it's not so portable.
215
    // i.e.   p = (uint8_t *)strchrnul((char *)start, aux->sep);
216
3.34M
    uint8_t *p2 = (uint8_t *)strchr((char *)start, aux->sep);
217
3.34M
    p = p2 ? p2 : start + strlen((char *)start);
218
3.34M
  }
219
3.34M
  aux->p = (const char *) p; // end of token
220
3.34M
  if (*p == 0) aux->finished = 1; // no more tokens
221
3.34M
  return (char*)start;
222
3.38M
}
223
224
// s MUST BE a null terminated string; l = strlen(s)
225
int ksplit_core(char *s, int delimiter, int *_max, int **_offsets)
226
0
{
227
0
  int i, n, max, last_char, last_start, *offsets, l;
228
0
  n = 0; max = *_max; offsets = *_offsets;
229
0
  l = strlen(s);
230
231
0
#define __ksplit_aux do {           \
232
0
    if (_offsets) {           \
233
0
      s[i] = 0;         \
234
0
      if (n == max) {         \
235
0
        int *tmp;       \
236
0
        max = max? max<<1 : 2;     \
237
0
        if ((tmp = hts_realloc_p(offsets, sizeof(int), max))) {  \
238
0
          offsets = tmp;      \
239
0
        } else {       \
240
0
          free(offsets);      \
241
0
          *_offsets = NULL;   \
242
0
          return 0;     \
243
0
        }          \
244
0
      }           \
245
0
      offsets[n++] = last_start;      \
246
0
    } else ++n;           \
247
0
  } while (0)
248
249
0
  for (i = 0, last_char = last_start = 0; i <= l; ++i) {
250
0
    if (delimiter == 0) {
251
0
      if (isspace((int)((unsigned char) s[i])) || s[i] == 0) {
252
0
        if (isgraph(last_char))
253
0
                    __ksplit_aux; // the end of a field
254
0
      } else {
255
0
        if (isspace(last_char) || last_char == 0)
256
0
                    last_start = i;
257
0
      }
258
0
    } else {
259
0
      if (s[i] == delimiter || s[i] == 0) {
260
0
        if (last_char != 0 && last_char != delimiter) __ksplit_aux; // the end of a field
261
0
      } else {
262
0
        if (last_char == delimiter || last_char == 0) last_start = i;
263
0
      }
264
0
    }
265
0
    last_char = (int)((unsigned char)s[i]);
266
0
  }
267
0
  *_max = max; *_offsets = offsets;
268
0
  return n;
269
0
}
270
271
int kgetline(kstring_t *s, kgets_func *fgets_fn, void *fp)
272
0
{
273
0
  size_t l0 = s->l;
274
275
0
  while (s->l == l0 || s->s[s->l-1] != '\n') {
276
0
    if (s->m - s->l < 200) {
277
0
      if (ks_resize(s, s->m + 200) < 0)
278
0
        return EOF;
279
0
    }
280
0
    if (fgets_fn(s->s + s->l, s->m - s->l, fp) == NULL) break;
281
0
    s->l += strlen(s->s + s->l);
282
0
  }
283
284
0
  if (s->l == l0) return EOF;
285
286
0
  if (s->l > l0 && s->s[s->l-1] == '\n') {
287
0
    s->l--;
288
0
    if (s->l > l0 && s->s[s->l-1] == '\r') s->l--;
289
0
  }
290
0
  s->s[s->l] = '\0';
291
0
  return 0;
292
0
}
293
294
// Wrap around fgets to get the right signature for kgets_func
295
static char * fgets_wrapper(char *buffer, int size, void *stream)
296
0
{
297
0
    return fgets(buffer, size, (FILE *) stream);
298
0
}
299
300
int kfgetline(kstring_t *s, FILE *fp)
301
0
{
302
0
    if (!s || !fp)
303
0
        return EOF;
304
0
    return kgetline(s, fgets_wrapper, fp);
305
0
}
306
307
int kgetline2(kstring_t *s, kgets_func2 *fgets_fn, void *fp)
308
2.09M
{
309
2.09M
  size_t l0 = s->l;
310
311
4.20M
  while (s->l == l0 || s->s[s->l-1] != '\n') {
312
2.13M
    if (s->m - s->l < 200) {
313
      // We return EOF for both EOF and error and the caller
314
      // needs to check for errors in fp, and we haven't
315
      // even got there yet.
316
      //
317
      // The only way of propagating memory errors is to
318
      // deliberately call something that we know triggers
319
      // and error so fp is also set.  This works for
320
      // hgets, but not for gets where reading <= 0 bytes
321
      // isn't an error.
322
805k
      if (ks_resize(s, s->m + 200) < 0) {
323
0
        fgets_fn(s->s + s->l, 0, fp);
324
0
        return EOF;
325
0
      }
326
805k
    }
327
2.13M
    ssize_t len = fgets_fn(s->s + s->l, s->m - s->l, fp);
328
2.13M
    if (len <= 0) break;
329
2.10M
    s->l += len;
330
2.10M
  }
331
332
2.09M
  if (s->l == l0) return EOF;
333
334
2.08M
  if (s->l > l0 && s->s[s->l-1] == '\n') {
335
2.06M
    s->l--;
336
2.06M
    if (s->l > l0 && s->s[s->l-1] == '\r') s->l--;
337
2.06M
  }
338
2.08M
  s->s[s->l] = '\0';
339
2.08M
  return 0;
340
2.09M
}
341
342
typedef unsigned char ubyte_t;
343
344
/**********************
345
 * Karp-Rabin search  *
346
 **********************/
347
348
// Backup solution for when we can't use Boyer-Moore, e.g. due to memory
349
// required.  Karp-Rabin only needs to store a couple of hash values
350
// so will always complete.
351
352
static uint64_t fast_exp(uint64_t x, uint64_t n)
353
0
{
354
0
  uint64_t y = 1;
355
0
  if (n == 0)
356
0
    return 1;
357
0
  while (n > 1) {
358
0
    if (n & 1)
359
0
      y *= x;
360
0
    x *= x;
361
0
    n >>= 1;
362
0
  }
363
0
  return y * x;
364
0
}
365
366
static void * karp_rabin(const void *str_, size_t n, const void *pat_, size_t m)
367
0
{
368
0
  const ubyte_t *str = (const ubyte_t *) str_;
369
0
  const ubyte_t *pat = (const ubyte_t *) pat_;
370
0
  const uint64_t b = 31;
371
0
  uint64_t hash_pat = 0;
372
0
  uint64_t hash_str = 0;
373
0
  uint64_t b_to_m = fast_exp(b, m);
374
0
  size_t i;
375
0
  ubyte_t mismatch = 0;
376
377
0
  if (m > n)
378
0
    return NULL;
379
380
  // Calculate hash of pat and initial part of str.
381
0
  for (i = 0; i < m; i++) {
382
0
    mismatch |= str[i] ^ pat[i];
383
0
    hash_pat = hash_pat * b + pat[i] + 1U;
384
0
    hash_str = hash_str * b + str[i] + 1U;
385
0
  }
386
387
0
  if (!mismatch) // Match found at start (or m == 0)
388
0
    return (void *) str_;
389
390
0
  for (; i < n; i++) {
391
0
    hash_str = hash_str * b + str[i] + 1U - b_to_m * (str[i - m] + 1U);
392
0
    if (hash_str == hash_pat) {
393
0
      if (memcmp(pat, str + i + 1 - m, m) == 0)
394
0
        return (void *) (str + i + 1 - m);
395
0
    }
396
0
  }
397
0
  return NULL;
398
0
}
399
400
/**********************
401
 * Boyer-Moore search *
402
 **********************/
403
404
405
// reference: http://www-igm.univ-mlv.fr/~lecroq/string/node14.html
406
static int *ksBM_prep(const ubyte_t *pat, int m)
407
432
{
408
432
  int i, *suff, *prep, *bmGs, *bmBc;
409
432
  if (m < 1)
410
0
    return NULL;
411
432
  prep = hts_calloc_ps(sizeof(int), m, 256);
412
432
  if (!prep) return NULL;
413
432
  bmGs = prep; bmBc = prep + m;
414
432
  { // preBmBc()
415
111k
    for (i = 0; i < 256; ++i) bmBc[i] = m;
416
8.29k
    for (i = 0; i < m - 1; ++i) bmBc[pat[i]] = m - i - 1;
417
432
  }
418
432
  suff = (int*)calloc(m, sizeof(int));
419
432
  if (!suff) { free(prep); return NULL; }
420
432
  { // suffixes()
421
432
    int f = 0, g;
422
432
    suff[m - 1] = m;
423
432
    g = m - 1;
424
8.29k
    for (i = m - 2; i >= 0; --i) {
425
7.86k
      if (i > g && suff[i + m - 1 - f] < i - g)
426
0
        suff[i] = suff[i + m - 1 - f];
427
7.86k
      else {
428
7.86k
        if (i < g) g = i;
429
7.86k
        f = i;
430
8.04k
        while (g >= 0 && pat[g] == pat[g + m - 1 - f]) --g;
431
7.86k
        suff[i] = f - g;
432
7.86k
      }
433
7.86k
    }
434
432
  }
435
432
  { // preBmGs()
436
432
    int j = 0;
437
8.72k
    for (i = 0; i < m; ++i) bmGs[i] = m;
438
8.72k
    for (i = m - 1; i >= 0; --i)
439
8.29k
      if (suff[i] == i + 1)
440
432
        for (; j < m - 1 - i; ++j)
441
0
          if (bmGs[j] == m)
442
0
            bmGs[j] = m - 1 - i;
443
8.29k
    for (i = 0; i <= m - 2; ++i)
444
7.86k
      bmGs[m - 1 - suff[i]] = m - 1 - i;
445
432
  }
446
432
  free(suff);
447
432
  return prep;
448
432
}
449
450
static void *boyer_moore(const void *str_, size_t n, const void *pat_, int m,
451
             int **stored_prep_ptr)
452
1.04k
{
453
1.04k
  size_t j;
454
1.04k
  int i, *prep = 0, *bmGs, *bmBc;
455
1.04k
  const ubyte_t *str, *pat;
456
457
1.04k
  if (!str_ || !pat_)
458
0
    return (void *) str_;
459
460
1.04k
  str = (const ubyte_t*) str_;
461
1.04k
  pat = (const ubyte_t*) pat_;
462
463
1.04k
  if (m <= 0) // Empty string always matches at the start
464
0
    return (void *) str_;
465
1.04k
  if (n < m)  // Input shorter than pattern can't match
466
611
    return NULL;
467
432
  if (m == 1) // Switch to memchr for 1 byte patterns (likely faster)
468
0
    return (void *)memchr(str, pat[0], n);
469
470
432
  if (stored_prep_ptr && *stored_prep_ptr) {
471
0
    prep = *stored_prep_ptr;
472
432
  } else {
473
432
    prep = ksBM_prep(pat, m);
474
432
    if (!prep) return karp_rabin(str_, n, pat_, m);
475
432
    if (stored_prep_ptr)
476
0
      *stored_prep_ptr = prep;
477
432
  }
478
432
  bmGs = prep;      // Good-suffix shift array
479
432
  bmBc = prep + m;  // Bad character shift array
480
432
  j = 0;
481
9.14M
  while (j <= n - m) {
482
9.14M
    for (i = m - 1; i >= 0 && pat[i] == str[i+j]; --i);
483
9.13M
    if (i >= 0) {
484
9.13M
      int max = bmBc[str[i+j]] - m + 1 + i;
485
9.13M
      if (max < bmGs[i]) max = bmGs[i];
486
9.13M
      j += max;
487
9.13M
    } else { // Match found
488
16
      if (!stored_prep_ptr) free(prep);
489
16
      return (void*)(str + j);
490
16
    }
491
9.13M
  }
492
  // No match
493
416
  if (!stored_prep_ptr) free(prep);
494
416
  return NULL;
495
432
}
496
497
void *kmemmem(const void *str, int n, const void *pat, int m, int **prep)
498
1.04k
{
499
1.04k
  return boyer_moore(str, n >= 0 ? n : 0, pat, m, prep);
500
1.04k
}
501
502
char *kstrstr(const char *str, const char *pat, int **prep)
503
0
{
504
0
  size_t patlen = strlen(pat);
505
0
  if (patlen <= INT_MAX)
506
0
    return (char*)boyer_moore(str, strlen(str), pat, patlen, prep);
507
0
  else
508
0
    return karp_rabin(str, strlen(str), pat, patlen);
509
0
}
510
511
char *kstrnstr(const char *str, const char *pat, int n, int **prep)
512
0
{
513
0
  if (!pat || *pat == '\0')
514
0
    return (char *) str;
515
0
  if (n <= 0)
516
0
    return NULL;
517
0
  const char *endp = memchr(str, '\0', n);
518
0
  if (endp != NULL && endp - str < n)
519
0
    n = endp - str;
520
0
  size_t patlen = strlen(pat);
521
0
  if (patlen > n)
522
0
    return NULL;
523
0
  return (char*)boyer_moore(str, n, pat, patlen, prep);
524
0
}
525
526
/***********************
527
 * The main() function *
528
 ***********************/
529
530
#ifdef KSTRING_MAIN
531
#include <stdio.h>
532
int main()
533
{
534
  kstring_t *s;
535
  int *fields, n, i;
536
  ks_tokaux_t aux;
537
  char *p;
538
  s = (kstring_t*)calloc(1, sizeof(kstring_t));
539
  // test ksprintf()
540
  ksprintf(s, " abcdefg:    %d ", 100);
541
  printf("'%s'\n", s->s);
542
  // test ksplit()
543
  fields = ksplit(s, 0, &n);
544
  for (i = 0; i < n; ++i)
545
    printf("field[%d] = '%s'\n", i, s->s + fields[i]);
546
  // test kstrtok()
547
  s->l = 0;
548
  for (p = kstrtok("ab:cde:fg/hij::k", ":/", &aux); p; p = kstrtok(0, 0, &aux)) {
549
    kputsn(p, aux.p - p, s);
550
    kputc('\n', s);
551
  }
552
  printf("%s", s->s);
553
  // free
554
  free(s->s); free(s); free(fields);
555
556
  {
557
    static char *str = "abcdefgcdgcagtcakcdcd";
558
    static char *pat = "cd";
559
    char *ret, *s = str;
560
    int *prep = 0;
561
    while ((ret = kstrstr(s, pat, &prep)) != 0) {
562
      printf("match: %s\n", ret);
563
      s = ret + prep[0];
564
    }
565
    free(prep);
566
  }
567
  return 0;
568
}
569
#endif