1 /************************************************************************
2 * Copyright (C) 2024 Francesco Palumbo <phranz.dev@gmail.com>, Naples Italy
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *************************************************************************/
21 #define CUTILS_VERSION "0.2.1"
29 #if defined(__linux__)
30 #include <sys/sysmacros.h>
32 #include <sys/types.h>
36 * Equivalent to p->func(p, a, b)
38 #define __(p, f, ...) (p->f(p, ## __VA_ARGS__))
41 * Allocate memory for a type (calls type's _init)
44 * ...: additional params
46 #define alloc(t, ...) (t ## _init(malloc(sizeof(t)), ## __VA_ARGS__))
50 * Release memory hold by type's instance (calls ptr's free)
54 #define release(p) (p ? (p->free(p), (p=NULL)) : NULL)
57 * Utility to call free and setting pointer to NULL
61 #define zfree(p) (free(p), (p=NULL))
64 * Declare a vector of a specific type
69 #define dectype_vector(t, n) \
73 void (*free)(struct n*); \
74 int (*push)(struct n*, t); \
75 int (*push_back)(struct n*, t); \
76 int (*pop)(struct n*, t*); \
77 int (*pop_back)(struct n*, t*); \
78 int (*get)(struct n*, size_t, t*); \
79 int (*first)(struct n*, t*); \
80 int (*last)(struct n*, t*); \
81 int (*put)(struct n*, size_t, t); \
82 int (*insert)(struct n*, size_t, t); \
83 int (*remove)(struct n*, size_t); \
84 void (*clear)(struct n*); \
88 #define define_vector(t, n) \
90 * Add an element to the end of a vector
93 * v: a value of type t
95 * return: boolean operation success/failure
97 static int n ## _push(n* p, t v) { \
100 t* mem = realloc(p->data, sizeof(t)*(p->count+1)); \
107 ++*(size_t*)&p->count; \
111 * Add an element to the beginning of a vector
114 * v (output): a value of type t
116 * return: boolean operation success/failure
118 static int n ## _push_back(n* p, t v) { \
119 return p->insert(p, 0, v); \
122 * Get and remove the last element of a vector
125 * v (output): a pointer of type t
127 * return: boolean operation success/failure
129 static int n ## _pop(n* p, t* v) { \
130 if (!p->count || !v) \
134 *v = p->data[p->count-1]; \
135 if (!(p->count-1)) { \
139 t* mem = realloc(p->data, sizeof(t)*(p->count-1)); \
145 --*(size_t*)&p->count; \
149 * Get and remove the first element of a vector
152 * v (output): a pointer of type t
154 * return: boolean operation success/failure
156 static int n ## _pop_back(n* p, t* v) { \
157 if (!p->count || !v) \
160 if (!(p->count-1)) { \
163 --*(size_t*)&p->count; \
166 for (size_t x=0; x+1<p->count; ++x) \
167 p->data[x] = p->data[x+1]; \
168 t* mem = realloc(p->data, sizeof(t)*(p->count-1)); \
173 --*(size_t*)&p->count; \
177 * Get a vector element by index
181 * v (output): a pointer of type t
183 * return: boolean operation success/failure
185 static int n ## _get(n* p, size_t i, t* v) { \
186 if (!p->count || i>p->count-1 || !v) \
192 * Get the first element of a vector
195 * v (output): a pointer of type t
197 * return: boolean operation success/failure
199 static int n ## _first(n* p, t* v) { \
200 if (!p->count || !v) \
206 * Get the last element of a vector
209 * v (output): a pointer of type t
211 * return: boolean operation success/failure
213 static int n ## _last(n* p, t* v) { \
214 if (!p->count || !v) \
216 *v = p->data[p->count-1]; \
220 * Change the value of a vector by index
224 * v: a value of type t
226 * return: boolean operation success/failure
228 static int n ## _put(n* p, size_t i, t v) { \
229 if (!p->count || i>p->count-1) \
235 * Remove a vector element by index
240 * return: boolean operation success/failure
242 static int n ## _remove(n* p, size_t i) { \
247 t l = p->data[p->count-1]; \
248 if (!(p->count-1)) { \
251 --*(size_t*)&p->count; \
254 t* mem = realloc(p->data, sizeof(t)*(p->count-1)); \
259 --*(size_t*)&p->count; \
260 for (size_t x=i; x+1<p->count; ++x) \
261 p->data[x] = p->data[x+1]; \
263 p->data[p->count-1] = l; \
267 * Insert an element at index
271 * v: a value of type t
273 * return: boolean operation success/failure
275 static int n ## _insert(n* p, size_t i, t v) { \
276 if (i>p->count || !(p->count+1)) \
278 t* mem = realloc(p->data, sizeof(t)*(p->count+1)); \
284 if (i != p->count) { \
285 p->data[p->count] = p->data[p->count-1]; \
286 for (size_t x=p->count; x!=i; --x) \
287 p->data[x] = p->data[x-1]; \
290 ++*(size_t*)&p->count; \
294 * Remove all elements from a vector
298 static void n ## _clear(n* p) { \
299 *(size_t*)&p->count = 0; \
304 * Release vector's resources
308 static void n ## _free(n* p) { \
313 * Initialize vector's resources
317 n* n ## _init(n* p) { \
320 memset(p, 0, sizeof(*p)); \
321 p->push = n ## _push; \
322 p->push_back = n ## _push_back; \
323 p->pop = n ## _pop; \
324 p->pop_back = n ## _pop_back; \
325 p->put = n ## _put; \
326 p->get = n ## _get; \
327 p->first = n ## _first; \
328 p->last = n ## _last; \
329 p->remove = n ## _remove; \
330 p->insert = n ## _insert; \
331 p->clear = n ## _clear; \
332 p->free = n ## _free; \
338 * Declare a list of a specific type
343 #define dectype_list(t, n) \
344 typedef struct __node_ ## n { \
345 struct __node_ ## n* prev; \
346 struct __node_ ## n* next; \
349 dectype_pair(size_t, __node_ ## n*, __cached_node_ ## n) \
351 __node_ ## n* head; \
352 __node_ ## n* tail; \
353 __cached_node_ ## n cached; \
355 void (*free)(struct n*); \
356 int (*push)(struct n*, t); \
357 int (*push_back)(struct n*, t); \
358 int (*put)(struct n*, size_t, t); \
359 int (*insert)(struct n*, size_t, t); \
360 int (*pop)(struct n*, t*); \
361 int (*pop_back)(struct n*, t*); \
362 int (*get)(struct n*, size_t, t*); \
363 int (*first)(struct n*, t*); \
364 int (*last)(struct n*, t*); \
365 int (*remove)(struct n*, size_t); \
366 void (*clear)(struct n*); \
370 #define define_list(t, n) \
371 static int __ ## n ## _htalloc(n* p) { \
372 p->head = calloc(1, sizeof(__node_ ## n)); \
375 p->head->next = NULL; \
376 p->head->prev = NULL; \
380 static int __ ## n ## _talloc(n* p) { \
381 __node_ ## n* node = calloc(1, sizeof(__node_ ## n)); \
384 p->tail->next = node; \
385 node->prev = p->tail; \
391 * Add an element to the end of a list
394 * v: a value of type t
396 * return: boolean operation success/failure
398 static int n ## _push(n* p, t v) { \
399 if (!p->head || !p->tail) { \
400 if (!__ ## n ## _htalloc(p)) \
403 p->cached.val = p->head; \
407 if(!__ ## n ## _talloc(p)) \
410 p->cached.val = p->tail; \
412 ++*(size_t*)&p->count; \
413 p->cached.key = p->count-1; \
417 * Add an element to the beginning of a list
420 * v: a value of type t
422 * return: boolean operation success/failure
424 static int n ## _push_back(n* p, t v) { \
425 return p->insert(p, 0, v); \
428 * Insert an element at index
432 * v: a value of type t
434 * return: boolean operation success/failure
436 static int n ## _insert(n* p, size_t i, t v) { \
437 if (i>p->count || !(p->count+1)) \
440 return p->push(p, v); \
441 __node_ ## n* node = calloc(1, sizeof(__node_ ## n)); \
446 node->next = p->head; \
447 p->head->prev = node; \
451 __node_ ## n* c = p->head; \
453 if (p->cached.key >= i && p->cached.val) { \
457 for (; j!=i; ++j, c=c->next); \
458 node->prev = c->prev; \
460 c->prev->next = node; \
464 ++*(size_t*)&p->count; \
466 p->cached.val = node; \
470 * Change the value of a list by index
474 * v: a value of type t
476 * return: boolean operation success/failure
478 static int n ## _put(n* p, size_t i, t v) { \
481 if (p->cached.key == i && p->cached.val) { \
482 p->cached.val->data = v; \
485 __node_ ## n* c = p->head; \
486 if (i == p->count-1) \
489 for (size_t j=0; j!=i && c->next; ++j, c=c->next); \
496 * Get and remove the last element of a list
499 * v (output): a pointer of type t
501 * return: boolean operation success/failure
503 static int n ## _pop(n* p, t* v) { \
504 if (!p->tail || !v) \
506 __node_ ## n* tofree = p->tail; \
507 *v = p->tail->data; \
508 if (p->tail->prev) { \
509 p->tail->prev->next = NULL; \
510 p->tail = p->tail->prev; \
512 p->head = p->tail = NULL; \
515 --*(size_t*)&p->count; \
517 p->cached.key = p->count-1; \
518 p->cached.val = p->tail; \
520 memset(&p->cached, 0, sizeof(p->cached)); \
525 * Get and remove the first element of a list
528 * v (output): a pointer of type t
530 * return: boolean operation success/failure
532 static int n ## _pop_back(n* p, t* v) { \
533 if (!p->count || !v) \
535 if (p->get(p, 0, v)) { \
537 memset(&p->cached, 0, sizeof(p->cached)); \
542 * Get a list element by index
546 * v (output): a pointer of type t
548 * return: boolean operation success/failure
550 static int n ## _get(n* p, size_t i, t* v) { \
551 if (!p->count || !v || i>=p->count) \
553 if (i<p->count && p->cached.key == i && p->cached.val) { \
554 *v = p->cached.val->data; \
557 __node_ ## n* c = p->head; \
559 if (p->cached.key < i && p->cached.val) { \
563 for (; j!=i && c; ++j) \
571 * Get the first element of a list
574 * v (output): a pointer of type t
576 * return: boolean operation success/failure
578 static int n ## _first(n* p, t* v) { \
579 if (!p->count || !v) \
581 *v = p->head->data; \
585 * Get the last element of a list
588 * v (output): a pointer of type t
590 * return: boolean operation success/failure
592 static int n ## _last(n* p, t* v) { \
593 if (!p->count || !v) \
595 *v = p->tail->data; \
599 * Remove a list element by index
604 * return: boolean operation success/failure
606 static int n ## _remove(n* p, size_t i) { \
611 if (p->cached.key <= i) \
612 memset(&p->cached, 0, sizeof(p->cached)); \
613 __node_ ## n* c = p->head; \
614 for (size_t j=0; j!=i; ++j) \
616 if ((c == p->head) && (c == p->tail)) { \
617 p->head = p->tail = NULL; \
618 } else if (c == p->head) { \
619 c->next->prev = NULL; \
621 } else if (c == p->tail) { \
622 c->prev->next = NULL; \
625 c->next->prev = c->prev; \
626 c->prev->next = c->next; \
629 --*(size_t*)&p->count; \
633 * Remove all elements from a list
637 static void n ## _clear(n* p) { \
640 __node_ ## n* i = p->head; \
647 *(size_t*)&p->count = 0; \
648 p->head = p->tail = NULL; \
649 memset(&p->cached, 0, sizeof(p->cached)); \
652 * Release list's resources
656 static void n ## _free(n* p) { \
661 * Initialize list's resources
665 n* n ## _init(n* p) { \
668 memset(p, 0, sizeof(*p)); \
669 p->push = n ## _push; \
670 p->push_back = n ## _push_back; \
671 p->put = n ## _put; \
672 p->insert = n ## _insert; \
673 p->pop = n ## _pop; \
674 p->pop_back = n ## _pop_back; \
675 p->get = n ## _get; \
676 p->first = n ## _first; \
677 p->last = n ## _last; \
678 p->remove = n ## _remove; \
679 p->clear = n ## _clear; \
680 p->free = n ## _free; \
685 * Declare a pair of specific types.
691 #define dectype_pair(t1, t2, n) \
695 void (*free)(struct n*); \
697 n* n ## _init(struct n*);
699 #define define_pair(t1, t2, n) \
700 static void n ## _free(struct n* p) { \
703 n* n ## _init(struct n* p) { \
706 memset(p, 0, sizeof(*p)); \
707 p->free = n ## _free; \
712 * Initial number of elements of a map
719 * Default load factor
726 * Declare a map of a specific type.
727 * By default pointers/values are hashed,
728 * not whole strings; to change this behaviour
729 * and use strings (for maps that have strings
730 * as keys), set strcmp field to 1:
737 #define dectype_map(t1, t2, n) \
738 dectype_pair(t1, t2, __pair_ ## n) \
739 dectype_list(__pair_ ## n*, __bucket_ ## n) \
740 dectype_vector(__pair_ ## n*, __items_ ## n) \
741 dectype_vector(__bucket_ ## n*, __vec_ ## n) \
744 __pair_ ## n* cached; \
750 void (*free)(struct n*); \
751 int (*full)(struct n*); \
752 int (*rehash)(struct n*); \
753 int (*insert)(struct n*, t1, t2); \
754 __items_ ## n* (*items)(struct n*); \
755 int (*get)(struct n*, t1, t2*); \
756 int (*item)(struct n*, t1, void*); \
757 int (*contains)(struct n*, t1); \
758 int (*remove)(struct n*, t1); \
759 void (*clear)(struct n*); \
763 #define define_map(t1, t2, n) \
764 define_pair(t1, t2, __pair_ ## n) \
765 define_list(__pair_ ## n*, __bucket_ ## n) \
766 define_vector(__pair_ ## n*, __items_ ## n) \
767 define_vector(__bucket_ ## n*, __vec_ ## n) \
769 * Check if hashmap is saturated (have to be
774 * return: boolean saturated
776 static int n ## _full(n* p) { \
777 return p->count >= (p->size * p->lfactor); \
780 * Returns a vector with key-value pairs;
781 * the vector must be freed after use.
785 * return: pointer to vector of pairs on success,
788 static __items_ ## n* n ## _items(n* p) { \
789 __items_ ## n* b = alloc(__items_ ## n); \
792 size_t r = p->count; \
793 for (size_t i=0; i<p->data->count && r; ++i) \
794 if (p->data->get(p->data, i, &l)) \
796 for (size_t j=0; j<l->count; ++j) \
797 if (l->get(l, j, &e)) { \
798 if (b->push(b, e)) { \
812 * return: boolean operation success/failure
814 static int n ## _rehash(n* p) { \
815 if (p->r || (p->size > (p->size+p->size))) \
818 __bucket_ ## n* r = alloc(__bucket_ ## n); \
822 while (p->data->count) { \
823 if (p->data->pop(p->data, &b)) { \
826 if (b->pop(b, &e)) { \
827 if (!r->push(r, e)) { \
828 p->data->push(p->data, b); \
841 while (p->count >= (p->size*p->lfactor)) { \
842 if (p->size > (p->size+p->size)) { \
843 p->size = ((size_t)-1); \
848 *(size_t*)&p->count = 0; \
849 for (size_t i=0; i<p->size; ++i) \
850 if (!p->data->push(p->data, NULL)) \
853 if (r->pop(r, &e)) { \
854 if (p->insert(p, e->key, e->val)) { \
865 static size_t __ ## n ## _hash(n* p, t1 k) { \
869 sprintf(b, "%p", (void*)(size_t)k); \
870 s = p->strcmp ? (char*)(size_t)strtoull(b, NULL, 16) : b; \
871 size_t l = strlen(s); \
873 for (size_t i=0; i<l; ++i) \
874 h = (h << 7) + (i ^ s[i]) + l; \
875 return h % p->size; \
877 static int __ ## n ## _cmpkeys(n* p, t1 ok, t1 nk) { \
881 return eq((char*)(size_t)ok, (char*)(size_t)nk); \
885 * Insert key and value in map
889 * v: value of type t2
891 * return: boolean operation success/failure
893 static int n ## _insert(n* p, t1 k, t2 v) { \
896 size_t x = __ ## n ## _hash(p, k); \
899 if (!p->data->get(p->data, x, &b)) \
905 b = alloc(__bucket_ ## n); \
908 if (!p->data->put(p->data, x, b)) { \
913 for (size_t i=0; i<b->count; ++i) \
914 if (b->get(b, i, &e)) \
915 if (__ ## n ## _cmpkeys(p, e->key, k)) { \
920 e = alloc(__pair_ ## n); \
929 if (!b->push(b, e)) { \
936 ++*(size_t*)&p->count; \
940 * Get a value from a key
944 * v (output): pointer value of type t2
946 * return: boolean operation success/failure
948 static int n ## _get(n* p, t1 k, t2* v) { \
949 if (!p->count || !v) \
951 if (p->cached && __ ## n ## _cmpkeys(p, p->cached->key, k)) { \
952 *v = p->cached->val; \
957 size_t x = __ ## n ## _hash(p, k); \
958 if (!p->data->get(p->data, x, &b)) \
960 if (b && b->count) { \
961 for (size_t i=0; i<b->count; ++i) { \
962 if (!b->get(b, i, &e)) \
964 if (__ ## n ## _cmpkeys(p, e->key, k)) { \
974 * Get key, value pair from a key
978 * v (output): pair of type <t1, t2>
980 * return: boolean operation success/failure
982 static int n ## _item(n* p, t1 k, void* v) { \
983 if (!p->count || !v) \
985 __pair_ ## n** t = (__pair_ ## n**)v; \
986 if (p->cached && __ ## n ## _cmpkeys(p, p->cached->key, k)) { \
992 size_t x = __ ## n ## _hash(p, k); \
993 if (!p->data->get(p->data, x, &b)) \
995 if (b && b->count) { \
996 for (size_t i=0; i<b->count; ++i) { \
997 if (!b->get(b, i, &e)) \
999 if (__ ## n ## _cmpkeys(p, e->key, k)) { \
1009 * Check if there is a key in a map
1014 * return: boolean contains key
1016 static int n ## _contains(n* p, t1 k) { \
1018 return p->get(p, k, &tmp); \
1021 * Remove key and value by key
1026 * return: boolean operation success/failure
1028 static int n ## _remove(n* p, t1 k) { \
1031 if (p->cached && __ ## n ## _cmpkeys(p, p->cached->key, k)) \
1033 size_t x = __ ## n ## _hash(p, k); \
1034 __bucket_ ## n* b; \
1036 if (!p->data->get(p->data, x, &b)) \
1038 if (b && b->count) { \
1039 for (size_t i=0; i<b->count; ++i) { \
1040 if (!b->get(b, i, &e)) \
1042 if (__ ## n ## _cmpkeys(p, e->key, k)) { \
1045 --*(size_t*)&p->count; \
1053 * Remove all items from a map
1057 * return: boolean operation success/failure
1059 static void n ## _clear(n* p) { \
1061 __bucket_ ## n* b; \
1063 while (p->data->count) { \
1064 if (!p->data->pop(p->data, &b)) \
1069 if (b->pop(b, &e)) \
1076 * Release map's resources
1080 static void n ## _free(n* p) { \
1082 p->data->free(p->data); \
1086 * Initialize map's resources
1090 n* n ## _init(n* p) { \
1093 memset(p, 0, sizeof(*p)); \
1094 p->full = n ## _full; \
1095 p->rehash = n ## _rehash; \
1096 p->insert = n ## _insert; \
1097 p->items = n ## _items; \
1098 p->get = n ## _get; \
1099 p->item = n ## _item; \
1100 p->contains = n ## _contains; \
1101 p->remove = n ## _remove; \
1102 p->clear = n ## _clear; \
1103 p->free = n ## _free; \
1104 p->data = alloc(__vec_ ## n); \
1107 p->size = MAPSIZE; \
1108 p->lfactor = LFACTOR; \
1109 for (size_t i=0; i<p->size; ++i) \
1110 p->data->push(p->data, NULL); \
1115 * Reverse a vector or a list in-place.
1117 * e: container item's type
1118 * c: pointer to container
1120 #define vlrev(e, c) \
1122 if (!c || c->count < 2) \
1127 size_t j = c->count-1; \
1139 * Swap two items of a vector or a list by index.
1141 * c: pointer to container
1142 * e: container item's type
1146 #define vlswap(c, e, i1, i2) \
1148 if (!c || i1 > c->count-1 || i2 > c->count-1 || i1 == i2) \
1154 c->get(c, __i1, &e1); \
1155 c->get(c, __i2, &e2); \
1156 c->put(c, __i1, e2); \
1157 c->put(c, __i2, e1); \
1161 * For each item (pair) of a map
1166 * p: pointer to pair of contained type
1167 * c: code to execute
1169 #define eachitem(m, t, p, c) \
1173 vec_ ## t* __v = (vec_ ## t*)m->items(m); \
1176 for (size_t __i=0; __i<__v->count; ++__i) { \
1177 if (__v->get(__v, __i, &p)) { \
1185 * For each element of a vector/list
1188 * p: list/vector pointer
1189 * e: pointer to a value of contained type
1190 * c: code to execute
1192 #define each(p, e, c) \
1196 for (size_t __i=0; __i<p->count; ++__i) { \
1197 if (p->get(p, __i, &e)) { \
1204 * Call a function on a pointer
1205 * at the end of a block of code
1207 * p: pointer to a value
1209 * c: code to execute
1211 #define with(p, f, c) \
1220 * Splits a string into multiple
1221 * strings and puts them into
1222 * an already allocated list or vector.
1223 * If a delimiter replacer is given (r),
1224 * and it's not NULL, then append a copy
1225 * of it to list or vector.s
1227 * s: string to split
1229 * p: pointer to a list or a vector
1230 * r: string to replace delimiter
1232 #define ssplit(s, d, p, r) \
1236 char* __sub = NULL; \
1239 size_t __sl = strlen(s); \
1240 for (size_t __i=0; __i<__sl; ++__i) { \
1241 if (s[__i] == d) { \
1243 __sub = calloc(1, sizeof(char)*(__l+1)); \
1247 for (size_t __x=0; __x<__l; ++__x, ++__j) \
1248 __sub[__x] = s[__j]; \
1249 p->push(p, __sub); \
1253 p->push(p, salloc(r)); \
1258 if (__i==__sl-1) { \
1259 __sub = calloc(1, sizeof(char)*(__l+1)); \
1263 for (size_t __x=0; __x<__l; ++__x, ++__j) \
1264 __sub[__x] = s[__j]; \
1265 p->push(p, __sub); \
1273 * Join a vector of strings or a list of strings
1274 * into a single string. If the output buffer (b) is NULL, the
1275 * memory will be automatically allocated, and must be freed
1276 * after use; otherwise this macro simply uses the given
1279 * p: string to split
1280 * s: delimiter string
1283 #define cjoin(p, s, b) \
1285 if (!p || !p->count) \
1295 b = calloc(1, sizeof(char)); \
1302 for (size_t __i=0; __i<p->count; ++__i) { \
1303 if (p->get(p, __i, &__c) && __c) { \
1304 __lc = strlen(__c); \
1305 __ls = (__i+1==p->count) ? 0 : strlen(s); \
1308 __m = realloc(b, sizeof(char)*(__lb+__lc+__ls+1)); \
1316 memcpy(b+__lb, __c, __lc); \
1317 memcpy(b+__lb+__lc, s, __ls); \
1318 __lb += __lc+__ls; \
1325 * Check if a vector of strings or a list of strings
1326 * contains a specified string.
1328 * p: list/vector of strings
1329 * v: string to search
1330 * r: boolean output value
1332 #define scont(p, v, r) \
1344 #define declare_utils() \
1345 int eq(const char*, const char*); \
1346 int ieq(const char*, const char*); \
1347 char* sjoin(char*, const char*, ...); \
1348 int oneof(char, const char*); \
1349 char* shellsub(char*, const char*); \
1350 int cmdret(const char*); \
1351 char* trim(char*); \
1352 char* salloc(char*); \
1353 char* sadd(char*, const char*); \
1354 char* sins(char*, const char*, size_t); \
1355 char* srep(char*, const char*, const char*, const char*, size_t); \
1362 #define define_utils() \
1364 * Compare 2 strings for equality
1369 * return: boolean is/not equal
1371 int eq(const char* a, const char* b) { \
1376 return !strcmp(a, b); \
1379 * Compare 2 strings for equality (case insensitive)
1384 * return: boolean is/not equal
1386 int ieq(const char* a, const char* b) { \
1391 for (; *a; a++, b++) { \
1392 if ((*a < 0x41 || (*a >= 0x5B && *a <= 0x60) || *a > 0x7A) && *a != *b) \
1394 if ((*a & ~(1<<5)) != (*b & ~(1<<5))) \
1400 * Joins a variable number of strings into a single
1401 * one, using a specified separator. If a NULL
1402 * buffer is given, then the memory is automatically
1403 * allocated, and must be freed after use; otherwise
1404 * the given buffer is used. The final argument to this
1405 * function must be NULL!
1408 * s: separator string
1409 * ...: strings to join
1411 * return: string buffer
1413 char* sjoin(char* r, const char* s, ...) { \
1418 va_start(args, s); \
1423 size_t ls = strlen(s); \
1433 a = va_arg(args, const char*); \
1437 va_start(args, s); \
1438 for (size_t i=0; i<c; ++i) { \
1439 const char* a = va_arg(args, const char*); \
1441 ls = (i+1==c) ? 0 : strlen(s); \
1443 char* m = realloc(r, sizeof(char)*(lr+la+ls+1)); \
1451 memcpy(r+lr, a, la); \
1452 memcpy(r+lr+la, s, ls); \
1460 * Checks if a character is present inside
1463 * c: character to check
1464 * s: string to search
1466 * return: boolean character is inside
1468 int oneof(char c, const char* s) { \
1476 * Uses popen to get the output of a shell command
1477 * and puts it in a given buffer. If the buffer is NULL,
1478 * the memory is automatically allocated, and must
1479 * be freed after use.
1484 * return: string buffer
1486 char* shellsub(char* s, const char* c) { \
1487 FILE* f = popen(c, "r"); \
1500 while (getline(&r, &n, f)>0) { \
1501 ls = s ? strlen(s) : 0; \
1504 m = realloc(s, sizeof(char)*(l+1)); \
1524 * Executes a given command and returns
1529 * return: command exit status
1531 int cmdret(const char* s) { \
1532 int r = system(s); \
1533 return WIFEXITED(r) ? WEXITSTATUS(r) : r; \
1536 * Removes the trailing newline from a string.
1540 * return: string buffer
1542 char* trim(char* s) { \
1546 size_t l = strlen(s); \
1547 if (s[l-1] == '\n') \
1552 * Allocates enough memory to copy
1553 * a given string, and then copies it.
1554 * The string returned must be freed after use.
1558 * return: allocated string buffer
1560 char* salloc(char* s) { \
1565 size_t l = strlen(s); \
1566 r = calloc(l+1, sizeof(char)); \
1573 * Inserts a string into another one at specific
1574 * position and returns the result. If initial string is NULL,
1575 * memory is automatically allocated, and must
1576 * be freed after use, otherwise memory is reallocated
1577 * to insert the string.
1578 * Never pass a buffer to this function!
1583 * return: (re)allocated string buffer
1585 char* sins(char* s, const char* a, size_t p) { \
1587 return s ? s : NULL; \
1590 size_t la = strlen(a); \
1597 m = realloc(s, sizeof(char)*(ls+la+1)); \
1606 for (; j>=p; --i, --j) { \
1619 * Joins two strings into one, and returns
1620 * the result. If initial string is NULL,
1621 * memory is automatically allocated, and must
1622 * be freed after use, otherwise memory is reallocated
1623 * to add a new string.
1624 * Never pass a buffer to this function!
1629 * return: (re)allocated string buffer
1631 char* sadd(char* s, const char* a) { \
1633 return s ? s : NULL; \
1636 size_t la = strlen(a); \
1641 m = realloc(s, sizeof(char)*(ls+la+1)); \
1652 * Replaces a string found in another string with another
1653 * string (a given number of times). If output buffer is
1654 * given, then simply uses it, otherwise memory is automatically
1655 * allocated, and must be freed after use.
1656 * If number of replacement is '0', the replaces all occurrences.
1659 * s: string to search into
1660 * r: substring to find and replace
1661 * t: substring replacement
1662 * n: number of replacements
1664 * return: string buffer
1666 char* srep(char* b, const char* s, const char* r, const char* t, size_t n) { \
1667 const char* d = s; \
1674 size_t ls = strlen(s); \
1675 size_t lr = strlen(r); \
1676 size_t lt = strlen(t); \
1679 for (size_t o=1; (f = strstr(d, r)); ++o) { \
1680 lret += (f-d) + lt; \
1682 m = realloc(b, sizeof(char)*(lret+1)); \
1692 strncat(b, d, f-d); \
1700 b = malloc(sizeof(char)*(ls+1)); \
1703 strncpy(b, s, ls+1); \
1708 m = realloc(b, sizeof(char)*(lret+(lt+ls-(p-s))+1)); \
1715 ofs = (p - s) + lr; \
1716 strncat(b, s+ofs, ls-ofs); \
1720 * Checks if a character is not "strange" :D
1722 * c: character to check
1724 * return: boolean is not strange
1726 int valid(char c) { \
1727 return (c >= 0x09 && c <=0x0d) || (c >= 0x20 && c <= 0x7e); \
1730 * Checks if file descriptor refers to a regular file.
1731 * Doesn't check for syscall errors.
1733 * fd: file descriptor
1735 * return: boolean is a file
1737 int isfile(int fd) { \
1739 if (fstat(fd, &sb) == -1) \
1742 return S_IFREG == (sb.st_mode & S_IFMT); \
1745 * Checks if file descriptor refers to a socket.
1746 * Doesn't check for syscall errors.
1748 * fd: file descriptor
1750 * return: boolean is a socket
1752 int issock(int fd) { \
1754 if (fstat(fd, &sb) == -1) \
1757 return S_IFSOCK == (sb.st_mode & S_IFMT); \
1760 * Checks if file descriptor refers to a pipe.
1761 * Doesn't check for syscall errors.
1763 * fd: file descriptor
1765 * return: boolean is a pipe
1767 int ispipe(int fd) { \
1769 if (fstat(fd, &sb) == -1) \
1772 return S_IFIFO == (sb.st_mode & S_IFMT); \