summaryrefslogtreecommitdiff
path: root/xs.h
diff options
context:
space:
mode:
authorGravatar default2022-09-19 20:41:11 +0200
committerGravatar default2022-09-19 20:41:11 +0200
commit67288a763b8bceadbb128d2cf5bdc431ba8a686f (patch)
tree0a0bc1922016bbd3d3cd2ec3c80a033970280a9f /xs.h
parentProject started. (diff)
downloadsnac2-67288a763b8bceadbb128d2cf5bdc431ba8a686f.tar.gz
snac2-67288a763b8bceadbb128d2cf5bdc431ba8a686f.tar.xz
snac2-67288a763b8bceadbb128d2cf5bdc431ba8a686f.zip
Imported xs.
Diffstat (limited to 'xs.h')
-rw-r--r--xs.h714
1 files changed, 714 insertions, 0 deletions
diff --git a/xs.h b/xs.h
new file mode 100644
index 0000000..40df89f
--- /dev/null
+++ b/xs.h
@@ -0,0 +1,714 @@
1/* copyright (c) 2022 grunfink - MIT license */
2
3#ifndef _XS_H
4
5#define _XS_H
6
7#include <stdio.h>
8#include <string.h>
9#include <stdlib.h>
10#include <ctype.h>
11#include <unistd.h>
12#include <stdarg.h>
13#include <signal.h>
14#include <errno.h>
15
16typedef enum {
17 XSTYPE_NULL = 0x18,
18 XSTYPE_TRUE = 0x06,
19 XSTYPE_FALSE = 0x15,
20 XSTYPE_SOL = 0x11,
21 XSTYPE_LITEM = 0x1f,
22 XSTYPE_EOL = 0x12,
23 XSTYPE_SOD = 0x13,
24 XSTYPE_DITEM = 0x1e,
25 XSTYPE_EOD = 0x14,
26 XSTYPE_NUMBER = 0x17,
27 XSTYPE_STRING = 0x02
28} xstype;
29
30
31/* dynamic strings */
32typedef char d_char;
33
34/* auto-destroyable strings */
35#define xs __attribute__ ((__cleanup__ (_xs_destroy))) d_char
36
37#define _XS_BLK_SIZE 16
38#define _xs_blk_size(sz) ((((sz) + _XS_BLK_SIZE) / _XS_BLK_SIZE) * _XS_BLK_SIZE)
39
40#define xs_debug() kill(getpid(), 5)
41xstype xs_type(const char *data);
42int xs_size(const char *data);
43d_char *xs_dup(const char *data);
44d_char *xs_expand(d_char *data, int offset, int size);
45d_char *xs_collapse(d_char *data, int offset, int size);
46d_char *xs_insert_m(d_char *data, int offset, const char *mem, int size);
47#define xs_insert(data, offset, data2) xs_insert_m(data, offset, data2, xs_size(data2))
48#define xs_append_m(data, mem, size) xs_insert_m(data, xs_size(data) - 1, mem, size)
49d_char *xs_str_new(const char *str);
50#define xs_str_cat(str1, str2) xs_insert(str1, xs_size(str1) - 1, str2)
51d_char *xs_replace(const char *str, const char *sfrom, const char *sto);
52d_char *xs_fmt(const char *fmt, ...);
53int xs_str_in(char *haystack, char *needle);
54int xs_startswith(char *str, char *prefix);
55int xs_endswith(char *str, char *postfix);
56d_char *xs_crop(d_char *str, int start, int end);
57d_char *xs_strip(d_char *str);
58d_char *xs_tolower(d_char *str);
59d_char *xs_list_new(void);
60d_char *xs_list_append_m(d_char *list, const char *mem, int dsz);
61#define xs_list_append(list, data) xs_list_append_m(list, data, xs_size(data))
62int xs_list_iter(char **list, char **value);
63int xs_list_len(char *list);
64char *xs_list_get(char *list, int num);
65int xs_list_in(char *list, char *val);
66d_char *xs_join(char *list, const char *sep);
67d_char *xs_splitn(const char *str, const char *sep, int times);
68#define xs_split(str, sep) xs_splitn(str, sep, 0xfffffff)
69d_char *xs_dict_new(void);
70d_char *xs_dict_append_m(d_char *dict, const char *key, const char *mem, int dsz);
71#define xs_dict_append(dict, key, data) xs_dict_append_m(dict, key, data, xs_size(data))
72int xs_dict_iter(char **dict, char **key, char **value);
73char *xs_dict_get(char *dict, const char *key);
74d_char *xs_dict_del(d_char *dict, const char *key);
75d_char *xs_dict_set(d_char *dict, const char *key, const char *data);
76d_char *xs_val_new(xstype t);
77d_char *xs_number_new(float f);
78float xs_get_number(char *v);
79
80extern int _xs_debug;
81
82
83#ifdef XS_IMPLEMENTATION
84
85int _xs_debug = 0;
86
87void _xs_destroy(char **var)
88{
89 if (_xs_debug)
90 printf("_xs_destroy %p\n", var);
91
92 free(*var);
93}
94
95xstype xs_type(const char *data)
96/* return the type of data */
97{
98 xstype t;
99
100 switch (data[0]) {
101 case XSTYPE_NULL:
102 case XSTYPE_TRUE:
103 case XSTYPE_FALSE:
104 case XSTYPE_SOL:
105 case XSTYPE_EOL:
106 case XSTYPE_SOD:
107 case XSTYPE_EOD:
108 case XSTYPE_LITEM:
109 case XSTYPE_DITEM:
110 case XSTYPE_NUMBER:
111 t = data[0];
112 break;
113 default:
114 t = XSTYPE_STRING;
115 break;
116 }
117
118 return t;
119}
120
121
122int xs_size(const char *data)
123/* returns the size of data in bytes */
124{
125 int len = 0;
126 int c = 0;
127 const char *p;
128
129 if (data == NULL)
130 return 0;
131
132 switch (xs_type(data)) {
133 case XSTYPE_STRING:
134 len = strlen(data) + 1;
135 break;
136
137 case XSTYPE_SOL:
138 /* look for a balanced EOL */
139 do {
140 c += data[len] == XSTYPE_SOL ? 1 : data[len] == XSTYPE_EOL ? -1 : 0;
141 len++;
142 } while (c);
143
144 break;
145
146 case XSTYPE_SOD:
147 /* look for a balanced EOD */
148 do {
149 c += data[len] == XSTYPE_SOD ? 1 : data[len] == XSTYPE_EOD ? -1 : 0;
150 len++;
151 } while (c);
152
153 break;
154
155 case XSTYPE_DITEM:
156 /* calculate the size of the key and the value */
157 p = data + 1;
158 p += xs_size(p);
159 p += xs_size(p);
160
161 len = p - data;
162
163 break;
164
165 case XSTYPE_LITEM:
166 /* it's the size of the item + 1 */
167 p = data + 1;
168 p += xs_size(p);
169
170 len = p - data;
171
172 break;
173
174 case XSTYPE_NUMBER:
175 len = sizeof(float) + 1;
176
177 break;
178
179 default:
180 len = 1;
181 }
182
183 return len;
184}
185
186
187d_char *xs_dup(const char *data)
188/* creates a duplicate of data */
189{
190 int sz = xs_size(data);
191 d_char *s = malloc(_xs_blk_size(sz));
192
193 memcpy(s, data, sz);
194
195 return s;
196}
197
198
199d_char *xs_expand(d_char *data, int offset, int size)
200/* opens a hole in data */
201{
202 int sz = xs_size(data);
203 int n;
204
205 /* open room */
206 if (sz == 0 || _xs_blk_size(sz) != _xs_blk_size(sz + size))
207 data = realloc(data, _xs_blk_size(sz + size));
208
209 /* move up the rest of the data */
210 for (n = sz + size - 1; n >= offset + size; n--)
211 data[n] = data[n - size];
212
213 return data;
214}
215
216
217d_char *xs_collapse(d_char *data, int offset, int size)
218/* shrinks data */
219{
220 int sz = xs_size(data);
221 int n;
222
223 /* don't try to delete beyond the limit */
224 if (offset + size > sz)
225 size = sz - offset;
226
227 /* shrink total size */
228 sz -= size;
229
230 for (n = offset; n < sz; n++)
231 data[n] = data[n + size];
232
233 return realloc(data, _xs_blk_size(sz));
234}
235
236
237d_char *xs_insert_m(d_char *data, int offset, const char *mem, int size)
238/* inserts a memory block */
239{
240 data = xs_expand(data, offset, size);
241 memcpy(data + offset, mem, size);
242
243 return data;
244}
245
246
247/** strings **/
248
249d_char *xs_str_new(const char *str)
250/* creates a new string */
251{
252 return xs_insert(NULL, 0, str ? str : "");
253}
254
255
256d_char *xs_replace(const char *str, const char *sfrom, const char *sto)
257/* replaces all occurrences of sfrom with sto in str */
258{
259 d_char *s;
260 char *ss;
261 int sfsz;
262
263 /* cache the sizes */
264 sfsz = strlen(sfrom);
265
266 /* create the new string */
267 s = xs_str_new(NULL);
268
269 while ((ss = strstr(str, sfrom)) != NULL) {
270 /* copy the first part */
271 s = xs_append_m(s, str, ss - str);
272
273 /* copy sto */
274 s = xs_str_cat(s, sto);
275
276 /* move forward */
277 str = ss + sfsz;
278 }
279
280 /* copy the rest */
281 s = xs_str_cat(s, str);
282
283 return s;
284}
285
286
287d_char *xs_fmt(const char *fmt, ...)
288/* formats a string with printf()-like marks */
289{
290 int n;
291 d_char *s = NULL;
292 va_list ap;
293
294 va_start(ap, fmt);
295 n = vsnprintf(s, 0, fmt, ap);
296 va_end(ap);
297
298 if (n > 0) {
299 n = _xs_blk_size(n + 1);
300 s = calloc(n, 1);
301
302 va_start(ap, fmt);
303 n = vsnprintf(s, n, fmt, ap);
304 va_end(ap);
305 }
306
307 return s;
308}
309
310
311int xs_str_in(char *haystack, char *needle)
312/* finds needle in haystack and returns the offset or -1 */
313{
314 char *s;
315 int r = -1;
316
317 if ((s = strstr(haystack, needle)) != NULL)
318 r = s - haystack;
319
320 return r;
321}
322
323
324int xs_startswith(char *str, char *prefix)
325/* returns true if str starts with prefix */
326{
327 return !!(xs_str_in(str, prefix) == 0);
328}
329
330
331int xs_endswith(char *str, char *postfix)
332/* returns true if str ends with postfix */
333{
334 int ssz = strlen(str);
335 int psz = strlen(postfix);
336
337 return !!(ssz >= psz && memcmp(postfix, str + ssz - psz, psz) == 0);
338}
339
340
341d_char *xs_crop(d_char *str, int start, int end)
342/* crops the d_char to be only from start to end */
343{
344 int sz = strlen(str);
345
346 if (end <= 0)
347 end = sz + end;
348
349 /* crop from the top */
350 str[end] = '\0';
351
352 /* crop from the bottom */
353 str = xs_collapse(str, 0, start);
354
355 return str;
356}
357
358
359d_char *xs_strip(d_char *str)
360/* strips the string of blanks from the start and the end */
361{
362 int s, e;
363
364 for (s = 0; isspace(str[s]); s++);
365 for (e = strlen(str); e > 0 && isspace(str[e - 1]); e--);
366
367 return xs_crop(str, s, e);
368}
369
370
371d_char *xs_tolower(d_char *str)
372/* convert to lowercase */
373{
374 int n;
375
376 for (n = 0; str[n]; n++)
377 str[n] = tolower(str[n]);
378
379 return str;
380}
381
382
383/** lists **/
384
385d_char *xs_list_new(void)
386/* creates a new list */
387{
388 d_char *list;
389
390 list = malloc(_xs_blk_size(2));
391 list[0] = XSTYPE_SOL;
392 list[1] = XSTYPE_EOL;
393
394 return list;
395}
396
397
398d_char *xs_list_append_m(d_char *list, const char *mem, int dsz)
399/* adds a memory block to the list */
400{
401 char c = XSTYPE_LITEM;
402 int lsz = xs_size(list);
403
404 list = xs_insert_m(list, lsz - 1, &c, 1);
405 list = xs_insert_m(list, lsz, mem, dsz);
406
407 return list;
408}
409
410
411int xs_list_iter(char **list, char **value)
412/* iterates a list value */
413{
414 int goon = 1;
415 char *p;
416
417 if (list == NULL || *list == NULL)
418 return 0;
419
420 p = *list;
421
422 /* skip a possible start of the list */
423 if (*p == XSTYPE_SOL)
424 p++;
425
426 /* an element? */
427 if (*p == XSTYPE_LITEM) {
428 p++;
429
430 *value = p;
431
432 p += xs_size(*value);
433 }
434 else {
435 /* end of list */
436 p++;
437 goon = 0;
438 }
439
440 /* store back the pointer */
441 *list = p;
442
443 return goon;
444}
445
446
447int xs_list_len(char *list)
448/* returns the number of elements in the list */
449{
450 int c = 0;
451 char *v;
452
453 while (xs_list_iter(&list, &v))
454 c++;
455
456 return c;
457}
458
459
460char *xs_list_get(char *list, int num)
461/* returns the element #num */
462{
463 char *v, *r = NULL;
464 int c = 0;
465
466 if (num < 0)
467 num = xs_list_len(list) + num;
468
469 while (xs_list_iter(&list, &v)) {
470 if (c == num) {
471 r = v;
472 break;
473 }
474 c++;
475 }
476
477 return r;
478}
479
480
481int xs_list_in(char *list, char *val)
482/* returns the position of val in list or -1 */
483{
484 int n = 0;
485 int r = -1;
486 char *v;
487 int sz = xs_size(val);
488
489 while (r == -1 && xs_list_iter(&list, &v)) {
490 int vsz = xs_size(v);
491
492 if (sz == vsz && memcmp(val, v, sz) == 0)
493 r = n;
494
495 n++;
496 }
497
498 return r;
499}
500
501
502d_char *xs_join(char *list, const char *sep)
503/* joins a list into a string */
504{
505 d_char *s;
506 char *v;
507 int c = 0;
508
509 s = xs_str_new(NULL);
510
511 while (xs_list_iter(&list, &v)) {
512 /* refuse to join non-string values */
513 if (xs_type(v) == XSTYPE_STRING) {
514 /* add the separator */
515 if (c != 0)
516 s = xs_str_cat(s, sep);
517
518 /* add the element */
519 s = xs_str_cat(s, v);
520
521 c++;
522 }
523 }
524
525 return s;
526}
527
528
529d_char *xs_splitn(const char *str, const char *sep, int times)
530/* splits a string into a list upto n times */
531{
532 int sz = strlen(sep);
533 char *ss;
534 d_char *list;
535
536 list = xs_list_new();
537
538 while (times > 0 && (ss = strstr(str, sep)) != NULL) {
539 /* add the first part (without the asciiz) */
540 list = xs_list_append_m(list, str, ss - str);
541
542 /* add the asciiz */
543 list = xs_str_cat(list, "");
544
545 /* skip past the separator */
546 str = ss + sz;
547
548 times--;
549 }
550
551 /* add the rest of the string */
552 list = xs_list_append(list, str);
553
554 return list;
555}
556
557
558/** dicts **/
559
560d_char *xs_dict_new(void)
561/* creates a new dict */
562{
563 d_char *dict;
564
565 dict = malloc(_xs_blk_size(2));
566 dict[0] = XSTYPE_SOD;
567 dict[1] = XSTYPE_EOD;
568
569 return dict;
570}
571
572
573d_char *xs_dict_append_m(d_char *dict, const char *key, const char *mem, int dsz)
574/* adds a memory block to the dict */
575{
576 char c = XSTYPE_DITEM;
577 int sz = xs_size(dict);
578 int ksz = xs_size(key);
579
580 dict = xs_insert_m(dict, sz - 1, &c, 1);
581 dict = xs_insert_m(dict, sz, key, ksz);
582 dict = xs_insert_m(dict, sz + ksz, mem, dsz);
583
584 return dict;
585}
586
587
588int xs_dict_iter(char **dict, char **key, char **value)
589/* iterates a dict value */
590{
591 int goon = 1;
592 char *p;
593
594 if (dict == NULL || *dict == NULL)
595 return 0;
596
597 p = *dict;
598
599 /* skip a possible start of the list */
600 if (*p == XSTYPE_SOD)
601 p++;
602
603 /* an element? */
604 if (*p == XSTYPE_DITEM) {
605 p++;
606
607 *key = p;
608 p += xs_size(*key);
609
610 *value = p;
611 p += xs_size(*value);
612 }
613 else {
614 /* end of list */
615 p++;
616 goon = 0;
617 }
618
619 /* store back the pointer */
620 *dict = p;
621
622 return goon;
623}
624
625
626char *xs_dict_get(char *dict, const char *key)
627/* returns the value directed by key */
628{
629 char *k, *v, *r = NULL;
630
631 while (xs_dict_iter(&dict, &k, &v)) {
632 if (strcmp(k, key) == 0) {
633 r = v;
634 break;
635 }
636 }
637
638 return r;
639}
640
641
642d_char *xs_dict_del(d_char *dict, const char *key)
643/* deletes a key */
644{
645 char *k, *v;
646 char *p = dict;
647
648 while (xs_dict_iter(&p, &k, &v)) {
649 if (strcmp(k, key) == 0) {
650 /* the address of the item is just behind the key */
651 char *i = k - 1;
652
653 dict = xs_collapse(dict, i - dict, xs_size(i));
654 break;
655 }
656 }
657
658 return dict;
659}
660
661
662d_char *xs_dict_set(d_char *dict, const char *key, const char *data)
663/* sets (replaces) a key */
664{
665 /* delete the possibly existing key */
666 dict = xs_dict_del(dict, key);
667
668 /* append the data */
669 dict = xs_dict_append(dict, key, data);
670
671 return dict;
672}
673
674
675/** other values **/
676
677d_char *xs_val_new(xstype t)
678/* adds a new special value */
679{
680 d_char *v = malloc(_xs_blk_size(1));
681
682 v[0] = t;
683
684 return v;
685}
686
687
688d_char *xs_number_new(float f)
689/* adds a new number value */
690{
691 d_char *v = malloc(_xs_blk_size(1 + sizeof(float)));
692
693 v[0] = XSTYPE_NUMBER;
694 memcpy(&v[1], &f, sizeof(float));
695
696 return v;
697}
698
699
700float xs_get_number(char *v)
701/* gets the number as a float */
702{
703 float f = 0.0;
704
705 if (v[0] == XSTYPE_NUMBER)
706 memcpy(&f, &v[1], sizeof(float));
707
708 return f;
709}
710
711
712#endif /* XS_IMPLEMENTATION */
713
714#endif /* _XS_H */