Coverage Report

Created: 2025-10-14 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/w3m/Str.c
Line
Count
Source
1
/* $Id: Str.c,v 1.8 2002/12/24 17:20:46 ukai Exp $ */
2
/* 
3
 * String manipulation library for Boehm GC
4
 *
5
 * (C) Copyright 1998-1999 by Akinori Ito
6
 *
7
 * This software may be redistributed freely for this purpose, in full 
8
 * or in part, provided that this entire copyright notice is included 
9
 * on any copies of this software and applications and derivations thereof.
10
 *
11
 * This software is provided on an "as is" basis, without warranty of any
12
 * kind, either expressed or implied, as to any matter including, but not
13
 * limited to warranty of fitness of purpose, or merchantability, or
14
 * results obtained from use of this software.
15
 */
16
#include <stdio.h>
17
#include <stdlib.h>
18
#include <gc.h>
19
#include <stdarg.h>
20
#include <string.h>
21
#ifdef __EMX__      /* or include "fm.h" for HAVE_BCOPY? */
22
#include <strings.h>
23
#endif
24
#include "Str.h"
25
#include "myctype.h"
26
27
62.0k
#define INITIAL_STR_SIZE 32
28
29
#ifdef STR_DEBUG
30
/* This is obsolete, because "Str" can handle a '\0' character now. */
31
#define STR_LENGTH_CHECK(x) if (((x)->ptr==0&&(x)->length!=0)||(strlen((x)->ptr)!=(x)->length))abort();
32
#else       /* not STR_DEBUG */
33
#define STR_LENGTH_CHECK(x)
34
#endif        /* not STR_DEBUG */
35
36
Str
37
Strnew()
38
0
{
39
0
    Str x = GC_MALLOC(sizeof(struct _Str));
40
0
    if (x == NULL)
41
0
  exit(1);
42
0
    x->ptr = GC_MALLOC_ATOMIC(INITIAL_STR_SIZE);
43
0
    if (x->ptr == NULL)
44
0
  exit(1);
45
0
    x->ptr[0] = '\0';
46
0
    x->area_size = INITIAL_STR_SIZE;
47
0
    x->length = 0;
48
0
    return x;
49
0
}
50
51
Str
52
Strnew_size(int n)
53
23.5k
{
54
23.5k
    Str x = GC_MALLOC(sizeof(struct _Str));
55
23.5k
    if (x == NULL)
56
0
  exit(1);
57
23.5k
    if (n < 0 || n >= STR_SIZE_MAX)
58
0
  n = STR_SIZE_MAX - 1;
59
23.5k
    else if (n + 1 < INITIAL_STR_SIZE)
60
15.2k
  n = INITIAL_STR_SIZE - 1;
61
23.5k
    x->ptr = GC_MALLOC_ATOMIC(n + 1);
62
23.5k
    if (x->ptr == NULL)
63
0
  exit(1);
64
23.5k
    x->ptr[0] = '\0';
65
23.5k
    x->area_size = n + 1;
66
23.5k
    x->length = 0;
67
23.5k
    return x;
68
23.5k
}
69
70
Str
71
Strnew_charp(const char *p)
72
0
{
73
0
    Str x;
74
0
    int n, len;
75
76
0
    if (p == NULL)
77
0
  return Strnew();
78
0
    x = GC_MALLOC(sizeof(struct _Str));
79
0
    if (x == NULL)
80
0
  exit(1);
81
0
    n = strlen(p) + 1;
82
0
    if (n <= 0 || n > STR_SIZE_MAX)
83
0
  n = STR_SIZE_MAX;
84
0
    len = n - 1;
85
0
    if (n < INITIAL_STR_SIZE)
86
0
  n = INITIAL_STR_SIZE;
87
0
    x->ptr = GC_MALLOC_ATOMIC(n);
88
0
    if (x->ptr == NULL)
89
0
  exit(1);
90
0
    x->area_size = n;
91
0
    x->length = len;
92
0
    bcopy((void *)p, (void *)x->ptr, len);
93
0
    x->ptr[x->length] = '\0';
94
0
    return x;
95
0
}
96
97
Str
98
Strnew_m_charp(const char *p, ...)
99
0
{
100
0
    va_list ap;
101
0
    Str r = Strnew();
102
103
0
    va_start(ap, p);
104
0
    while (p != NULL) {
105
0
  Strcat_charp(r, p);
106
0
  p = va_arg(ap, char *);
107
0
    }
108
0
    va_end(ap);
109
0
    return r;
110
0
}
111
112
Str
113
Strnew_charp_n(const char *p, int n)
114
12.0k
{
115
12.0k
    Str x;
116
12.0k
    int len;
117
118
12.0k
    if (p == NULL)
119
0
  return Strnew_size(n);
120
12.0k
    x = GC_MALLOC(sizeof(struct _Str));
121
12.0k
    if (x == NULL)
122
0
  exit(1);
123
12.0k
    if (n < 0 || n >= STR_SIZE_MAX)
124
0
  n = STR_SIZE_MAX - 1;
125
12.0k
    len = n;
126
12.0k
    if (n + 1 < INITIAL_STR_SIZE)
127
8.09k
  n = INITIAL_STR_SIZE - 1;
128
12.0k
    x->ptr = GC_MALLOC_ATOMIC(n + 1);
129
12.0k
    if (x->ptr == NULL)
130
0
  exit(1);
131
12.0k
    x->area_size = n + 1;
132
12.0k
    x->length = len;
133
12.0k
    bcopy((void *)p, (void *)x->ptr, len);
134
12.0k
    x->ptr[x->length] = '\0';
135
12.0k
    return x;
136
12.0k
}
137
138
Str
139
Strdup(Str s)
140
0
{
141
0
    Str n = Strnew_size(s->length);
142
0
    STR_LENGTH_CHECK(s);
143
0
    Strcopy(n, s);
144
0
    return n;
145
0
}
146
147
void
148
Strclear(Str s)
149
260
{
150
260
    s->length = 0;
151
260
    s->ptr[0] = '\0';
152
260
}
153
154
void
155
Strfree(Str x)
156
12.4k
{
157
12.4k
    GC_free(x->ptr);
158
12.4k
    GC_free(x);
159
12.4k
}
160
161
void
162
Strcopy(Str x, Str y)
163
0
{
164
0
    STR_LENGTH_CHECK(x);
165
0
    STR_LENGTH_CHECK(y);
166
0
    if (x->area_size < y->length + 1) {
167
0
  x->ptr = GC_REALLOC(x->ptr, y->length + 1);
168
0
  if (x->ptr == NULL)
169
0
      exit(1);
170
0
  x->area_size = y->length + 1;
171
0
    }
172
0
    bcopy((void *)y->ptr, (void *)x->ptr, y->length + 1);
173
0
    x->length = y->length;
174
0
}
175
176
void
177
Strcopy_charp(Str x, const char *y)
178
0
{
179
0
    int len;
180
181
0
    STR_LENGTH_CHECK(x);
182
0
    if (y == NULL) {
183
0
  x->length = 0;
184
0
  x->ptr[0] = '\0';
185
0
  return;
186
0
    }
187
0
    len = strlen(y);
188
0
    if (len < 0 || len >= STR_SIZE_MAX)
189
0
  len = STR_SIZE_MAX - 1;
190
0
    if (x->area_size < len + 1) {
191
0
  x->ptr = GC_REALLOC(x->ptr, len + 1);
192
0
  if (x->ptr == NULL)
193
0
      exit(1);
194
0
  x->area_size = len + 1;
195
0
    }
196
0
    bcopy((void *)y, (void *)x->ptr, len);
197
0
    x->ptr[len] = '\0';
198
0
    x->length = len;
199
0
}
200
201
void
202
Strcopy_charp_n(Str x, const char *y, int n)
203
0
{
204
0
    int len = n;
205
206
0
    STR_LENGTH_CHECK(x);
207
0
    if (y == NULL) {
208
0
  x->length = 0;
209
0
  x->ptr[0] = '\0';
210
0
  return;
211
0
    }
212
0
    if (len < 0 || len >= STR_SIZE_MAX)
213
0
  len = STR_SIZE_MAX - 1;
214
0
    if (x->area_size < len + 1) {
215
0
  x->ptr = GC_REALLOC(x->ptr, len + 1);
216
0
  if (x->ptr == NULL)
217
0
      exit(1);
218
0
  x->area_size = len + 1;
219
0
    }
220
0
    bcopy((void *)y, (void *)x->ptr, len);
221
0
    x->ptr[len] = '\0';
222
0
    x->length = len;
223
0
}
224
225
void
226
Strcat_charp_n(Str x, const char *y, int n)
227
237M
{
228
237M
    int newlen;
229
230
237M
    STR_LENGTH_CHECK(x);
231
237M
    if (y == NULL || n == 0)
232
706
  return;
233
237M
    if (n < 0)
234
0
  n = STR_SIZE_MAX - 1;
235
237M
    newlen = x->length + n + 1;
236
237M
    if (newlen <= 0 || newlen > STR_SIZE_MAX) {
237
0
  newlen = STR_SIZE_MAX;
238
0
  n = newlen - x->length - 1;
239
0
  if (n <= 0)
240
0
      return;
241
0
    }
242
237M
    if (x->area_size < newlen) {
243
10.5k
  newlen += newlen / 2;
244
10.5k
  if (newlen <= 0 || newlen > STR_SIZE_MAX)
245
0
      newlen = STR_SIZE_MAX;
246
10.5k
  x->ptr = GC_REALLOC(x->ptr, newlen);
247
10.5k
  if (x->ptr == NULL)
248
0
      exit(1);
249
10.5k
  x->area_size = newlen;
250
10.5k
    }
251
237M
    bcopy((void *)y, (void *)&x->ptr[x->length], n);
252
237M
    x->length += n;
253
237M
    x->ptr[x->length] = '\0';
254
237M
}
255
256
void
257
Strcat(Str x, Str y)
258
0
{
259
0
    STR_LENGTH_CHECK(y);
260
0
    Strcat_charp_n(x, y->ptr, y->length);
261
0
}
262
263
void
264
Strcat_charp(Str x, const char *y)
265
82.2M
{
266
82.2M
    if (y == NULL)
267
0
  return;
268
82.2M
    Strcat_charp_n(x, y, strlen(y));
269
82.2M
}
270
271
void
272
Strcat_m_charp(Str x, ...)
273
0
{
274
0
    va_list ap;
275
0
    char *p;
276
277
0
    va_start(ap, x);
278
0
    while ((p = va_arg(ap, char *)) != NULL)
279
0
   Strcat_charp_n(x, p, strlen(p));
280
0
    va_end(ap);
281
0
}
282
283
void
284
Strgrow(Str x)
285
3.16k
{
286
3.16k
    int newlen, addlen;
287
288
3.16k
    if (x->area_size < 8192)
289
1.55k
  addlen = x->area_size;
290
1.60k
    else
291
1.60k
  addlen = x->area_size / 2;
292
3.16k
    if (addlen < INITIAL_STR_SIZE)
293
0
  addlen = INITIAL_STR_SIZE;
294
3.16k
    newlen = x->area_size + addlen;
295
3.16k
    if (newlen <= 0 || newlen > STR_SIZE_MAX) {
296
21
  newlen = STR_SIZE_MAX;
297
21
  if (x->length + 1 >= newlen)
298
0
      x->length = newlen - 2;
299
21
    }
300
3.16k
    if (x->area_size < newlen) {
301
3.16k
  x->ptr = GC_REALLOC(x->ptr, newlen);
302
3.16k
  if (x->ptr == NULL)
303
0
      exit(1);
304
3.16k
  x->area_size = newlen;
305
3.16k
    }
306
3.16k
    x->ptr[x->length] = '\0';
307
3.16k
}
308
309
Str
310
Strsubstr(Str s, int beg, int len)
311
0
{
312
0
    Str new_s;
313
0
    int i;
314
315
0
    STR_LENGTH_CHECK(s);
316
0
    new_s = Strnew();
317
0
    if (beg >= s->length)
318
0
  return new_s;
319
0
    for (i = 0; i < len && beg + i < s->length; i++)
320
0
  Strcat_char(new_s, s->ptr[beg + i]);
321
0
    return new_s;
322
0
}
323
324
void
325
Strlower(Str s)
326
0
{
327
0
    int i;
328
0
    STR_LENGTH_CHECK(s);
329
0
    for (i = 0; i < s->length; i++)
330
0
  s->ptr[i] = TOLOWER(s->ptr[i]);
331
0
}
332
333
void
334
Strupper(Str s)
335
0
{
336
0
    int i;
337
0
    STR_LENGTH_CHECK(s);
338
0
    for (i = 0; i < s->length; i++)
339
0
  s->ptr[i] = TOUPPER(s->ptr[i]);
340
0
}
341
342
void
343
Strchop(Str s)
344
0
{
345
0
    STR_LENGTH_CHECK(s);
346
0
    while (s->length > 0 &&
347
0
     (s->ptr[s->length - 1] == '\n' || s->ptr[s->length - 1] == '\r')) {
348
0
  s->length--;
349
0
    }
350
0
    s->ptr[s->length] = '\0';
351
0
}
352
353
void
354
Strinsert_char(Str s, int pos, char c)
355
0
{
356
0
    int i;
357
0
    STR_LENGTH_CHECK(s);
358
0
    if (pos < 0 || s->length < pos)
359
0
  return;
360
0
    if (s->length + 2 > s->area_size)
361
0
  Strgrow(s);
362
0
    if (s->length < pos)
363
0
  return;
364
0
    for (i = s->length; i > pos; i--)
365
0
  s->ptr[i] = s->ptr[i - 1];
366
0
    s->ptr[++s->length] = '\0';
367
0
    s->ptr[pos] = c;
368
0
}
369
370
void
371
Strinsert_charp(Str s, int pos, const char *p)
372
0
{
373
0
    STR_LENGTH_CHECK(s);
374
0
    while (*p)
375
0
  Strinsert_char(s, pos++, *(p++));
376
0
}
377
378
void
379
Strdelete(Str s, int pos, int n)
380
0
{
381
0
    int i;
382
0
    STR_LENGTH_CHECK(s);
383
0
    if (pos < 0 || s->length < pos)
384
0
  return;
385
0
    if (n < 0)
386
0
  n = STR_SIZE_MAX - pos - 1;
387
0
    if (s->length <= pos + n) {
388
0
  s->ptr[pos] = '\0';
389
0
  s->length = pos;
390
0
  return;
391
0
    }
392
0
    for (i = pos; i < s->length - n; i++)
393
0
  s->ptr[i] = s->ptr[i + n];
394
0
    s->ptr[i] = '\0';
395
0
    s->length = i;
396
0
}
397
398
void
399
Strtruncate(Str s, int pos)
400
0
{
401
0
    STR_LENGTH_CHECK(s);
402
0
    if (pos < 0 || s->length < pos)
403
0
  return;
404
0
    s->ptr[pos] = '\0';
405
0
    s->length = pos;
406
0
}
407
408
void
409
Strshrink(Str s, int n)
410
0
{
411
0
    STR_LENGTH_CHECK(s);
412
0
    if (n >= s->length) {
413
0
  s->length = 0;
414
0
  s->ptr[0] = '\0';
415
0
    }
416
0
    else if (n > 0) {
417
0
  s->length -= n;
418
0
  s->ptr[s->length] = '\0';
419
0
    }
420
0
}
421
422
void
423
Strremovefirstspaces(Str s)
424
0
{
425
0
    int i;
426
427
0
    STR_LENGTH_CHECK(s);
428
0
    for (i = 0; i < s->length && IS_SPACE(s->ptr[i]); i++) ;
429
0
    if (i == 0)
430
0
  return;
431
0
    Strdelete(s, 0, i);
432
0
}
433
434
void
435
Strremovetrailingspaces(Str s)
436
0
{
437
0
    int i;
438
439
0
    STR_LENGTH_CHECK(s);
440
0
    for (i = s->length - 1; i >= 0 && IS_SPACE(s->ptr[i]); i--) ;
441
0
    s->length = i + 1;
442
0
    s->ptr[i + 1] = '\0';
443
0
}
444
445
Str
446
Stralign_left(Str s, int width)
447
0
{
448
0
    Str n;
449
0
    int i;
450
451
0
    STR_LENGTH_CHECK(s);
452
0
    if (s->length >= width)
453
0
  return Strdup(s);
454
0
    n = Strnew_size(width);
455
0
    Strcopy(n, s);
456
0
    for (i = s->length; i < width; i++)
457
0
  Strcat_char(n, ' ');
458
0
    return n;
459
0
}
460
461
Str
462
Stralign_right(Str s, int width)
463
0
{
464
0
    Str n;
465
0
    int i;
466
467
0
    STR_LENGTH_CHECK(s);
468
0
    if (s->length >= width)
469
0
  return Strdup(s);
470
0
    n = Strnew_size(width);
471
0
    for (i = s->length; i < width; i++)
472
0
  Strcat_char(n, ' ');
473
0
    Strcat(n, s);
474
0
    return n;
475
0
}
476
477
Str
478
Stralign_center(Str s, int width)
479
0
{
480
0
    Str n;
481
0
    int i, w;
482
483
0
    STR_LENGTH_CHECK(s);
484
0
    if (s->length >= width)
485
0
  return Strdup(s);
486
0
    n = Strnew_size(width);
487
0
    w = (width - s->length) / 2;
488
0
    for (i = 0; i < w; i++)
489
0
  Strcat_char(n, ' ');
490
0
    Strcat(n, s);
491
0
    for (i = w + s->length; i < width; i++)
492
0
  Strcat_char(n, ' ');
493
0
    return n;
494
0
}
495
496
0
#define SP_NORMAL 0
497
0
#define SP_PREC   1
498
0
#define SP_PREC2  2
499
500
Str
501
Sprintf(char *fmt, ...)
502
0
{
503
0
    int len = 0;
504
0
    int status = SP_NORMAL;
505
0
    int p = 0;
506
0
    char *f;
507
0
    Str s;
508
0
    va_list ap;
509
510
0
    va_start(ap, fmt);
511
0
    for (f = fmt; *f; f++) {
512
0
      redo:
513
0
  switch (status) {
514
0
  case SP_NORMAL:
515
0
      if (*f == '%') {
516
0
    status = SP_PREC;
517
0
    p = 0;
518
0
      }
519
0
      else
520
0
    len++;
521
0
      break;
522
0
  case SP_PREC:
523
0
      if (IS_ALPHA(*f)) {
524
    /* conversion char. */
525
0
    int vi;
526
0
    char *vs;
527
528
0
    switch (*f) {
529
0
    case 'l':
530
0
    case 'h':
531
0
    case 'L':
532
0
    case 'w':
533
0
        continue;
534
0
    case 'd':
535
0
    case 'i':
536
0
    case 'o':
537
0
    case 'x':
538
0
    case 'X':
539
0
    case 'u':
540
0
        vi = va_arg(ap, int);
541
0
        len += (p > 0) ? p : 10;
542
0
        break;
543
0
    case 'f':
544
0
    case 'g':
545
0
    case 'e':
546
0
    case 'G':
547
0
    case 'E':
548
0
        va_arg(ap, double);
549
0
        len += (p > 0) ? p : 15;
550
0
        break;
551
0
    case 'c':
552
0
        len += 1;
553
0
        vi = va_arg(ap, int);
554
0
        break;
555
0
    case 's':
556
0
        vs = va_arg(ap, char *);
557
0
        vi = strlen(vs);
558
0
        len += (p > vi) ? p : vi;
559
0
        break;
560
0
    case 'p':
561
0
        va_arg(ap, void *);
562
0
        len += 10;
563
0
        break;
564
0
    case 'n':
565
0
        va_arg(ap, void *);
566
0
        break;
567
0
    }
568
0
    status = SP_NORMAL;
569
0
      }
570
0
      else if (IS_DIGIT(*f))
571
0
    p = p * 10 + *f - '0';
572
0
      else if (*f == '.')
573
0
    status = SP_PREC2;
574
0
      else if (*f == '%') {
575
0
    status = SP_NORMAL;
576
0
    len++;
577
0
      }
578
0
      break;
579
0
  case SP_PREC2:
580
0
      if (IS_ALPHA(*f)) {
581
0
    status = SP_PREC;
582
0
    goto redo;
583
0
      }
584
0
      break;
585
0
  }
586
0
    }
587
0
    va_end(ap);
588
0
    s = Strnew_size(len * 2);
589
0
    va_start(ap, fmt);
590
0
    vsprintf(s->ptr, fmt, ap);
591
0
    va_end(ap);
592
0
    s->length = strlen(s->ptr);
593
0
    if (s->length > len * 2) {
594
0
  fprintf(stderr, "Sprintf: string too long\n");
595
0
  exit(1);
596
0
    }
597
0
    return s;
598
0
}
599
600
Str
601
Strfgets(FILE * f)
602
0
{
603
0
    Str s = Strnew();
604
0
    int c;
605
0
    while ((c = fgetc(f)) != EOF) {
606
0
  Strcat_char(s, c);
607
0
  if (c == '\n')
608
0
      break;
609
0
    }
610
0
    return s;
611
0
}
612
613
Str
614
Strfgetall(FILE * f)
615
0
{
616
0
    Str s = Strnew();
617
0
    int c;
618
0
    while ((c = fgetc(f)) != EOF) {
619
  Strcat_char(s, c);
620
0
    }
621
0
    return s;
622
0
}