4223
|
1 #include "config.h"
|
|
2 #include "Str.h"
|
|
3 #include "strutil.h"
|
|
4 #include "xmalloc.h"
|
|
5
|
|
6 #include <ctype.h>
|
|
7 #include <errno.h>
|
|
8 #include <float.h>
|
|
9 #include <stdarg.h>
|
|
10 #include <stdio.h>
|
|
11 #include <stdlib.h>
|
|
12 #include <string.h>
|
|
13 #include <assert.h>
|
|
14
|
|
15 enum {MAGIC = 4};
|
|
16
|
|
17 #define OFFSET_OFF(s) \
|
|
18 do { \
|
|
19 if ((s)->offset) { \
|
|
20 memmove((s)->buf - (s)->offset, (s)->buf, (s)->length + 1); \
|
|
21 (s)->buf -= (s)->offset; \
|
|
22 (s)->offset = 0; \
|
|
23 } \
|
|
24 } while (0)
|
|
25
|
|
26
|
|
27 void
|
|
28 St_init(String *s) {
|
|
29 s->buf = xmalloc(s->size = MAGIC, sizeof *s->buf);
|
|
30 s->buf[s->offset = s->length = 0] = '\0';
|
|
31 }
|
|
32
|
|
33 void
|
|
34 St_fake(String *s, char *p, size_t n) {
|
|
35 assert(s != NULL);
|
|
36 assert(p != NULL);
|
|
37 s->buf = p;
|
|
38 s->offset = 0;
|
|
39 s->length = s->size = n;
|
|
40 }
|
|
41
|
|
42 void
|
|
43 St_clear(String *s) {
|
|
44 assert(s != NULL);
|
|
45 if (!s->buf) {
|
|
46 return;
|
|
47 }
|
|
48 xfree(s->buf - s->offset);
|
|
49 s->buf = NULL;
|
|
50 DEBUG(s->offset = s->length = s->size = 0;)
|
|
51 }
|
|
52
|
|
53 #if 0
|
|
54 void
|
|
55 (St_zero)(String *s) {
|
|
56 St_zero(s);
|
|
57 }
|
|
58
|
|
59 char *
|
|
60 (St_ptr)(const String *s) {
|
|
61 return St_ptr(s);
|
|
62 }
|
|
63
|
|
64 size_t
|
|
65 (St_len)(const String *s) {
|
|
66 return St_len(s);
|
|
67 }
|
|
68 #endif
|
|
69
|
|
70 static void
|
|
71 St_grow(String *s, size_t n) {
|
|
72 if (s->size - s->offset <= n) {
|
|
73 OFFSET_OFF(s);
|
|
74 if (s->size <= n) {
|
|
75 s->buf = xrealloc(s->buf, n + 1u);
|
|
76 s->size = n + 1u;
|
|
77 }
|
|
78 }
|
|
79 }
|
|
80
|
|
81 void
|
|
82 St_trunc(String *s, size_t n) {
|
|
83 if (s->length > n) {
|
|
84 s->buf[s->length = n] = '\0';
|
|
85 }
|
|
86 if (s->size > n + 1 && n >= MAGIC) {
|
|
87 OFFSET_OFF(s);
|
|
88 s->buf = xrealloc(s->buf, n + 1);
|
|
89 s->size = n + 1;
|
|
90 }
|
|
91 }
|
|
92
|
|
93 #if 0
|
|
94 int
|
|
95 St_lastchar(const String *s) {
|
|
96 return ST_LASTCHAR(s);
|
|
97 }
|
|
98
|
|
99 int
|
|
100 St_firstchar(const String *s) {
|
|
101 return ST_FIRSTCHAR(s);
|
|
102 }
|
|
103
|
|
104 int
|
|
105 St_chop(String *s) {
|
|
106 int tmp;
|
|
107
|
|
108 if (!s->length) {
|
|
109 return EOF;
|
|
110 }
|
|
111 tmp = (unsigned char)s->buf[s->length - 1];
|
|
112 s->buf[--s->length] = '\0';
|
|
113 return tmp;
|
|
114 }
|
|
115 #endif
|
|
116
|
|
117 int
|
|
118 St_shift(String *s) {
|
|
119 int tmp;
|
|
120
|
|
121 if (!s->length) {
|
|
122 return EOF;
|
|
123 }
|
|
124 tmp = (unsigned char)s->buf[0];
|
|
125 ++s->offset;
|
|
126 ++s->buf;
|
|
127 --s->length;
|
|
128 return tmp;
|
|
129 }
|
|
130
|
|
131
|
|
132 size_t
|
|
133 St_shiftws(String *s) {
|
|
134 size_t n;
|
|
135
|
|
136 for (n = 0; n < s->length && isspace((unsigned char)s->buf[n]); ++n)
|
|
137 ;
|
|
138 s->offset += n;
|
|
139 s->buf += n;
|
|
140 s->length -= n;
|
|
141
|
|
142 return n;
|
|
143 }
|
|
144
|
|
145 #if 0
|
|
146 int
|
|
147 St_index(const String *s, size_t n) {
|
|
148 return ST_INDEX(s, n);
|
|
149 }
|
|
150 #endif
|
|
151
|
|
152 size_t
|
|
153 St_chr(const String *s, int c) {
|
|
154 const char *tmp;
|
|
155 if (!(tmp = memchr(s->buf, c, s->length))) {
|
|
156 return -1;
|
|
157 }
|
|
158 return tmp - s->buf;
|
|
159 }
|
|
160
|
|
161 #if 0
|
|
162 size_t
|
|
163 St_rchr(const String *s, int c) {
|
|
164 size_t i;
|
|
165
|
|
166 for (i = s->length; i; --i) {
|
|
167 if (s->buf[i - 1] == c)
|
|
168 return i - 1;
|
|
169 }
|
|
170 return -1;
|
|
171 }
|
|
172 #endif
|
|
173
|
|
174 int
|
|
175 St_cmp(const String *s, const String *t) {
|
|
176 return u_cmp(St_ptr(s), St_len(s), St_ptr(t), St_len(t));
|
|
177 }
|
|
178
|
|
179 int
|
|
180 St_cmp_m(const String *s, const void *m, size_t n) {
|
|
181 return u_cmp(St_ptr(s), St_len(s), m, n);
|
|
182 }
|
|
183
|
|
184 #if 0
|
|
185 int
|
|
186 St_cmp_s(const String *s, const char *tz) {
|
|
187 return u_cmp(St_ptr(s), St_len(s), tz, strlen(tz));
|
|
188 }
|
|
189 #endif
|
|
190
|
|
191 #define NCMP(s, m, n) \
|
|
192 do { \
|
|
193 return memcmp((s)->buf, m, (s)->length < (n) ? (s)->length : (n)); \
|
|
194 } while (0)
|
|
195
|
|
196 #if 0
|
|
197 int
|
|
198 St_ncmp(const String *s, const String *t) {
|
|
199 NCMP(s, t->buf, t->length);
|
|
200 }
|
|
201 #endif
|
|
202
|
|
203 int
|
|
204 St_ncmp_m(const String *s, const void *m, size_t n) {
|
|
205 NCMP(s, m, n);
|
|
206 }
|
|
207
|
|
208 #if 0
|
|
209 int
|
|
210 St_ncmp_s(const String *s, const char *tz) {
|
|
211 size_t length = strlen(tz);
|
|
212
|
|
213 NCMP(s, tz, length);
|
|
214 }
|
|
215
|
|
216 static int
|
|
217 my_memcasecmp(const void *p, const void *q, size_t n) {
|
|
218 const unsigned char *s = p, *t = q;
|
|
219 size_t i;
|
|
220
|
|
221 for (i = 0; i < n; ++i) {
|
|
222 if (tolower(s[i]) < tolower(t[i])) {
|
|
223 return -1;
|
|
224 }
|
|
225 if (tolower(s[i]) > tolower(t[i])) {
|
|
226 return 1;
|
|
227 }
|
|
228 }
|
|
229 return 0;
|
|
230 }
|
|
231
|
|
232 #define CASECMP(s, m, n) \
|
|
233 do { \
|
|
234 int tmp__; \
|
|
235 if (!(tmp__ = my_memcasecmp((s)->buf, m, (s)->length < (n) ? (s)->length : (n)))) { \
|
|
236 if ((s)->length < (n)) \
|
|
237 return -1; \
|
|
238 if ((s)->length > (n)) \
|
|
239 return 1; \
|
|
240 } \
|
|
241 return tmp__; \
|
|
242 } while (0)
|
|
243
|
|
244 int
|
|
245 St_casecmp(const String *s, const String *t) {
|
|
246 CASECMP(s, t->buf, t->length);
|
|
247 }
|
|
248
|
|
249 int
|
|
250 St_casecmp_m(const String *s, const void *m, size_t n) {
|
|
251 CASECMP(s, m, n);
|
|
252 }
|
|
253
|
|
254 int
|
|
255 St_casecmp_s(const String *s, const char *tz) {
|
|
256 size_t length = strlen(tz);
|
|
257
|
|
258 CASECMP(s, tz, length);
|
|
259 }
|
|
260
|
|
261 #define NCASECMP(s, m, n) \
|
|
262 do { \
|
|
263 return my_memcasecmp((s)->buf, m, n); \
|
|
264 } while (0)
|
|
265
|
|
266 int
|
|
267 St_ncasecmp(const String *s, const String *t) {
|
|
268 NCASECMP(s, t->buf, t->length);
|
|
269 }
|
|
270
|
|
271 int
|
|
272 St_ncasecmp_m(const String *s, const void *m, size_t n) {
|
|
273 NCASECMP(s, m, n);
|
|
274 }
|
|
275
|
|
276 int
|
|
277 St_ncasecmp_s(const String *s, const char *tz) {
|
|
278 size_t length = strlen(tz);
|
|
279
|
|
280 NCASECMP(s, tz, length);
|
|
281 }
|
|
282 #endif
|
|
283
|
|
284 #define STR(s, m, n) \
|
|
285 do { \
|
|
286 size_t i__; \
|
|
287 if ((n) == 0) \
|
|
288 return 0; \
|
|
289 if ((s)->length < (n)) \
|
|
290 return -1; \
|
|
291 for (i__ = 0; i__ <= (s)->length - (n); ++i__) { \
|
|
292 if (!memcmp((s)->buf + i__, m, n)) \
|
|
293 return i__; \
|
|
294 } \
|
|
295 return -1; \
|
|
296 } while (0)
|
|
297
|
|
298 size_t
|
|
299 St_str(const String *s, const String *t) {
|
|
300 STR(s, t->buf, t->length);
|
|
301 }
|
|
302
|
|
303 size_t
|
|
304 St_str_m(const String *s, const void *m, size_t n) {
|
|
305 STR(s, m, n);
|
|
306 }
|
|
307
|
|
308 #if 0
|
|
309 size_t
|
|
310 St_str_s(const String *s, const char *tz) {
|
|
311 size_t length = strlen(tz);
|
|
312
|
|
313 STR(s, tz, length);
|
|
314 }
|
|
315 #endif
|
|
316
|
|
317 #define RSTR(s, m, n) \
|
|
318 do { \
|
|
319 size_t i__; \
|
|
320 if ((n) == 0) \
|
|
321 return (s)->length; \
|
|
322 if ((s)->length < (n)) \
|
|
323 return -1; \
|
|
324 for (i__ = (s)->length - (n) + 1; i__; --i__) { \
|
|
325 if (!memcmp((s)->buf + i__ - 1, m, n)) \
|
|
326 return i__ - 1; \
|
|
327 } \
|
|
328 return -1; \
|
|
329 } while (0)
|
|
330
|
|
331 #if 0
|
|
332 size_t
|
|
333 St_rstr(const String *s, const String *t) {
|
|
334 RSTR(s, t->buf, t->length);
|
|
335 }
|
|
336 #endif
|
|
337
|
|
338 size_t
|
|
339 St_rstr_m(const String *s, const void *m, size_t n) {
|
|
340 RSTR(s, m, n);
|
|
341 }
|
|
342
|
|
343 size_t
|
|
344 St_rstr_s(const String *s, const char *tz) {
|
|
345 size_t length = strlen(tz);
|
|
346
|
|
347 RSTR(s, tz, length);
|
|
348 }
|
|
349
|
|
350 size_t
|
|
351 St_stro_m(const String *s, size_t off, const void *m, size_t n) {
|
|
352 size_t i;
|
|
353
|
|
354 assert(off <= s->length);
|
|
355
|
|
356 if (n == 0) {
|
|
357 return off;
|
|
358 }
|
|
359
|
|
360 if (n > s->length - off) {
|
|
361 return -1;
|
|
362 }
|
|
363
|
|
364 for (i = off; i < s->length - n; ++i) {
|
|
365 if (memcmp(s->buf + i, m, n) == 0) {
|
|
366 return i;
|
|
367 }
|
|
368 }
|
|
369 return -1;
|
|
370 }
|
|
371
|
|
372 size_t
|
|
373 St_rstro_m(const String *s, size_t off, const void *m, size_t n) {
|
|
374 size_t i;
|
|
375
|
|
376 assert(off <= s->length);
|
|
377
|
|
378 if (n == 0) {
|
|
379 return off;
|
|
380 }
|
|
381
|
|
382 if (n > s->length) {
|
|
383 return -1;
|
|
384 }
|
|
385
|
|
386 i = off;
|
|
387 if (i > s->length - n) {
|
|
388 i = s->length - n;
|
|
389 }
|
|
390
|
|
391 for (; i + 1u; --i) {
|
|
392 if (memcmp(s->buf + i, m, n) == 0) {
|
|
393 return i;
|
|
394 }
|
|
395 }
|
|
396 return -1;
|
|
397 }
|
|
398
|
|
399 #define CPY(s, m, n) \
|
|
400 do { \
|
|
401 if ((s)->size - (s)->offset <= (n)) { \
|
|
402 OFFSET_OFF(s); \
|
|
403 if ((s)->size <= (n)) { \
|
|
404 (s)->buf = xrealloc((s)->buf, (n) + 1); \
|
|
405 (s)->size = (n) + 1; \
|
|
406 } \
|
|
407 } \
|
|
408 memcpy((s)->buf, m, (s)->length = (n)); \
|
|
409 (s)->buf[n] = '\0'; \
|
|
410 } while (0)
|
|
411
|
|
412 void
|
|
413 St_cpy(String *s, const String *t) {
|
|
414 CPY(s, t->buf, t->length);
|
|
415 }
|
|
416
|
|
417 void
|
|
418 St_cpy_m(String *s, const void *m, size_t n) {
|
|
419 CPY(s, m, n);
|
|
420 }
|
|
421
|
|
422 void
|
|
423 St_cpy_s(String *s, const char *tz) {
|
|
424 size_t length = strlen(tz);
|
|
425
|
|
426 CPY(s, tz, length);
|
|
427 }
|
|
428
|
|
429 void
|
|
430 St_cpy_c(String *s, int c) {
|
|
431 unsigned char tmp = c;
|
|
432 CPY(s, &tmp, 1);
|
|
433 }
|
|
434
|
|
435 static void cat(String *s, const void *m, size_t n) {
|
|
436 if (s->size - s->offset <= s->length + n) {
|
|
437 OFFSET_OFF(s);
|
|
438 if (s->size <= s->length + n) {
|
|
439 do {
|
|
440 s->size = s->size / 2 * 3 + 1;
|
|
441 } while (s->size <= s->length + n);
|
|
442 s->buf = xrealloc(s->buf, s->size);
|
|
443 }
|
|
444 }
|
|
445 memcpy(s->buf + s->length, m, n);
|
|
446 s->buf[s->length += n] = '\0';
|
|
447 }
|
|
448
|
|
449 void
|
|
450 St_cat(String *s, const String *t) {
|
|
451 cat(s, t->buf, t->length);
|
|
452 }
|
|
453
|
|
454 void
|
|
455 St_cat_m(String *s, const void *m, size_t n) {
|
|
456 cat(s, m, n);
|
|
457 }
|
|
458
|
|
459 void
|
|
460 St_cat_s(String *s, const char *tz) {
|
|
461 cat(s, tz, strlen(tz));
|
|
462 }
|
|
463
|
|
464 void
|
|
465 St_cat_c(String *s, int c) {
|
|
466 unsigned char tmp = c;
|
|
467 cat(s, &tmp, 1);
|
|
468 }
|
|
469
|
|
470 #define TAC(s, m, n) \
|
|
471 do { \
|
|
472 if ((s)->offset >= (n)) { \
|
|
473 (s)->buf -= (n); \
|
|
474 (s)->offset -= (n); \
|
|
475 } else if ((s)->size <= (s)->length + (n)) { \
|
|
476 (s)->buf -= (s)->offset; \
|
|
477 (s)->buf = xrealloc((s)->buf, (s)->length + (n) + 1); \
|
|
478 (s)->size = (s)->length + (n) + 1; \
|
|
479 memmove((s)->buf + (n), (s)->buf + (s)->offset, (s)->length + 1); \
|
|
480 (s)->offset = 0; \
|
|
481 } else { \
|
|
482 memmove((s)->buf + (n), (s)->buf, (s)->length + 1); \
|
|
483 } \
|
|
484 memcpy((s)->buf, m, n); \
|
|
485 (s)->length += (n); \
|
|
486 } while (0)
|
|
487
|
|
488 #if 0
|
|
489 void
|
|
490 St_tac(String *s, const String *t) {
|
|
491 TAC(s, t->buf, t->length);
|
|
492 }
|
|
493 #endif
|
|
494
|
|
495 void
|
|
496 St_tac_m(String *s, const void *m, size_t n) {
|
|
497 TAC(s, m, n);
|
|
498 }
|
|
499
|
|
500 void
|
|
501 St_tac_s(String *s, const char *tz) {
|
|
502 size_t length = strlen(tz);
|
|
503
|
|
504 TAC(s, tz, length);
|
|
505 }
|
|
506
|
|
507 void
|
|
508 St_tac_c(String *s, int c) {
|
|
509 unsigned char tmp = c;
|
|
510 TAC(s, &tmp, 1);
|
|
511 }
|
|
512
|
|
513 void
|
|
514 St_reverse(String *s) {
|
|
515 size_t i;
|
|
516 char tmp;
|
|
517
|
|
518 for (i = 0; i < s->length / 2; ++i) {
|
|
519 tmp = s->buf[i];
|
|
520 s->buf[i] = s->buf[s->length - i - 1];
|
|
521 s->buf[s->length - i - 1] = tmp;
|
|
522 }
|
|
523 }
|
|
524
|
|
525 #if 0
|
|
526 void
|
|
527 St_map(String *s, int (*better)(int)) {
|
|
528 size_t i;
|
|
529 int tmp;
|
|
530
|
|
531 for (i = 0; i < s->length; ++i) {
|
|
532 tmp = better((unsigned char)s->buf[i]);
|
|
533 if (tmp == EOF) {
|
|
534 s->buf[s->length = i] = '\0';
|
|
535 return;
|
|
536 }
|
|
537 s->buf[i] = tmp;
|
|
538 }
|
|
539
|
|
540 while ((tmp = better(EOF)) != EOF) {
|
|
541 if (s->size <= s->length + 1) {
|
|
542 OFFSET_OFF(s);
|
|
543 XREALLOC(s->buf, s->size * 2);
|
|
544 s->size *= 2;
|
|
545 }
|
|
546 s->buf[s->length++] = tmp;
|
|
547 s->buf[s->length] = '\0';
|
|
548 }
|
|
549 }
|
|
550 #endif
|
|
551
|
|
552 void
|
|
553 St_grep(String *s, int (*good)(int)) {
|
|
554 size_t r, w;
|
|
555
|
|
556 for (r = w = 0; r < s->length; ++r) {
|
|
557 if (good((unsigned char)s->buf[r])) {
|
|
558 s->buf[w++] = s->buf[r];
|
|
559 }
|
|
560 }
|
|
561 s->buf[s->length = w] = '\0';
|
|
562 }
|
|
563
|
|
564 void
|
|
565 St_upper(String *s) {
|
|
566 size_t i;
|
|
567
|
|
568 for (i = 0; i < s->length; ++i) {
|
|
569 s->buf[i] = toupper((unsigned char)s->buf[i]);
|
|
570 }
|
|
571 }
|
|
572
|
|
573 void
|
|
574 St_lower(String *s) {
|
|
575 size_t i;
|
|
576
|
|
577 for (i = 0; i < s->length; ++i) {
|
|
578 s->buf[i] = tolower((unsigned char)s->buf[i]);
|
|
579 }
|
|
580 }
|
|
581
|
|
582 void
|
|
583 St_del(String *s, size_t p, size_t n) {
|
|
584 if (n == 0 || s->length < p)
|
|
585 return;
|
|
586 if (s->length < n || s->length < p + n) {
|
|
587 n = s->length - p;
|
|
588 }
|
|
589 if (p + n == s->length) {
|
|
590 s->buf[p] = '\0';
|
|
591 } else if (p == 0) {
|
|
592 s->offset += n;
|
|
593 s->buf += n;
|
|
594 } else {
|
|
595 memmove(s->buf + p, s->buf + n + p, s->length - p - n);
|
|
596 }
|
|
597 s->length -= n;
|
|
598 }
|
|
599
|
|
600 #if 0
|
|
601 #define INS(s, p, m, n) \
|
|
602 do { \
|
|
603 if ((n) == 0 || (s)->length < (p)) \
|
|
604 return; \
|
|
605 if ((n) <= (s)->offset) { \
|
|
606 (s)->offset -= (n); \
|
|
607 (s)->buf -= (n); \
|
|
608 memmove((s)->buf, (s)->buf + (n), p); \
|
|
609 } else { \
|
|
610 if ((s)->size - (s)->offset <= (s)->length + (n)) { \
|
|
611 OFFSET_OFF(s); \
|
|
612 XREALLOC((s)->buf, (s)->length + (n) + 1); \
|
|
613 (s)->size = (s)->length + (n) + 1; \
|
|
614 } \
|
|
615 memmove((s)->buf + (p) + (n), (s)->buf + (p), (s)->length - (p) + 1); \
|
|
616 } \
|
|
617 memcpy((s)->buf + (p), m, n); \
|
|
618 (s)->length += (n); \
|
|
619 } while (0)
|
|
620
|
|
621 void
|
|
622 St_ins(String *s, size_t p, const String *t) {
|
|
623 INS(s, p, t->buf, t->length);
|
|
624 }
|
|
625
|
|
626 void
|
|
627 St_ins_m(String *s, size_t p, const void *m, size_t n) {
|
|
628 INS(s, p, m, n);
|
|
629 }
|
|
630
|
|
631 void
|
|
632 St_ins_s(String *s, size_t p, const char *tz) {
|
|
633 size_t length = strlen(tz);
|
|
634
|
|
635 INS(s, p, tz, length);
|
|
636 }
|
|
637
|
|
638 void
|
|
639 St_ins_c(String *s, size_t p, int c) {
|
|
640 unsigned char tmp = c;
|
|
641 INS(s, p, &tmp, 1);
|
|
642 }
|
|
643 #endif
|
|
644
|
|
645 void
|
|
646 St_substr(String *l, String *s, size_t p, size_t n, const String *r) {
|
|
647 if (l) {
|
|
648 if (p >= s->length) {
|
|
649 St_zero(l);
|
|
650 } else {
|
|
651 size_t length = n;
|
|
652
|
|
653 if (p + length > s->length) {
|
|
654 length = s->length - p;
|
|
655 }
|
|
656 St_cpy_m(l, s->buf + p, length);
|
|
657 }
|
|
658 }
|
|
659
|
|
660 if (r) {
|
|
661 size_t gap = 0;
|
|
662
|
|
663 if (p + n > s->length) {
|
|
664 if (p > s->length) {
|
|
665 n = 0;
|
|
666 gap = p - s->length;
|
|
667 } else {
|
|
668 n = s->length - p;
|
|
669 }
|
|
670 }
|
|
671 St_grow(s, s->length + r->length - n + gap);
|
|
672 if (gap) {
|
|
673 memset(s->buf + s->length, '\0', gap);
|
|
674 } else if (r->length != n && s->length - p - n) {
|
|
675 memmove(s->buf + p + r->length, s->buf + p + n, s->length - p - n);
|
|
676 }
|
|
677 memcpy(s->buf + p, r->buf, r->length);
|
|
678 s->buf[s->length += r->length - n + gap] = '\0';
|
|
679 }
|
|
680 }
|
|
681
|
|
682 #if HAVE_VSNPRINTF_P
|
|
683 size_t
|
|
684 St_xprintf(String *s, const char *fmt, ...) {
|
|
685 va_list ap;
|
|
686 int tmp;
|
|
687
|
|
688 va_start(ap, fmt);
|
|
689 tmp = vsnprintf(s->buf, s->size, fmt, ap);
|
|
690 va_end(ap);
|
|
691
|
|
692 if (tmp < 0) {
|
|
693 do {
|
|
694 St_grow(s, s->size * 2);
|
|
695
|
|
696 va_start(ap, fmt);
|
|
697 tmp = vsnprintf(s->buf, s->size, fmt, ap);
|
|
698 va_end(ap);
|
|
699 } while (tmp < 0);
|
|
700 } else if (tmp + 1u >= s->size) {
|
|
701 St_grow(s, tmp);
|
|
702 s->length = 0;
|
|
703
|
|
704 va_start(ap, fmt);
|
|
705 tmp = vsnprintf(s->buf, s->size, fmt, ap);
|
|
706 va_end(ap);
|
|
707
|
|
708 if (tmp < 0) {
|
|
709 s->buf[0] = '\0';
|
|
710 return -1;
|
|
711 }
|
|
712 }
|
|
713
|
|
714 return s->length = tmp;
|
|
715 }
|
|
716 #endif
|
|
717
|
|
718 void
|
|
719 St_num(String *s, double d) {
|
|
720 #if HAVE_VSNPRINTF_P
|
|
721 St_xprintf(s, "%.*g", DBL_DIG, d);
|
|
722 #else
|
|
723 St_grow(s, 255);
|
|
724 s->length = sprintf(s->buf, "%.*g", DBL_DIG, d);
|
|
725 #endif
|
|
726 }
|
|
727
|
|
728 #if 0
|
|
729 size_t
|
|
730 St_write(const String *s, FILE *fp) {
|
|
731 return ST_WRITE(s, fp);
|
|
732 }
|
|
733 #endif
|
|
734
|
|
735 #define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
736
|
|
737 size_t
|
|
738 St_read(String *s, FILE *fp, size_t n) {
|
|
739 char buf[4096];
|
|
740 size_t red;
|
|
741
|
|
742 St_zero(s);
|
|
743 while (n && !feof(fp) && (red = fread(buf, sizeof *buf, MIN(n, sizeof buf / sizeof *buf), fp))) {
|
|
744 St_cat_m(s, buf, red);
|
|
745 n -= red;
|
|
746 }
|
|
747 return s->length;
|
|
748 }
|
|
749
|
|
750 #if 0
|
|
751 int
|
|
752 St_getline(String *s, FILE *fp, int n) {
|
|
753 int c;
|
|
754
|
|
755 OFFSET_OFF(s);
|
|
756 for (s->length = 0; (c = getc(fp)) != EOF; ++s->length) {
|
|
757 if (s->size <= s->length + 1) {
|
|
758 XREALLOC(s->buf, s->size * 2);
|
|
759 s->size *= 2;
|
|
760 }
|
|
761 s->buf[s->length] = c;
|
|
762 if (c == n)
|
|
763 break;
|
|
764 }
|
|
765 s->buf[s->length] = '\0';
|
|
766
|
|
767 return s->length != 0;
|
|
768 }
|
|
769
|
|
770 void
|
|
771 St_getfile(String *s, FILE *fp) {
|
|
772 size_t tmp;
|
|
773
|
|
774 OFFSET_OFF(s);
|
|
775 if (s->size <= BUFSIZ) {
|
|
776 XREALLOC(s->buf, BUFSIZ + 1);
|
|
777 s->size = BUFSIZ + 1;
|
|
778 }
|
|
779
|
|
780 for (s->length = 0; (tmp = fread(s->buf + s->length, 1, BUFSIZ, fp)); ) {
|
|
781 s->length += tmp;
|
|
782 if (s->size <= s->length + BUFSIZ + 1) {
|
|
783 XREALLOC(s->buf, s->size * 2);
|
|
784 s->size *= 2;
|
|
785 }
|
|
786 }
|
|
787 s->buf[s->length] = '\0';
|
|
788 }
|
|
789 #endif
|
|
790
|
|
791 size_t
|
|
792 St_hash(const String *s, size_t h) {
|
|
793 return u_hash(St_ptr(s), St_len(s), h);
|
|
794 }
|