1 /*
2 * C utilities
3 *
4 * Copyright (c) 2017 Fabrice Bellard
5 * Copyright (c) 2018 Charlie Gordon
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <string.h>
29
30 #include "cutils.h"
31
pstrcpy(char * buf,int buf_size,const char * str)32 void pstrcpy(char *buf, int buf_size, const char *str)
33 {
34 int c;
35 char *q = buf;
36
37 if (buf_size <= 0)
38 return;
39
40 for(;;) {
41 c = *str++;
42 if (c == 0 || q >= buf + buf_size - 1)
43 break;
44 *q++ = c;
45 }
46 *q = '\0';
47 }
48
49 /* strcat and truncate. */
pstrcat(char * buf,int buf_size,const char * s)50 char *pstrcat(char *buf, int buf_size, const char *s)
51 {
52 int len;
53 len = strlen(buf);
54 if (len < buf_size)
55 pstrcpy(buf + len, buf_size - len, s);
56 return buf;
57 }
58
strstart(const char * str,const char * val,const char ** ptr)59 int strstart(const char *str, const char *val, const char **ptr)
60 {
61 const char *p, *q;
62 p = str;
63 q = val;
64 while (*q != '\0') {
65 if (*p != *q)
66 return 0;
67 p++;
68 q++;
69 }
70 if (ptr)
71 *ptr = p;
72 return 1;
73 }
74
has_suffix(const char * str,const char * suffix)75 int has_suffix(const char *str, const char *suffix)
76 {
77 size_t len = strlen(str);
78 size_t slen = strlen(suffix);
79 return (len >= slen && !memcmp(str + len - slen, suffix, slen));
80 }
81
82 /* Dynamic buffer package */
83
dbuf_default_realloc(void * opaque,void * ptr,size_t size)84 static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)
85 {
86 return realloc(ptr, size);
87 }
88
dbuf_init2(DynBuf * s,void * opaque,DynBufReallocFunc * realloc_func)89 void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
90 {
91 memset(s, 0, sizeof(*s));
92 if (!realloc_func)
93 realloc_func = dbuf_default_realloc;
94 s->opaque = opaque;
95 s->realloc_func = realloc_func;
96 }
97
dbuf_init(DynBuf * s)98 void dbuf_init(DynBuf *s)
99 {
100 dbuf_init2(s, NULL, NULL);
101 }
102
103 /* return < 0 if error */
dbuf_realloc(DynBuf * s,size_t new_size)104 int dbuf_realloc(DynBuf *s, size_t new_size)
105 {
106 size_t size;
107 uint8_t *new_buf;
108 if (new_size > s->allocated_size) {
109 if (s->error)
110 return -1;
111 size = s->allocated_size * 3 / 2;
112 if (size > new_size)
113 new_size = size;
114 new_buf = s->realloc_func(s->opaque, s->buf, new_size);
115 if (!new_buf) {
116 s->error = TRUE;
117 return -1;
118 }
119 s->buf = new_buf;
120 s->allocated_size = new_size;
121 }
122 return 0;
123 }
124
dbuf_write(DynBuf * s,size_t offset,const uint8_t * data,size_t len)125 int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len)
126 {
127 size_t end;
128 end = offset + len;
129 if (dbuf_realloc(s, end))
130 return -1;
131 memcpy(s->buf + offset, data, len);
132 if (end > s->size)
133 s->size = end;
134 return 0;
135 }
136
dbuf_put(DynBuf * s,const uint8_t * data,size_t len)137 int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
138 {
139 if (unlikely((s->size + len) > s->allocated_size)) {
140 if (dbuf_realloc(s, s->size + len))
141 return -1;
142 }
143 memcpy(s->buf + s->size, data, len);
144 s->size += len;
145 return 0;
146 }
147
dbuf_put_self(DynBuf * s,size_t offset,size_t len)148 int dbuf_put_self(DynBuf *s, size_t offset, size_t len)
149 {
150 if (unlikely((s->size + len) > s->allocated_size)) {
151 if (dbuf_realloc(s, s->size + len))
152 return -1;
153 }
154 memcpy(s->buf + s->size, s->buf + offset, len);
155 s->size += len;
156 return 0;
157 }
158
dbuf_putc(DynBuf * s,uint8_t c)159 int dbuf_putc(DynBuf *s, uint8_t c)
160 {
161 return dbuf_put(s, &c, 1);
162 }
163
dbuf_putstr(DynBuf * s,const char * str)164 int dbuf_putstr(DynBuf *s, const char *str)
165 {
166 return dbuf_put(s, (const uint8_t *)str, strlen(str));
167 }
168
dbuf_printf(DynBuf * s,const char * fmt,...)169 int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
170 const char *fmt, ...)
171 {
172 va_list ap;
173 char buf[128];
174 int len;
175
176 va_start(ap, fmt);
177 len = vsnprintf(buf, sizeof(buf), fmt, ap);
178 va_end(ap);
179 if (len < sizeof(buf)) {
180 /* fast case */
181 return dbuf_put(s, (uint8_t *)buf, len);
182 } else {
183 if (dbuf_realloc(s, s->size + len + 1))
184 return -1;
185 va_start(ap, fmt);
186 vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,
187 fmt, ap);
188 va_end(ap);
189 s->size += len;
190 }
191 return 0;
192 }
193
dbuf_free(DynBuf * s)194 void dbuf_free(DynBuf *s)
195 {
196 /* we test s->buf as a fail safe to avoid crashing if dbuf_free()
197 is called twice */
198 if (s->buf) {
199 s->realloc_func(s->opaque, s->buf, 0);
200 }
201 memset(s, 0, sizeof(*s));
202 }
203
204 /* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes
205 are output. */
unicode_to_utf8(uint8_t * buf,unsigned int c)206 int unicode_to_utf8(uint8_t *buf, unsigned int c)
207 {
208 uint8_t *q = buf;
209
210 if (c < 0x80) {
211 *q++ = c;
212 } else {
213 if (c < 0x800) {
214 *q++ = (c >> 6) | 0xc0;
215 } else {
216 if (c < 0x10000) {
217 *q++ = (c >> 12) | 0xe0;
218 } else {
219 if (c < 0x00200000) {
220 *q++ = (c >> 18) | 0xf0;
221 } else {
222 if (c < 0x04000000) {
223 *q++ = (c >> 24) | 0xf8;
224 } else if (c < 0x80000000) {
225 *q++ = (c >> 30) | 0xfc;
226 *q++ = ((c >> 24) & 0x3f) | 0x80;
227 } else {
228 return 0;
229 }
230 *q++ = ((c >> 18) & 0x3f) | 0x80;
231 }
232 *q++ = ((c >> 12) & 0x3f) | 0x80;
233 }
234 *q++ = ((c >> 6) & 0x3f) | 0x80;
235 }
236 *q++ = (c & 0x3f) | 0x80;
237 }
238 return q - buf;
239 }
240
241 static const unsigned int utf8_min_code[5] = {
242 0x80, 0x800, 0x10000, 0x00200000, 0x04000000,
243 };
244
245 static const unsigned char utf8_first_code_mask[5] = {
246 0x1f, 0xf, 0x7, 0x3, 0x1,
247 };
248
249 /* return -1 if error. *pp is not updated in this case. max_len must
250 be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */
unicode_from_utf8(const uint8_t * p,int max_len,const uint8_t ** pp)251 int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
252 {
253 int l, c, b, i;
254
255 c = *p++;
256 if (c < 0x80) {
257 *pp = p;
258 return c;
259 }
260 switch(c) {
261 case 0xc0 ... 0xdf:
262 l = 1;
263 break;
264 case 0xe0 ... 0xef:
265 l = 2;
266 break;
267 case 0xf0 ... 0xf7:
268 l = 3;
269 break;
270 case 0xf8 ... 0xfb:
271 l = 4;
272 break;
273 case 0xfc ... 0xfd:
274 l = 5;
275 break;
276 default:
277 return -1;
278 }
279 /* check that we have enough characters */
280 if (l > (max_len - 1))
281 return -1;
282 c &= utf8_first_code_mask[l - 1];
283 for(i = 0; i < l; i++) {
284 b = *p++;
285 if (b < 0x80 || b >= 0xc0)
286 return -1;
287 c = (c << 6) | (b & 0x3f);
288 }
289 if (c < utf8_min_code[l - 1])
290 return -1;
291 *pp = p;
292 return c;
293 }
294
295 #if 0
296
297 #if defined(EMSCRIPTEN) || defined(__ANDROID__)
298
299 static void *rqsort_arg;
300 static int (*rqsort_cmp)(const void *, const void *, void *);
301
302 static int rqsort_cmp2(const void *p1, const void *p2)
303 {
304 return rqsort_cmp(p1, p2, rqsort_arg);
305 }
306
307 /* not reentrant, but not needed with emscripten */
308 void rqsort(void *base, size_t nmemb, size_t size,
309 int (*cmp)(const void *, const void *, void *),
310 void *arg)
311 {
312 rqsort_arg = arg;
313 rqsort_cmp = cmp;
314 qsort(base, nmemb, size, rqsort_cmp2);
315 }
316
317 #endif
318
319 #else
320
321 typedef void (*exchange_f)(void *a, void *b, size_t size);
322 typedef int (*cmp_f)(const void *, const void *, void *opaque);
323
exchange_bytes(void * a,void * b,size_t size)324 static void exchange_bytes(void *a, void *b, size_t size) {
325 uint8_t *ap = (uint8_t *)a;
326 uint8_t *bp = (uint8_t *)b;
327
328 while (size-- != 0) {
329 uint8_t t = *ap;
330 *ap++ = *bp;
331 *bp++ = t;
332 }
333 }
334
exchange_one_byte(void * a,void * b,size_t size)335 static void exchange_one_byte(void *a, void *b, size_t size) {
336 uint8_t *ap = (uint8_t *)a;
337 uint8_t *bp = (uint8_t *)b;
338 uint8_t t = *ap;
339 *ap = *bp;
340 *bp = t;
341 }
342
exchange_int16s(void * a,void * b,size_t size)343 static void exchange_int16s(void *a, void *b, size_t size) {
344 uint16_t *ap = (uint16_t *)a;
345 uint16_t *bp = (uint16_t *)b;
346
347 for (size /= sizeof(uint16_t); size-- != 0;) {
348 uint16_t t = *ap;
349 *ap++ = *bp;
350 *bp++ = t;
351 }
352 }
353
exchange_one_int16(void * a,void * b,size_t size)354 static void exchange_one_int16(void *a, void *b, size_t size) {
355 uint16_t *ap = (uint16_t *)a;
356 uint16_t *bp = (uint16_t *)b;
357 uint16_t t = *ap;
358 *ap = *bp;
359 *bp = t;
360 }
361
exchange_int32s(void * a,void * b,size_t size)362 static void exchange_int32s(void *a, void *b, size_t size) {
363 uint32_t *ap = (uint32_t *)a;
364 uint32_t *bp = (uint32_t *)b;
365
366 for (size /= sizeof(uint32_t); size-- != 0;) {
367 uint32_t t = *ap;
368 *ap++ = *bp;
369 *bp++ = t;
370 }
371 }
372
exchange_one_int32(void * a,void * b,size_t size)373 static void exchange_one_int32(void *a, void *b, size_t size) {
374 uint32_t *ap = (uint32_t *)a;
375 uint32_t *bp = (uint32_t *)b;
376 uint32_t t = *ap;
377 *ap = *bp;
378 *bp = t;
379 }
380
exchange_int64s(void * a,void * b,size_t size)381 static void exchange_int64s(void *a, void *b, size_t size) {
382 uint64_t *ap = (uint64_t *)a;
383 uint64_t *bp = (uint64_t *)b;
384
385 for (size /= sizeof(uint64_t); size-- != 0;) {
386 uint64_t t = *ap;
387 *ap++ = *bp;
388 *bp++ = t;
389 }
390 }
391
exchange_one_int64(void * a,void * b,size_t size)392 static void exchange_one_int64(void *a, void *b, size_t size) {
393 uint64_t *ap = (uint64_t *)a;
394 uint64_t *bp = (uint64_t *)b;
395 uint64_t t = *ap;
396 *ap = *bp;
397 *bp = t;
398 }
399
exchange_int128s(void * a,void * b,size_t size)400 static void exchange_int128s(void *a, void *b, size_t size) {
401 uint64_t *ap = (uint64_t *)a;
402 uint64_t *bp = (uint64_t *)b;
403
404 for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) {
405 uint64_t t = ap[0];
406 uint64_t u = ap[1];
407 ap[0] = bp[0];
408 ap[1] = bp[1];
409 bp[0] = t;
410 bp[1] = u;
411 }
412 }
413
exchange_one_int128(void * a,void * b,size_t size)414 static void exchange_one_int128(void *a, void *b, size_t size) {
415 uint64_t *ap = (uint64_t *)a;
416 uint64_t *bp = (uint64_t *)b;
417 uint64_t t = ap[0];
418 uint64_t u = ap[1];
419 ap[0] = bp[0];
420 ap[1] = bp[1];
421 bp[0] = t;
422 bp[1] = u;
423 }
424
exchange_func(const void * base,size_t size)425 static inline exchange_f exchange_func(const void *base, size_t size) {
426 switch (((uintptr_t)base | (uintptr_t)size) & 15) {
427 case 0:
428 if (size == sizeof(uint64_t) * 2)
429 return exchange_one_int128;
430 else
431 return exchange_int128s;
432 case 8:
433 if (size == sizeof(uint64_t))
434 return exchange_one_int64;
435 else
436 return exchange_int64s;
437 case 4:
438 case 12:
439 if (size == sizeof(uint32_t))
440 return exchange_one_int32;
441 else
442 return exchange_int32s;
443 case 2:
444 case 6:
445 case 10:
446 case 14:
447 if (size == sizeof(uint16_t))
448 return exchange_one_int16;
449 else
450 return exchange_int16s;
451 default:
452 if (size == 1)
453 return exchange_one_byte;
454 else
455 return exchange_bytes;
456 }
457 }
458
heapsortx(void * base,size_t nmemb,size_t size,cmp_f cmp,void * opaque)459 static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
460 {
461 uint8_t *basep = (uint8_t *)base;
462 size_t i, n, c, r;
463 exchange_f swap = exchange_func(base, size);
464
465 if (nmemb > 1) {
466 i = (nmemb / 2) * size;
467 n = nmemb * size;
468
469 while (i > 0) {
470 i -= size;
471 for (r = i; (c = r * 2 + size) < n; r = c) {
472 if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0)
473 c += size;
474 if (cmp(basep + r, basep + c, opaque) > 0)
475 break;
476 swap(basep + r, basep + c, size);
477 }
478 }
479 for (i = n - size; i > 0; i -= size) {
480 swap(basep, basep + i, size);
481
482 for (r = 0; (c = r * 2 + size) < i; r = c) {
483 if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0)
484 c += size;
485 if (cmp(basep + r, basep + c, opaque) > 0)
486 break;
487 swap(basep + r, basep + c, size);
488 }
489 }
490 }
491 }
492
med3(void * a,void * b,void * c,cmp_f cmp,void * opaque)493 static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque)
494 {
495 return cmp(a, b, opaque) < 0 ?
496 (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) :
497 (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c ));
498 }
499
500 /* pointer based version with local stack and insertion sort threshhold */
rqsort(void * base,size_t nmemb,size_t size,cmp_f cmp,void * opaque)501 void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
502 {
503 struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack;
504 uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;
505 size_t m4, i, lt, gt, span, span2;
506 int c, depth;
507 exchange_f swap = exchange_func(base, size);
508 exchange_f swap_block = exchange_func(base, size | 128);
509
510 if (nmemb < 2 || size <= 0)
511 return;
512
513 sp->base = (uint8_t *)base;
514 sp->count = nmemb;
515 sp->depth = 0;
516 sp++;
517
518 while (sp > stack) {
519 sp--;
520 ptr = sp->base;
521 nmemb = sp->count;
522 depth = sp->depth;
523
524 while (nmemb > 6) {
525 if (++depth > 50) {
526 /* depth check to ensure worst case logarithmic time */
527 heapsortx(ptr, nmemb, size, cmp, opaque);
528 nmemb = 0;
529 break;
530 }
531 /* select median of 3 from 1/4, 1/2, 3/4 positions */
532 /* should use median of 5 or 9? */
533 m4 = (nmemb >> 2) * size;
534 m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque);
535 swap(ptr, m, size); /* move the pivot to the start or the array */
536 i = lt = 1;
537 pi = plt = ptr + size;
538 gt = nmemb;
539 pj = pgt = top = ptr + nmemb * size;
540 for (;;) {
541 while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) {
542 if (c == 0) {
543 swap(plt, pi, size);
544 lt++;
545 plt += size;
546 }
547 i++;
548 pi += size;
549 }
550 while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) {
551 if (c == 0) {
552 gt--;
553 pgt -= size;
554 swap(pgt, pj, size);
555 }
556 }
557 if (pi >= pj)
558 break;
559 swap(pi, pj, size);
560 i++;
561 pi += size;
562 }
563 /* array has 4 parts:
564 * from 0 to lt excluded: elements identical to pivot
565 * from lt to pi excluded: elements smaller than pivot
566 * from pi to gt excluded: elements greater than pivot
567 * from gt to n excluded: elements identical to pivot
568 */
569 /* move elements identical to pivot in the middle of the array: */
570 /* swap values in ranges [0..lt[ and [i-lt..i[
571 swapping the smallest span between lt and i-lt is sufficient
572 */
573 span = plt - ptr;
574 span2 = pi - plt;
575 lt = i - lt;
576 if (span > span2)
577 span = span2;
578 swap_block(ptr, pi - span, span);
579 /* swap values in ranges [gt..top[ and [i..top-(top-gt)[
580 swapping the smallest span between top-gt and gt-i is sufficient
581 */
582 span = top - pgt;
583 span2 = pgt - pi;
584 pgt = top - span2;
585 gt = nmemb - (gt - i);
586 if (span > span2)
587 span = span2;
588 swap_block(pi, top - span, span);
589
590 /* now array has 3 parts:
591 * from 0 to lt excluded: elements smaller than pivot
592 * from lt to gt excluded: elements identical to pivot
593 * from gt to n excluded: elements greater than pivot
594 */
595 /* stack the larger segment and keep processing the smaller one
596 to minimize stack use for pathological distributions */
597 if (lt > nmemb - gt) {
598 sp->base = ptr;
599 sp->count = lt;
600 sp->depth = depth;
601 sp++;
602 ptr = pgt;
603 nmemb -= gt;
604 } else {
605 sp->base = pgt;
606 sp->count = nmemb - gt;
607 sp->depth = depth;
608 sp++;
609 nmemb = lt;
610 }
611 }
612 /* Use insertion sort for small fragments */
613 for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) {
614 for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size)
615 swap(pj, pj - size, size);
616 }
617 }
618 }
619
620 #endif
621