Tou
Tou header library
Loading...
Searching...
No Matches
tou.h
Go to the documentation of this file.
1
32#ifndef __TOU_H_
33#define __TOU_H_
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <ctype.h>
39#include <stdbool.h>
40
41/* == Debug options and helpers == */
48#define TOU_GET_VERSION() (20240819L)
49
53#ifndef TOU_DBG
54#define TOU_DBG 0
55#endif
56
62#ifndef TOU_DEBUG
63#define TOU_DEBUG(...) if (TOU_DBG) { __VA_ARGS__; } else (void)0
64#endif
65
69#ifndef TOU_DEBUG_PREFIX
70#define TOU_DEBUG_PREFIX "[:] "
71#endif
72
76#ifndef TOU_PRINTD
77#define TOU_PRINTD(format, ...) if (TOU_DBG) { fprintf(stdout, TOU_DEBUG_PREFIX format, ##__VA_ARGS__); } else (void)0
78#endif
79
83#ifdef _WIN32
84#include <io.h>
85#define _TOU_DEVNULL_FILE "NUL:"
86#else
87#include <unistd.h>
88#include <fcntl.h> // O_WRONLY
89#define _TOU_DEVNULL_FILE "/dev/null"
90#endif
94/* == Various definitions == */
101#ifndef nullptr
102#define nullptr ((void*)0)
103#endif
104
106#ifndef TOU_DEFAULT_BLOCKSIZE
107#define TOU_DEFAULT_BLOCKSIZE 4096
108#endif
109
111#define TOU_JSON_DATA_VER "1.0"
112
114#define TOU_XML_DATA_VER "1.0"
115
119#ifndef TOU_STR
120#define TOU_STR(s) #s
121#endif
128#ifndef TOU_MSTR
129#define TOU_MSTR(s) TOU_STR(s)
130#endif
131
135#ifndef TOU_IS_BLANK
136#define TOU_IS_BLANK(c) ((c)==' ' || (c)=='\n' || (c)=='\r' || (c)=='\t')
137#endif
138
142#ifndef TOU_ARRSIZE
143#define TOU_ARRSIZE(x) (sizeof(x) / sizeof(x[0])) // /sizeof(__typeof__(x[0])))
144#endif
145
154#ifndef TOU_RANDINT
155#define TOU_RANDINT(mx, mn) ((int)(((float)rand()/RAND_MAX) * ((mx)-(mn)) + (mn)))
156#endif
157
162 TOU_BREAK = 0,
163 TOU_CONTINUE = 1,
164};
165
166
167/* Func ptrs */
168
172typedef void* (*tou_func)(void*);
173
177typedef void* (*tou_func2)(void*, void*);
178
182typedef void* (*tou_func3)(void*, void*, void*);
183
184
188/* == Linked list definitions == */
197typedef struct tou_llist
198{
199 struct tou_llist* prev;
200 struct tou_llist* next;
201 void* dat1;
202#ifndef TOU_LLIST_SINGLE_ELEM
203 void* dat2;
204#endif
205 char destroy_dat1/* : 1*/;
206#ifndef TOU_LLIST_SINGLE_ELEM
207 char destroy_dat2/* : 1*/;
208#endif
210
212typedef struct tou_llist tou_llist_elem;
213
214
218// ==============================================================
219// || FUNC DECLS ||
220// ==============================================================
221
222/* == String functions == */
228/*
229 * strlcpy() and strcat() functions were acquired from
230 * Todd Miller under the following license:
231 *
232 * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
233 *
234 * Permission to use, copy, modify, and distribute this software for any
235 * purpose with or without fee is hereby granted, provided that the above
236 * copyright notice and this permission notice appear in all copies.
237 *
238 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
239 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
240 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
241 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
242 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
243 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
244 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
245 *
246 * Also see: https://www.millert.dev/papers/strlcpy
247 */
248
267size_t tou_strlcpy(char* dst, const char* src, size_t size);
268
288size_t tou_strlcat(char* dst, const char* src, size_t size);
289
296size_t tou_strlen(const char* str);
297
304char* tou_strdup(const char* src);
305
314char* tou_strndup(const char* src, size_t size);
315
326char* tou_strchr(const char* src, int ch);
327
338char* tou_strrchr(const char* src, int ch);
339
347char* tou_trim_string(char** str);
348
355char* tou_trim_front(char** str);
356
364char* tou_trim_back(char** str);
365
374void tou_trim_string_pure(char* str, char** start, char** end);
375
383char* tou_trim_front_pure(char* str);
384
392char* tou_trim_back_pure(char* str);
393
400char* tou_slower(char* str);
401
408char* tou_supper(char* str);
409
427char* tou_replace_ch(char* ss, char oldch, char newch);
428
436char* tou_sfind(const char* str, const char* kwd);
437
447char* tou_sfind_n(const char* str, const char* kwd, size_t maxlen);
448
460char* tou_sfind_multiple(const char* str, const char** kwds, int n_kwds, int* found_idx);
461
474char* tou_sfind_multiple_n(const char* str, const char** kwds, int n_kwds, int* found_idx, size_t maxlen);
475
491void tou_sfind_iter_multiple(const char* src, const char* kwds[], int n_kwds, tou_func3 cb, void* userdata);
492
510void tou_sfind_iter_multiple_n(const char* src, const char* kwds[], int n_kwds, tou_func3 cb, void* userdata, size_t maxlen);
511
519tou_llist_t* tou_split(char* str, const char* delim);
520
531char* tou_sappend(char* dst, char* src);
532
543char* tou_sprepend(char* dst, char* src);
544
554char* tou_sreplace(char* str, char* repl_str, char* with_str);
555
578char* tou_sreplace_n(char* str, char* repl_str, char* with_str, size_t* len_ptr);
579
588#ifndef tou_sisempty
589#define tou_sisempty(elem, dat) \
590 ((elem) == NULL /* wanted to do without this one but i can already see segfaults happening without it */ || \
591 (elem)->dat == NULL || \
592 tou_strlen(tou_trim_front_pure((elem)->dat)) == 0)
593#endif
594
595
599/* == File operations == */
623size_t tou_read_fp_in_blocks(FILE* fp, size_t blocksize, tou_func3 cb, void* userdata);
624
636typedef struct {
637 char* buffer;
638 size_t size;
640
655void* tou_block_store_cb(void* blockdata, void* len, void* userdata);
656
669char* tou_read_file(const char* filename, size_t* read_len);
670
681char* tou_read_fp(FILE* fp, size_t* read_len);
682
683
684/* == System/IO control == */
699
706void tou_enable_stdout(int saved_fd);
707
711#ifndef TOU_SILENCE
712#define TOU_SILENCE( ... ) \
713 _tou_g_saved_stdout = tou_disable_stdout(); \
714 __VA_ARGS__ ; \
715 tou_enable_stdout(_tou_g_saved_stdout);
716#endif
717
723
724
731/* == Linked list == */
758#ifndef TOU_LLIST_DAT_ADDR
759#define TOU_LLIST_DAT_ADDR(list, param) ((tou_llist_t**)(&((*(list))->param)))
760#endif
772#ifndef tou_llist_new
773#define tou_llist_new(...) ((TOU_DBG ? fprintf(stdout,TOU_DEBUG_PREFIX"Creating new llist :: NULL\n") : (void)0) , NULL)
774#endif
775
776/* */
777// typedef tou_llist_t* tou_llist_elem;
778/* */
779// #define TOU_LLIST_UNPACK(elem) (*(elem))->dat1,(*(elem))->dat2
780
795(
796 tou_llist_t** elem,
797 void* dat1,
798#ifndef TOU_LLIST_SINGLE_ELEM
799 void* dat2,
800#endif
801 char dat1_is_dynalloc
802#ifndef TOU_LLIST_SINGLE_ELEM
803 , char dat2_is_dynalloc
804#endif
805);
806
819tou_llist_t* tou_llist_appendone(tou_llist_t** elem, void* dat1, char dat1_is_dynalloc);
820
835(
836 tou_llist_t** elem,
837 void* dat1,
838#ifndef TOU_LLIST_SINGLE_ELEM
839 void* dat2,
840#endif
841 char dat1_is_dynalloc
842#ifndef TOU_LLIST_SINGLE_ELEM
843 , char dat2_is_dynalloc
844#endif
845);
846
859tou_llist_t* tou_llist_prependone(tou_llist_t** elem, void* dat1, char dat1_is_dynalloc);
860
868
885
894
904
913
922
932
942
952
962
973
984
993
1002
1013
1025(
1026 tou_llist_t* list,
1027 void* dat1
1028#ifndef TOU_LLIST_SINGLE_ELEM
1029 , void* dat2
1030#endif
1031);
1032
1042
1053
1068
1076
1085void** tou_llist_gather_dat1(tou_llist_t* list, size_t* len);
1086
1095#ifndef TOU_LLIST_SINGLE_ELEM
1096void** tou_llist_gather_dat2(tou_llist_t* list, size_t* len);
1097#endif
1098
1100#define tou_llist_gather tou_llist_gather_dat1
1101
1117#ifndef tou_llist_print
1118#ifndef TOU_LLIST_SINGLE_ELEM
1119
1120 #define tou_llist_print(llist, dat1_spec, dat2_spec, ...) \
1121 { \
1122 tou_llist_t* copy = tou_llist_get_newest(llist); \
1123 printf("List contents: (%d)\n", tou_llist_len(copy)); \
1124 while (copy) { \
1125 printf(" |\n "dat1_spec" :: "dat2_spec"\n", copy->dat1, copy->dat2); \
1126 copy = tou_llist_get_older(copy); \
1127 } \
1128 } (void)0
1129
1130#else
1131
1132 #define tou_llist_print(llist, dat1_spec, ...) \
1133 { \
1134 tou_llist_t* copy = tou_llist_get_newest(llist); \
1135 printf("List contents: (%d)\n", tou_llist_len(copy)); \
1136 while (copy) { \
1137 printf(" |\n "dat1_spec"\n", copy->dat1); \
1138 copy = tou_llist_get_older(copy); \
1139 } \
1140 } (void)0
1141
1142#endif
1143#endif
1144
1160#ifndef tou_llist_print_tail
1161#ifndef TOU_LLIST_SINGLE_ELEM
1162
1163 #define tou_llist_print_tail(llist, dat1_spec, dat2_spec, ...) \
1164 { \
1165 tou_llist_t* copy = tou_llist_get_oldest(llist); \
1166 printf("List contents: (%d)\n", tou_llist_len(copy)); \
1167 while (copy) { \
1168 printf(" |\n "dat1_spec" :: "dat2_spec"\n", copy->dat1, copy->dat2); \
1169 copy = tou_llist_get_newer(copy); \
1170 } \
1171 } (void)0
1172
1173#else
1174
1175 #define tou_llist_print_tail(llist, dat1_spec, ...) \
1176 { \
1177 tou_llist_t* copy = tou_llist_get_oldest(llist); \
1178 printf("List contents: (%d)\n", tou_llist_len(copy)); \
1179 while (copy) { \
1180 printf(" |\n "dat1_spec"\n", copy->dat1); \
1181 copy = tou_llist_get_newer(copy); \
1182 } \
1183 } (void)0
1184
1185#endif
1186#endif
1187
1188
1192/* == Stack == */
1200
1207
1214
1222
1229void tou_stack_push(tou_llist_t** stack, void* elem);
1230
1238
1239
1243/* == Queue == */
1251
1258
1265
1273
1280void tou_queue_push(tou_llist_t** queue, void* elem);
1281
1289
1290
1294/* == INI parser == */
1330#ifdef TOU_LLIST_SINGLE_ELEM
1331#warning TOU_LLIST_SINGLE_ELEM DEFINED, TOU_INI DISABLED.
1332#else
1333
1334
1363
1374
1385int tou_ini_parse_line(tou_llist_t** inicontents, char* line);
1386
1393void tou_ini_destroy(tou_llist_t* inicontents);
1394
1401void tou_ini_print(tou_llist_t* inicontents);
1402
1415tou_llist_t* tou_ini_get_section(tou_llist_t* inicontents, const char* section_name);
1416
1425tou_llist_t* tou_ini_get_property(tou_llist_t* inicontents, const char* section_name, const char* key);
1426
1437void* tou_ini_get(tou_llist_t* inicontents, const char* section_name, const char* key);
1438
1449void* tou_ini_set(tou_llist_t** inicontents, const char* section_name, const char* key, char* new_value);
1450
1458tou_llist_t* tou_ini_section(tou_llist_t* inicontents, const char* section_name);
1459
1467void* tou_ini_property(tou_llist_t* section, const char* property_name);
1468
1483int tou_ini_save_fp(tou_llist_t* inicontents, FILE* fp);
1484
1499int tou_ini_save_fp_json(tou_llist_t* inicontents, FILE* fp);
1500
1515int tou_ini_save_fp_xml(tou_llist_t* inicontents, FILE* fp);
1516
1517#endif
1518
1519
1523/* == Parsers == */
1529#ifdef TOU_LLIST_SINGLE_ELEM
1530#warning TOU_LLIST_SINGLE_ELEM DEFINED, PARSERS & CONVERTERS DISABLED.
1531#else
1532
1549tou_llist_t* tou_paramparse(char* str, const char* param_sep, const char* keyval_sep);
1550
1567tou_llist_t* tou_paramparse_n(char* str, const char* param_sep, const char* keyval_sep, size_t maxlen);
1568
1575
1576#endif
1577
1578
1582#endif // __TOU_H_
1583
1584
1585// ==============================================================
1586// || IMPLEMENTATION ||
1587// ==============================================================
1588
1589
1590#ifdef TOU_IMPLEMENTATION
1591#if defined(TOU_IMPLEMENTATION_DONE)
1592#pragma error "TOU_IMPLEMENTATION already defined somewhere!"
1593#else
1594
1595#define TOU_IMPLEMENTATION_DONE
1596
1597
1601
1602
1603/* */
1604size_t tou_strlcpy(char* dst, const char* src, size_t size)
1605{
1606 size_t src_len;
1607
1608 src_len = strlen (src);
1609 if (size > 0)
1610 {
1611 size_t dst_len = size - 1;
1612 if (src_len < dst_len)
1613 dst_len = src_len;
1614 memcpy (dst, src, dst_len);
1615 dst[dst_len] = '\0';
1616 }
1617 return src_len;
1618}
1619
1620
1621/* */
1622size_t tou_strlcat(char* dst, const char* src, size_t size)
1623{
1624 size_t src_len, dst_len;
1625
1626 src_len = strlen (src);
1627 dst_len = strlen (dst);
1628 if (size > 0 && dst_len < size)
1629 {
1630 size_t copy_cnt = size - dst_len - 1;
1631 if (src_len < copy_cnt)
1632 copy_cnt = src_len;
1633 memcpy (dst + dst_len, src, copy_cnt);
1634 dst[dst_len + copy_cnt] = '\0';
1635 }
1636 return src_len + dst_len;
1637}
1638
1639
1640/* */
1641size_t tou_strlen(const char* str)
1642{
1643 if (!str) return 0;
1644 return strlen(str);
1645}
1646
1647
1648/* */
1649char* tou_strdup(const char* src)
1650{
1651 size_t src_len = strlen(src);
1652 char* copy;
1653 if ((copy = malloc(src_len + 1)) == NULL)
1654 return NULL;
1655 // tou_strlcpy(copy, src, src_len + 1);
1656 memcpy(copy, src, src_len + 1);
1657 return copy;
1658}
1659
1660
1661/* */
1662char* tou_strndup(const char* src, size_t size)
1663{
1664 size_t src_len = strlen(src);
1665 char* copy = NULL;
1666
1667 if (size > 0) {
1668 size_t copy_len = size;
1669 if (src_len < copy_len)
1670 copy_len = src_len;
1671 if ((copy = malloc(copy_len + 1)) == NULL)
1672 return NULL;
1673 // tou_strlcpy(copy, src, copy_len + 1);
1674 memcpy(copy, src, copy_len + 1);
1675 }
1676 return copy;
1677}
1678
1679
1680/* */
1681char* tou_strchr(const char* src, int ch)
1682{
1683 while (*src) {
1684 if (*src == (char)ch)
1685 return (char*)src;
1686 src++;
1687 }
1688
1689 if (ch == '\0') // '\0' can also be searched for
1690 return (char*)src;
1691 else
1692 return NULL;
1693}
1694
1695
1696/* */
1697char* tou_strrchr(const char* src, int ch)
1698{
1699 char* pos = NULL;
1700
1701 while (*src) {
1702 if (*src == (char)ch)
1703 pos = (char*)src;
1704 src++;
1705 }
1706
1707 if (ch == '\0') // '\0' can also be searched for
1708 return (char*)src;
1709 else
1710 return pos;
1711}
1712
1713
1714/* */
1715char* tou_trim_string(char** str)
1716{
1717 tou_trim_back(str);
1718 return tou_trim_front(str);
1719}
1720
1721
1722/* */
1723char* tou_trim_front(char** str)
1724{
1725 if (str == NULL || *str == NULL)
1726 return NULL;
1727
1728 char* ptr = *str;
1729 while (*ptr != '\0' && TOU_IS_BLANK(*ptr))
1730 ptr++;
1731 *str = ptr;
1732 return ptr;
1733}
1734
1735
1736/* */
1737char* tou_trim_back(char** str)
1738{
1739 if (str == NULL || *str == NULL)
1740 return NULL;
1741
1742 char* ptr = (*str + strlen(*str) - 1);
1743 while (ptr >= *str && TOU_IS_BLANK(*ptr)) {
1744 *ptr = '\0';
1745 ptr--;
1746 }
1747 ptr++;
1748 return ptr;
1749}
1750
1751
1752/* */
1753void tou_trim_string_pure(char* str, char** start, char** end)
1754{
1755 char* back = tou_trim_back_pure(str);
1756 char* front = tou_trim_front_pure(str);
1757
1758 *end = back;
1759 *start = front;
1760}
1761
1762
1763/* */
1764char* tou_trim_front_pure(char* str)
1765{
1766 if (str == NULL)
1767 return NULL;
1768
1769 while (*str != '\0' && TOU_IS_BLANK(*str))
1770 str++;
1771 return str;
1772}
1773
1774
1775/* */
1776char* tou_trim_back_pure(char* str)
1777{
1778 if (str == NULL)
1779 return NULL;
1780
1781 char* ptr = (str + strlen(str) - 1);
1782 while (ptr >= str && TOU_IS_BLANK(*ptr)) {
1783 ptr--;
1784 }
1785 ptr++; // Inc to point at the first trimmed/NUL byte
1786 return ptr;
1787}
1788
1789
1790/* */
1791char* tou_slower(char* str)
1792{
1793 if (!str)
1794 return NULL;
1795
1796 char* ptr = str;
1797 while (*ptr++ = tolower(*ptr)) ;
1798 return str;
1799}
1800
1801/* */
1802char* tou_supper(char* str)
1803{
1804 if (!str)
1805 return NULL;
1806
1807 char* ptr = str;
1808 while (*ptr++ = toupper(*ptr)) ;
1809 return str;
1810}
1811
1812
1813/* */
1814char* tou_replace_ch(char* ss, char oldch, char newch)
1815{
1816 TOU_PRINTD("[replace_ch] replacing ('%c'->'%c') \"%s\" => ", oldch, newch, ss);
1817 char* ptr = tou_strchr(ss, oldch);
1818 while (ptr) {
1819 *ptr = newch;
1820 ptr = tou_strchr(ptr + 1, oldch);
1821 }
1822 TOU_PRINTD("\"%s\"\n", ss);
1823 return ss;
1824}
1825
1826
1827/* */
1828char* tou_sfind(const char* src, const char* kwd)
1829{
1830 return tou_sfind_n(src, kwd, strlen(src));
1831}
1832
1833
1834/* */
1835char* tou_sfind_n(const char* src, const char* kwd, size_t maxlen)
1836{
1837 if (src == NULL)
1838 return NULL;
1839
1840 const char* ret_ptr = NULL;
1841 const int kwd_len = strlen(kwd);
1842 const char* kwd_ptr = kwd;
1843
1844 if (kwd_len > maxlen)
1845 return NULL;
1846
1847 while (maxlen + 1 > 0 ){//&& *src) {
1848 if (*kwd_ptr == '\0') {
1849 // only time it should be is when kwd is found
1850 ret_ptr = src - kwd_len;
1851 break;
1852 }
1853
1854 if (*src == '\0')
1855 break;
1856
1857 if (*kwd_ptr == *src) {
1858 kwd_ptr++;
1859 } else {
1860 kwd_ptr = kwd;
1861 }
1862
1863 src++;
1864 maxlen--;
1865 }
1866
1867 return (char*)ret_ptr;
1868}
1869
1870
1871/* */
1872char* tou_sfind_multiple(const char* str, const char** kwds, int n_kwds, int* found_idx)
1873{
1874 return tou_sfind_multiple_n(str, kwds, n_kwds, found_idx, ((size_t)-1) - 1);
1875}
1876
1877
1878/* */
1879char* tou_sfind_multiple_n(const char* str, const char** kwds, int n_kwds, int* found_idx, size_t maxlen)
1880{
1881 if (str == NULL || kwds == NULL || n_kwds < 1)
1882 return NULL;
1883
1884 if (maxlen < 1) {
1885 if (found_idx) *found_idx = -1;
1886 return NULL;
1887 }
1888
1889 int kwd_len[n_kwds];
1890 const char* kwd_ptr[n_kwds];
1891 const char* ret_ptr = NULL;
1892
1893 // Kwds which are NULL will not stop function but will be
1894 // ignored later in search loop and their kwd_len will be set to 0
1895 for (int i = 0; i < n_kwds; i++) {
1896 kwd_ptr[i] = kwds[i];
1897 kwd_len[i] = tou_strlen(kwds[i]);
1898 }
1899
1900 while (maxlen + 1 > 0 && *str) {
1901 for (int i = 0; i < n_kwds; i++) {
1902
1903 if (kwd_ptr[i] == NULL) // Skip NULL keywords
1904 continue;
1905 if (*(kwd_ptr[i]) == '\0') {
1906 // only time it should be is when that kwd is found
1907 ret_ptr = str - kwd_len[i];
1908 if (found_idx)
1909 *found_idx = i;
1910 goto jmp_sfind_multiple_n_break; // break;
1911 }
1912
1913 if (*(kwd_ptr[i]) == *str) {
1914 kwd_ptr[i]++; // this character matched next char in this kwd
1915 } else {
1916 kwd_ptr[i] = kwds[i]; // reset this kwd tracker
1917 }
1918
1919 }
1920
1921 str++;
1922 maxlen--;
1923 }
1924
1925jmp_sfind_multiple_n_break:
1926 // Do the check one more time in case matching string is found
1927 // at the end of `str` (*str will break before the check has a chance)
1928 for (int i = 0; i < n_kwds; i++) {
1929 if (*(kwd_ptr[i]) == '\0') {
1930 ret_ptr = str - kwd_len[i];
1931 if (found_idx)
1932 *found_idx = i;
1933 break;
1934 }
1935 }
1936 return (char*)ret_ptr;
1937}
1938
1939
1940/* */
1941void tou_sfind_iter_multiple(const char* src, const char* kwds[], int n_kwds, tou_func3 cb, void* userdata)
1942{
1943 tou_sfind_iter_multiple_n(src, kwds, n_kwds, cb, userdata, ((size_t)-1) - 1);
1944}
1945
1946
1947/* */
1948void tou_sfind_iter_multiple_n(const char* src, const char* kwds[], int n_kwds, tou_func3 cb, void* userdata, size_t maxlen)
1949{
1950 char* found = NULL;
1951 int found_idx = -1;
1952 const char* text_ptr = src;
1953 size_t remaining = maxlen - 0;
1954
1955 while ((found = tou_sfind_multiple_n(text_ptr, kwds, n_kwds, &found_idx, remaining)) != NULL) {
1956 // TOU_PRINTD("[iter_find_multiple_n] calling user func with (\"%s\", \"%s\", %p)\n", text_ptr, kwds[found_idx], userdata);
1957
1958 // Call user func
1959 if (cb((void*)found, (void*)kwds[found_idx], userdata) == TOU_BREAK) {
1960 TOU_PRINTD("[iter_find_multiple_n] breaking early\n");
1961 return;
1962 }
1963 // Iter continue
1964 text_ptr = found + tou_strlen(kwds[found_idx]);
1965 remaining -= (text_ptr - src);
1966 }
1967}
1968
1969
1970/* */
1971tou_llist_t* tou_split(char* str, const char* delim)
1972{
1973 if (!str || !delim)
1974 return NULL;
1975
1976 TOU_PRINTD("[tou_split] STR_LEN :: %zu\n", tou_strlen(str));
1977
1978 size_t delim_len = tou_strlen(delim);
1979 tou_llist_t* list = NULL;
1980 char* pos_start = str;
1981 char* pos_delim = tou_sfind(str, delim);
1982
1983 while (pos_delim) {
1984 // TODO: swap with tou_str[n]dup() ?
1985 char* buf = malloc(pos_delim-pos_start + 1);
1986 tou_strlcpy(buf, pos_start, pos_delim-pos_start + 1);
1987 TOU_PRINTD("[tou_split] BUF: %s\n", buf);
1988 tou_llist_appendone(&list, buf, 1);
1989
1990 // Find next occurence
1991 pos_start = pos_delim + delim_len;
1992 pos_delim = tou_sfind(pos_start, delim);
1993 }
1994
1995 size_t len = tou_strlen(pos_start);
1996 TOU_PRINTD("[tou_split] FINAL LEN :: %zu\n", len);
1997 if (len > 0) {
1998 // Append last part till the end
1999 // TODO: swap with tou_strndup() ?
2000 char* buf = malloc(len + 1);
2001 tou_strlcpy(buf, pos_start, len + 1);
2002 TOU_PRINTD("[tou_split] BUF: %s\n", buf);
2003 tou_llist_appendone(&list, buf, 1);
2004 }
2005
2006 return list;//tou_llist_get_tail(list);
2007}
2008
2009
2010/* */
2011char* tou_sappend(char* dst, char* src)
2012{
2013 size_t dst_len = tou_strlen(dst);
2014 size_t src_len = tou_strlen(src);
2015
2016 size_t new_size = dst_len + src_len + 1;
2017 dst = realloc(dst, new_size);
2018 tou_strlcpy(dst + dst_len, src, new_size);
2019
2020 return dst;
2021}
2022
2023
2024/* */
2025char* tou_sprepend(char* dst, char* src)
2026{
2027 size_t dst_len = tou_strlen(dst);
2028 size_t src_len = tou_strlen(src);
2029
2030 char* new_mem = malloc(dst_len + src_len + 1);
2031
2032 memcpy(new_mem, src, src_len);
2033 memcpy(new_mem + src_len, dst, dst_len + 1); // copy \0 too
2034
2035 return new_mem;
2036}
2037
2038
2039/* */
2040char* tou_sreplace(char* str, char* repl_str, char* with_str)
2041{
2042 return tou_sreplace_n(str, repl_str, with_str, NULL);
2043}
2044
2045
2046/* */
2047char* tou_sreplace_n(char* str, char* repl_str, char* with_str, size_t* len_ptr)
2048{
2049 if (!str || !repl_str) {
2050 TOU_PRINTD("[tou_sreplace_n] string or replace string NULL\n");
2051 return NULL;
2052 }
2053
2054 size_t true_len = tou_strlen(str);
2055 size_t repl_len = tou_strlen(repl_str);
2056 size_t with_len = tou_strlen(with_str);
2057
2058 size_t len = 0;
2059 if (len_ptr != NULL) {
2060 len = *len_ptr;
2061 }
2062 if (len == 0 || len > true_len)
2063 len = true_len;
2064
2065 char tmp_replaced_ch = '\0';
2066 if (len < true_len) {
2067 tmp_replaced_ch = str[len];
2068 str[len] = '\0';
2069 }
2070
2071 char* search_ptr = str;
2072 char* dst = NULL;
2073 char* tmp_dst; // used when realloc'ing dst & when iterating last part
2074 size_t current_size = 0;
2075 const int with_alloc_mult = 4; // prealloc for more than one and shrink in the end?
2076
2077 size_t copydiff = 0;
2078 char* next_with = NULL;
2079
2080 while ((next_with = tou_sfind(search_ptr, repl_str)) != NULL)
2081 {
2082 copydiff = next_with - search_ptr;
2083
2084 if ((tmp_dst = realloc(dst, current_size + copydiff + with_len*with_alloc_mult + 1)) == NULL) {
2085 TOU_PRINTD("[tou_sreplace_n] realloc failed (%zu bytes)\n", current_size + copydiff + with_len*with_alloc_mult + 1);
2086 if (dst != NULL) // Would be NULL if this was the first replace
2087 *(dst + current_size) = '\0'; // needed?
2088 break;
2089 }
2090 dst = tmp_dst;
2091
2092 memcpy(dst + current_size, search_ptr, copydiff);
2093 memcpy(dst + current_size + copydiff, with_str, with_len);
2094 // *(dst + current_size + copydiff + with_len) = '\0';
2095
2096 current_size += copydiff + with_len;
2097 search_ptr += copydiff + repl_len;
2098 }
2099
2100 // Calc size of last one + remainder of source
2101 size_t rest = tou_strlen(search_ptr); // last part + non-searched remainder since replaced char was returned to place
2102 if ((tmp_dst = realloc(dst, current_size + rest + 1)) == NULL) {
2103 TOU_PRINTD("[tou_sreplace_n] last part realloc failed (%zu)\n", current_size + rest + 1);
2104 return dst;
2105 }
2106 dst = tmp_dst;
2107
2108 // Copy the remaining unmodified part from search_ptr to (tmp_)dst
2109 tmp_dst = dst + current_size;
2110 while (*search_ptr)
2111 *(tmp_dst++) = *(search_ptr++);
2112 *tmp_dst = '\0';
2113 current_size += rest;
2114
2115 // Restore replaced char if it was needed
2116 if (tmp_replaced_ch != '\0')
2117 str[len] = tmp_replaced_ch;
2118
2119 // Resize to fit if larger (?)
2120 tmp_dst = realloc(dst, current_size + 1);
2121 if (tmp_dst) {
2122 // realloc succeded
2123 if (len_ptr) {
2124 *len_ptr = current_size;
2125 }
2126 return tmp_dst;
2127 }
2128
2129 // realloc failed
2130 if (len_ptr) {
2131 *len_ptr = tou_strlen(dst);
2132 }
2133 return dst;
2134}
2135
2136
2140
2141
2142/* */
2143size_t tou_read_fp_in_blocks(FILE* fp, size_t blocksize, tou_func3 cb, void* userdata)
2144{
2145 // Clamp blocksize to TOU_DEFAULT_BLOCKSIZE if not in following range:
2146 if (blocksize < 1 || blocksize > 0xFFFFFF) {
2147 blocksize = TOU_DEFAULT_BLOCKSIZE;
2148 TOU_PRINTD("[tou_read_fp_in_blocks] clamping blocksize to "TOU_MSTR(TOU_DEFAULT_BLOCKSIZE)"\n");
2149 }
2150
2151 size_t curr_bufsize = 0;
2152 char blockbuf[blocksize];
2153 size_t bytes_read = 0;
2154
2155 while (1) {
2156 // Clear buf
2157 memset(blockbuf, 0, blocksize);
2158
2159 // Load data into buf
2160 size_t cnt = fread(blockbuf, 1, blocksize, fp);
2161 if (cnt <= 0)
2162 break;
2163
2164 // Store real read length
2165 bytes_read += cnt;
2166
2167 // Do the useful things
2168 if (cb) {
2169 if (cb(blockbuf, (void*) cnt, userdata) == TOU_BREAK) {
2170 // User stopped iteration
2171 TOU_PRINTD("[tou_read_fp_in_blocks] iteration aborted.\n");
2172 break;
2173 }
2174 }
2175 }
2176
2177 return bytes_read;
2178}
2179
2180
2181/* */
2182void* tou_block_store_cb(void* blockdata, void* len, void* userdata)
2183{
2184 char* block = (char*) blockdata;
2185 size_t size = (size_t) len;
2187
2188 TOU_PRINTD("\n[tou_block_store_cb] Block\n=====\n%.*s (...first %d bytes)\n===== (%zu)\n", (size>64)?64:size, block, (size>64)?64:size, size);
2189
2190 if (size > 0) {
2191 char* new_buffer = realloc(data->buffer, data->size + size + 1); // accomodate \0
2192 if (!new_buffer){
2193 TOU_PRINTD("[tou_block_store_cb] cannot realloc memory\n");
2194 // return (void*) TOU_BREAK;
2195 } else {
2196 memcpy(new_buffer + data->size, block, size);
2197 *(new_buffer + data->size + size) = '\0';
2198 data->buffer = new_buffer;
2199 data->size += size;
2200 TOU_PRINTD("[tou_block_store_cb] appended block {size=%zu}\n", data->size);
2201 }
2202 }
2203
2204 return (void*)TOU_CONTINUE;
2205}
2206
2207/* */
2208char* tou_read_file(const char* filename, size_t* read_len)
2209{
2210 FILE* fp;
2211 if (!filename || strlen(filename) == 0 || strcmp("stdin", filename) == 0) { // stdin
2212 fp = stdin;
2213 } else if ((fp = fopen(filename, "rb")) == NULL) { // file
2214 TOU_PRINTD("[read_file] cannot open '%s' (as \"rb\")\n", filename);
2215 return NULL;
2216 }
2217
2218 TOU_PRINTD("[read_file] reading from: %s\n", (fp==stdin) ? "STDIN" : filename);
2219 char* read = tou_read_fp(fp, read_len);
2220
2221 if (fp != stdin) {
2222 fclose(fp);
2223 TOU_PRINTD("[read_file] closed.\n");
2224 }
2225
2226 return read;
2227}
2228
2229
2230/* */
2231char* tou_read_fp(FILE* fp, size_t* read_len)
2232{
2233 if (fp == NULL)
2234 return NULL;
2235
2236 TOU_PRINTD("[read_fp] reading from: FILE* %p\n", fp);
2237
2238 // char* read = tou_read_fp_in_blocks(fp, read_len, -1, NULL, NULL); // default block size, without function
2239 // tou_read_fp_in_blocks -> (FILE* fp, size_t* read_len, size_t blocksize, tou_func3 cb, void* userdata)
2240 tou_block_store_struct tmp = {NULL, 0};
2242
2243 TOU_PRINTD("[read_fp] finished reading.\n");
2244
2245 if (read_len)
2246 *read_len = tmp.size;
2247
2248 return tmp.buffer;
2249}
2250
2251
2252/* */
2254{
2255 TOU_PRINTD("[Disabling stdout.]\n");
2256
2257 fflush(stdout);
2258 int stdout_fd;
2259
2260#ifdef _WIN32
2261 // #pragma message "bindobs"
2262 stdout_fd = _dup(1);
2263 FILE* fp_nul = fopen(_TOU_DEVNULL_FILE, "w");
2264 _dup2(_fileno(fp_nul), 1);
2265 fclose(fp_nul);
2266
2267#elif __linux__
2268 // #pragma message "bibux"
2269 stdout_fd = dup(1);
2270 int new = open(_TOU_DEVNULL_FILE, O_WRONLY);
2271 dup2(new, 1);
2272 close(new);
2273#endif
2274
2275 return stdout_fd;
2276}
2277
2278
2279/* */
2280void tou_enable_stdout(int saved_fd)
2281{
2282 fflush(stdout);
2283
2284#ifdef _WIN32
2285 // #pragma message "bindobs"
2286 _dup2(saved_fd, 1);
2287 _flushall();
2288
2289#elif __linux__
2290 // #pragma message "bibux"
2291 dup2(saved_fd, 1);
2292 close(saved_fd);
2293#endif
2294
2295 TOU_PRINTD("[Enabled stdout.]\n");
2296}
2297
2298
2302
2303
2304/* */
2306(
2307 tou_llist_t** node_ref,
2308 void* dat1,
2309#ifndef TOU_LLIST_SINGLE_ELEM
2310 void* dat2,
2311#endif
2312 char dat1_is_dynalloc
2313#ifndef TOU_LLIST_SINGLE_ELEM
2314 , char dat2_is_dynalloc
2315#endif
2316) {
2317 if (node_ref == NULL)
2318 return NULL;
2319
2320 // Spawn new node
2321 tou_llist_t* new_node = malloc(sizeof(*new_node));
2322
2323 new_node->prev = NULL;
2324 new_node->next = NULL;
2325
2326 new_node->dat1 = dat1;
2327 new_node->destroy_dat1 = dat1_is_dynalloc;
2328#ifndef TOU_LLIST_SINGLE_ELEM
2329 new_node->dat2 = dat2;
2330 new_node->destroy_dat2 = dat2_is_dynalloc;
2331#endif
2332
2333 // Given node is empty list
2334 if (*node_ref == NULL) {
2335 *node_ref = new_node; // Update passed reference to point to the new node
2336 // printf("[::] LIST IS EMPTY, RETURNING NEW_NODE\n");
2337 return new_node;
2338 }
2339 // Given node/list already has something and this node is head
2340 tou_llist_t* prev_node = (*node_ref);
2341 if (prev_node->next == NULL) {
2342 prev_node->next = new_node; // Update passed node's .next
2343 new_node->prev = prev_node; // Update new node's .prev
2344 *node_ref = new_node; // Update passed reference to point to the new node
2345 // printf("[::] LIST GIVEN IS HEAD, RETURNING NEW_NODE\n");
2346 return new_node;
2347 }
2348
2349 // The given node is now somewhere inbetween (after head)
2350
2351 // Setup new node links
2352 tou_llist_t* previous_next = prev_node->next; // Save previously-next node
2353 new_node->prev = prev_node; // Update new node's .prev to point to the passed node
2354 new_node->next = previous_next; // Update new node's .next to
2355 // point to the previously-next node
2356
2357 // Setup previous (current) node links
2358 prev_node->next = new_node; // Update previously-next node to point to newly created node
2359 if (previous_next != NULL)
2360 previous_next->prev = new_node; // If previously-next actually exists,
2361 // make its .prev point to newly created node
2362
2363 // printf("[::] LIST IS IN THE MIDDLE, RETURNING ; %s\n", (*node_ref)->dat1);
2364 return new_node;
2365}
2366
2367
2368/* */
2369tou_llist_t* tou_llist_appendone(tou_llist_t** elem, void* dat1, char dat1_is_dynalloc)
2370{
2371#ifndef TOU_LLIST_SINGLE_ELEM
2372 return tou_llist_append(elem, dat1, NULL, dat1_is_dynalloc, 0);
2373#else
2374 return tou_llist_append(elem, dat1, dat1_is_dynalloc);
2375#endif
2376}
2377
2378
2379/* */
2381(
2382 tou_llist_t** node_ref,
2383 void* dat1,
2384#ifndef TOU_LLIST_SINGLE_ELEM
2385 void* dat2,
2386#endif
2387 char dat1_is_dynalloc,
2388#ifndef TOU_LLIST_SINGLE_ELEM
2389 char dat2_is_dynalloc
2390#endif
2391) {
2392 if (node_ref == NULL)
2393 return NULL;
2394
2395 // Spawn new node
2396 tou_llist_t* new_node = malloc(sizeof(*new_node));
2397
2398 new_node->prev = NULL;
2399 new_node->next = NULL;
2400
2401 new_node->dat1 = dat1;
2402 new_node->destroy_dat1 = dat1_is_dynalloc;
2403#ifndef TOU_LLIST_SINGLE_ELEM
2404 new_node->dat2 = dat2;
2405 new_node->destroy_dat2 = dat2_is_dynalloc;
2406#endif
2407
2408 // Given node is empty list
2409 // handle empty list same as append (head <=> tail)
2410 if (*node_ref == NULL) {
2411 *node_ref = new_node; // Update passed reference to point to the new node
2412 return new_node;
2413 }
2414
2415 // Given node/list already has something and this node is tail
2416 tou_llist_t* prev_node = (*node_ref);
2417 if (prev_node->prev == NULL) {
2418 prev_node->prev = new_node; // Update passed node's .prev
2419 new_node->next = prev_node; // Update new node's .next
2420 return new_node;
2421 }
2422
2423 // The given node is now somewhere inbetween (after tail)
2424
2425 // Setup new node links
2426 tou_llist_t* previous_prev = prev_node->prev; // Save previously-prev node
2427 new_node->next = prev_node; // Update new node's .next to point to the passed node
2428 new_node->prev = previous_prev; // Update new node's .prev to
2429 // point to the previously-prev node
2430
2431 // Setup previous (current) node links
2432 prev_node->prev = new_node; // Update previously-prev node to point to newly created node
2433 if (previous_prev != NULL)
2434 previous_prev->next = new_node; // If previously-prev actually exists,
2435 // make its .next point to newly created node
2436 return new_node;
2437}
2438
2439
2440/* */
2441tou_llist_t* tou_llist_prependone(tou_llist_t** elem, void* dat1, char dat1_is_dynalloc)
2442{
2443#ifndef TOU_LLIST_SINGLE_ELEM
2444 return tou_llist_prepend(elem, dat1, NULL, dat1_is_dynalloc, 0);
2445#else
2446 return tou_llist_prepend(elem, dat1, dat1_is_dynalloc);
2447#endif
2448}
2449
2450
2451/* */
2453{
2454 if (!list) return;
2455
2456 if (list->next == NULL) { // this is head.
2457 tou_llist_t *prev, *curr = list;
2458
2459 while (curr != NULL) {
2460 prev = curr->prev;
2461 if (curr->destroy_dat1) free(curr->dat1);
2462#ifndef TOU_LLIST_SINGLE_ELEM
2463 if (curr->destroy_dat2) free(curr->dat2);
2464#endif
2465 curr->prev = NULL;
2466 free(curr);
2467 curr = prev;
2468 }
2469
2470 } else { // this is tail (or inbetween)
2471 tou_llist_t *next, *curr = list;
2472
2473 while (curr != NULL) {
2474 next = curr->next;
2475 if (curr->destroy_dat1) free(curr->dat1);
2476#ifndef TOU_LLIST_SINGLE_ELEM
2477 if (curr->destroy_dat2) free(curr->dat2);
2478#endif
2479 curr->next = NULL;
2480 free(curr);
2481 curr = next;
2482 }
2483 }
2484}
2485
2486
2487/* */
2489{
2490 tou_llist_t *next = elem->next, *prev = elem->prev;
2491 tou_llist_pop(elem);
2493
2494 if (next == NULL) // This element was head
2495 return prev; // prev will be the new head
2496 else
2497 return next; // if assigned, next will be the new head
2498}
2499
2500
2501/* */
2503{
2504 if (!elem) return NULL;
2505
2506 if (elem->prev) {
2507 elem->prev->next = elem->next;
2508 }
2509 if (elem->next) {
2510 elem->next->prev = elem->prev;
2511 }
2512
2513 return elem;
2514}
2515
2516
2517/* */
2519{
2520 if (!elem) return;
2521
2522 if (elem->destroy_dat1) free(elem->dat1);
2523#ifndef TOU_LLIST_SINGLE_ELEM
2524 if (elem->destroy_dat2) free(elem->dat2);
2525#endif
2526
2527 free(elem);
2528}
2529
2530
2531/* */
2533{
2534 if (!list) return NULL;
2535
2536 while (list->next)
2537 list = list->next;
2538
2539 return list;
2540}
2541
2542
2543/* */
2545{
2546 if (!list) return NULL;
2547
2548 while (list->prev)
2549 list = list->prev;
2550
2551 return list;
2552}
2553
2554
2555/* */
2557{
2558 return tou_llist_get_head(list);
2559}
2560
2561
2562/* */
2564{
2565 return tou_llist_get_tail(list);
2566}
2567
2568
2569/* */
2571{
2572 if (elem == NULL) return NULL;
2573 return elem->next;
2574}
2575
2576
2577/* */
2579{
2580 if (elem == NULL) return NULL;
2581 return elem->prev;
2582}
2583
2584
2585/* */
2587{
2588 if (elem == NULL) return NULL;
2589 return *elem = tou_llist_get_newer(*elem);
2590}
2591
2592
2593/* */
2595{
2596 if (elem == NULL) return NULL;
2597 return *elem = tou_llist_get_older(*elem);
2598}
2599
2600
2601/* */
2603{
2604 return elem == NULL || elem->next == NULL;
2605}
2606
2607
2608/* */
2610{
2611 return elem == NULL || elem->prev == NULL;
2612}
2613
2614
2615/* */
2616void tou_llist_iter(tou_llist_t* list, tou_func cb)
2617{
2618 if (list == NULL || cb == NULL)
2619 return;
2620
2621 if (list->next == NULL) { // this is head.
2622 while (list) {
2623 if (cb(list) == 0)
2624 break;
2625 list = list->prev;
2626 }
2627
2628 } else { // this is tail (or inbetween)
2629 while (list) {
2630 if (cb(list) == 0)
2631 break;
2632 list = list->next;
2633 }
2634 }
2635}
2636
2637
2638/* */
2640(
2641 tou_llist_t* list,
2642 void* dat1
2643#ifndef TOU_LLIST_SINGLE_ELEM
2644 , void* dat2
2645#endif
2646) {
2647 if (list == NULL)
2648 return NULL;
2649 /* TOU_PRINTD("[find_exact] %p, %p, %p\n", list, dat1, dat2); */
2650
2651 while (list) {
2652 if (list->dat1 == dat1)
2653 return list;
2654#ifndef TOU_LLIST_SINGLE_ELEM
2655 if (list->dat2 == dat2)
2656 return list;
2657#endif
2658 list = list->prev;
2659 }
2660
2661 return NULL;
2662}
2663
2664/* */
2666{
2667#ifndef TOU_LLIST_SINGLE_ELEM
2668 if (list == NULL)
2669 return NULL;
2670
2671 while (list) {
2672 if (list->dat1 == dat1)
2673 return list;
2674 list = list->prev;
2675 }
2676
2677 return NULL;
2678#else
2679
2680 return tou_llist_find_exact(list, dat1);
2681
2682#endif
2683}
2684
2685
2686/* */
2687tou_llist_t* tou_llist_find_key(tou_llist_t* list, void* dat1)
2688{
2689 if (list == NULL)
2690 return NULL;
2691
2692 while (list) {
2693 if (strcmp(list->dat1, dat1) == 0) {
2694 return list;
2695 }
2696 list = list->prev;
2697 }
2698
2699 TOU_PRINTD("[llist_find_key] returning NULL\n");
2700 return NULL;
2701}
2702
2703
2704/* */
2705tou_llist_t* tou_llist_find_func(tou_llist_t* list, tou_func2 cb, void* userdata)
2706{
2707 if (list == NULL || cb == NULL)
2708 return NULL;
2709
2710 while (list) {
2711 if ((size_t) cb(list, userdata) == TOU_BREAK)
2712 return list;
2713 list = list->prev;
2714 }
2715
2716 return NULL;
2717}
2718
2719
2720/* */
2721size_t tou_llist_len(tou_llist_t* list)
2722{
2723 if (list == NULL)
2724 return 0;
2725
2726 size_t len = 0;
2727
2728 if (list->next == NULL) { // this is head.
2729 while (list) {
2730 len++;
2731 list = list->prev;
2732 }
2733
2734 } else { // this is tail (or inbetween)
2735 while (list) {
2736 len++;
2737 list = list->next;
2738 }
2739 }
2740
2741 return len;
2742}
2743
2744
2745/* */
2746void** tou_llist_gather_dat1(tou_llist_t* list, size_t* len)
2747{
2748 if (list == NULL) {
2749 TOU_PRINTD("[llist_gather_dat1] received null parameter\n");
2750 return NULL;
2751 }
2752
2753 if (len != NULL)
2754 *len = 0;
2755
2756 size_t _len = tou_llist_len(list);
2757 if (_len < 1) {
2758 TOU_PRINTD("[llist_gather_dat1] list has 0 length\n");
2759 return NULL;
2760 }
2761
2762 void** gathered;
2763 if ((gathered = malloc(_len * sizeof(void*))) == NULL) {
2764 TOU_PRINTD("[llist_gather_dat1] dynamic allocation failed\n");
2765 return NULL;
2766 }
2767
2768 for (size_t i = 0; i < _len; i++) {
2769 gathered[i] = list->dat1;
2770 list = list->prev;
2771 }
2772
2773 if (len != NULL)
2774 *len = _len;
2775 return gathered;
2776}
2777
2778
2779/* */
2780#ifndef TOU_LLIST_SINGLE_ELEM
2781void** tou_llist_gather_dat2(tou_llist_t* list, size_t* len)
2782{
2783 if (list == NULL) {
2784 TOU_PRINTD("[llist_gather_dat2] received null parameter\n");
2785 return NULL;
2786 }
2787
2788 if (len != NULL)
2789 *len = 0;
2790
2791 size_t _len = tou_llist_len(list);
2792 if (_len < 1) {
2793 TOU_PRINTD("[llist_gather_dat2] list has 0 length\n");
2794 return NULL;
2795 }
2796
2797 void** gathered;
2798 if ((gathered = malloc(_len * sizeof(void*))) == NULL) {
2799 TOU_PRINTD("[llist_gather_dat2] dynamic allocation failed\n");
2800 return NULL;
2801 }
2802
2803 for (size_t i = 0; i < _len; i++) {
2804 gathered[i] = list->dat2;
2805 list = list->prev;
2806 }
2807
2808 if (len != NULL)
2809 *len = _len;
2810 return gathered;
2811}
2812#endif
2813
2814
2818
2819
2820/* */
2822{
2823 return tou_llist_new();
2824}
2825
2826
2827/* */
2828void tou_stack_destroy(tou_llist_t* stack)
2829{
2830 return tou_llist_destroy(stack);
2831}
2832
2833
2834/* */
2835size_t tou_stack_len(tou_llist_t* stack)
2836{
2837 return tou_llist_len(stack);
2838}
2839
2840
2841/* */
2842void tou_stack_push(tou_llist_t** stack, void* elem)
2843{
2844 if (stack == NULL)
2845 return;
2846 tou_llist_t* top = tou_llist_get_newest(*stack);
2847 tou_llist_appendone(&top, (void*)elem, 0);
2848 *stack = top;
2849 return;
2850}
2851
2852
2853/* */
2854void* tou_stack_pop(tou_llist_t** stack)
2855{
2856 if (stack == NULL || *stack == NULL)
2857 return NULL;
2858
2859 tou_llist_t* top = tou_llist_get_newest(*stack);
2860 if (!top)
2861 return NULL;
2862
2863 tou_llist_t* saved = tou_llist_get_older(top);
2864 void* val = tou_llist_pop(top);
2865 if (val) val = ((tou_llist_t*) val)->dat1;
2866
2868 *stack = saved;
2869
2870 return val;
2871}
2872
2873
2877
2878
2879/* */
2881{
2882 return tou_llist_new();
2883}
2884
2885/* */
2886void tou_queue_destroy(tou_llist_t* queue)
2887{
2888 return tou_llist_destroy(queue);
2889}
2890
2891/* */
2892size_t tou_queue_len(tou_llist_t* queue)
2893{
2894 return tou_llist_len(queue);
2895}
2896
2897/* */
2898void tou_queue_push(tou_llist_t** queue, void* elem)
2899{
2900 if (queue == NULL)
2901 return;
2902 tou_llist_t* bottom = tou_llist_get_oldest(*queue);
2903 tou_llist_t* new_elem = tou_llist_prependone(&bottom, (void*)elem, 0);
2904 if (*queue == NULL)
2905 *queue = new_elem;
2906 return;
2907}
2908
2909/* */
2910void* tou_queue_pop(tou_llist_t** queue)
2911{
2912 if (queue == NULL)
2913 return NULL;
2914 tou_llist_t* top = tou_llist_get_newest(*queue);
2915 if (top == NULL)
2916 return NULL;
2917
2918 tou_llist_t* saved = tou_llist_get_older(top);
2919 void* val = tou_llist_pop(top);
2920 if (val) val = ((tou_llist_t*) val)->dat1;
2921
2923 *queue = saved;
2924 return val;
2925}
2926
2927
2928
2932
2933#ifndef TOU_LLIST_SINGLE_ELEM
2934
2935/* */
2937{
2938 if (fp == NULL) {
2939 TOU_PRINTD("ini_parse_fp received empty fp\n");
2940 return NULL;
2941 }
2942
2943 tou_llist_t* inicontents = tou_llist_new();
2944 char line_buf[256+1];
2945 char* line = line_buf;
2946 size_t line_no = 0;
2947
2948 while (fgets(line, 256+1, fp)) {
2949 line_no++;
2950
2951 int status = tou_ini_parse_line(&inicontents, line);
2952 if (status == TOU_BREAK) {
2953 TOU_PRINTD("Invalid line encountered while parsing (line %zu): %s\n", line_no, line);
2954 tou_ini_destroy(inicontents);
2955 return NULL;
2956 }
2957 }
2958
2959 return inicontents;
2960}
2961
2962
2963/* */
2965{
2966 if (buf == NULL) {
2967 TOU_PRINTD("ini_parse_buf received empty buffer\n");
2968 return NULL;
2969 }
2970
2971 tou_llist_t* inicontents = tou_llist_new();
2972 size_t line_no = 0;
2973
2974 char* pos;
2975 const char* nls[] = {"\r\n", "\n"};
2976 int found_idx;
2977
2978 while ((pos = tou_sfind_multiple(buf, nls, 2, &found_idx)) != NULL)
2979 {
2980 line_no++;
2981 *pos = '\0';
2982
2983 int status = tou_ini_parse_line(&inicontents, buf);
2984 if (status == TOU_BREAK) {
2985 TOU_PRINTD("Invalid line encountered while parsing (line %zu): %s\n", line_no, buf);
2986 tou_ini_destroy(inicontents);
2987 return NULL;
2988 }
2989
2990 buf = pos + strlen(nls[found_idx]);
2991 }
2992
2993 // Last line
2994 if (tou_strlen(buf) > 0) {
2995 line_no++;
2996 if (tou_ini_parse_line(&inicontents, buf) == TOU_BREAK) {
2997 TOU_PRINTD("Invalid line encountered while parsing (line %zu): %s\n", line_no, buf);
2998 tou_ini_destroy(inicontents);
2999 return NULL;
3000 }
3001 }
3002
3003 return inicontents;
3004}
3005
3006
3007/* */
3008int tou_ini_parse_line(tou_llist_t** inicontents, char* line)
3009{
3010 // Ignore null lines but break if inicontents is null
3011 if (inicontents == NULL)
3012 return TOU_BREAK;
3013 if (line == NULL)
3014 return TOU_CONTINUE;
3015
3016 // Cut off front whitespace
3017 tou_trim_front(&line);
3018 if (*line == '\0')
3019 return TOU_CONTINUE;
3020
3021 // Check if comment line
3022 switch(*line) {
3023 case ';':
3024 case '#':
3025 return TOU_CONTINUE;
3026 }
3027
3028 // Check if section declaration
3029 if (*line == '[') {
3030
3031 tou_trim_back(&line);
3032 size_t line_len = strlen(line);
3033
3034 // Cut off front bracket
3035 line++;
3036 line_len--;
3037
3038 // If other bracket doesn't exist ignore it and still parse as valid syntax
3039 if (line[line_len - 1] == ']') {
3040 line[line_len - 1] = '\0';
3041 line_len--;
3042 }
3043
3044 // Append section
3045 tou_llist_append(inicontents,
3046 tou_strdup(line), NULL,
3047 1, 0);
3048
3049 TOU_PRINTD("Appended section: %s\n", (*inicontents)->dat1);
3050 return TOU_CONTINUE;
3051 }
3052
3053 // Alright then, check if line matches a property line type; otherwise it's an invalid line
3054
3055 // Test if either delimiter exists in line
3056 char* prop = tou_sfind(line, " = ");
3057 int prop_len = 3;
3058
3059 if (prop == NULL) {
3060 prop = tou_sfind(line, "=");
3061 prop_len = 1;
3062
3063 // Invalid line
3064 if (prop == NULL) {
3065 int len = strlen(line);
3066 if (line[len - 1] == '\n')
3067 line[len - 1] = '\0';
3068 return TOU_BREAK;
3069 }
3070 }
3071
3072 // Property encountered before any section declaration
3073 if (*inicontents == NULL) {
3074 return TOU_BREAK;
3075 }
3076
3077 // Duplicate key and value and append to list
3078 *prop = '\0';
3079 char* key = line;
3080 char* val = prop + prop_len;
3081
3082 if (TOU_IS_BLANK(*val)) // Remove leading (only first one) whitespace
3083 val++;
3084 tou_trim_back(&key);
3085 tou_trim_back(&val);
3086
3087 TOU_PRINTD(" Key: %s, Val: %s\n", key, val);
3088 tou_llist_append((tou_llist_t**)( &((*inicontents)->dat2) ), // append to "current section" element
3089 tou_strdup(key), tou_strdup(val), // copy key, copy val
3090 1, 1); // auto dealloc both key&val
3091
3092 return TOU_CONTINUE;
3093}
3094
3095
3096/* */
3097void tou_ini_destroy(tou_llist_t* inicontents)
3098{
3099 tou_llist_t* section = inicontents;
3100 while (section) {
3101 tou_llist_destroy(section->dat2); // Destroy each props sublist
3102 TOU_PRINTD("Destroying section: %s\n", section->dat1);
3103 section = section->prev;
3104 }
3105 tou_llist_destroy(inicontents); // Destroy whole structure
3106 TOU_PRINTD("Destroyed INI structure.\n");
3107}
3108
3109
3110/* */
3111void tou_ini_print(tou_llist_t* inicontents)
3112{
3113 if (inicontents == NULL) {
3114 TOU_PRINTD("ini_print received empty struct\n");
3115 return;
3116 }
3117
3118 tou_llist_t* section = inicontents;
3119 tou_llist_t* props;
3120 fprintf(stdout, "<.INI STRUCTURE>\n");
3121 fprintf(stdout, " |\n");
3122
3123 while (section) {
3124 props = section->dat2;
3125 char next_section_ch = (section->prev == NULL) ? ' ' : '|';
3126 fprintf(stdout, " +-> [SECTION] \"%s\"\n", (char*)section->dat1);
3127 while (props) {
3128 fprintf(stdout, " %c |\n", next_section_ch);
3129 fprintf(stdout, " %c +-> [PROP] \"%s\": \"%s\"\n",
3130 next_section_ch, (char*)props->dat1, (char*)props->dat2);
3131 props = props->prev;
3132 }
3133 fprintf(stdout, " %c\n", next_section_ch);
3134 section = section->prev;
3135 }
3136}
3137
3138
3139/* */
3140tou_llist_t* tou_ini_get_section(tou_llist_t* inicontents, const char* section_name)
3141{
3142 if (inicontents == NULL || section_name == NULL) {
3143 TOU_PRINTD("ini_get_section received empty params\n");
3144 return NULL;
3145 }
3146
3147 tou_llist_t* sect = tou_llist_find_key(inicontents, (void*)section_name);
3148 if (sect == NULL) {
3149 TOU_PRINTD("ini_get_section unable to find given section\n");
3150 return NULL;
3151 }
3152
3153 return sect;
3154}
3155
3156
3157/* */
3158tou_llist_t* tou_ini_get_property(tou_llist_t* inicontents, const char* section_name, const char* key)
3159{
3160 if (inicontents == NULL || section_name == NULL || key == NULL) {
3161 TOU_PRINTD("ini_get_property received empty params\n");
3162 return NULL;
3163 }
3164
3165 tou_llist_t* sect = tou_llist_find_key(inicontents, (void*) section_name);
3166 if (sect == NULL) {
3167 TOU_PRINTD("ini_get_property unable to find given section\n");
3168 return NULL;
3169 }
3170 // TOU_PRINTD("TOU_INI_GET_PROPERTY found SECTION %s\n", sect->dat1);
3171
3172 tou_llist_t* prop = tou_llist_find_key(sect->dat2, (void*)key );
3173 if (prop == NULL) {
3174 TOU_PRINTD("ini_get_property unable to find given key\n");
3175 }
3176
3177 return prop;
3178}
3179
3180
3181/* */
3182tou_llist_t* tou_ini_section(tou_llist_t* inicontents, const char* section_name)
3183{
3184 tou_llist_t* sect = tou_ini_get_section(inicontents, (void*)section_name);
3185 if (sect == NULL)
3186 return NULL;
3187 return sect->dat2;
3188}
3189
3190
3191/* */
3192void* tou_ini_property(tou_llist_t* section, const char* property_name)
3193{
3194 tou_llist_t* prop = tou_llist_find_key(section, (void*)property_name);
3195 if (prop == NULL)
3196 return NULL;
3197 return prop->dat2;
3198}
3199
3200
3201/* */
3202void* tou_ini_get(tou_llist_t* inicontents, const char* section_name, const char* key)
3203{
3204 tou_llist_t* prop = tou_ini_get_property(inicontents, section_name, key);
3205 TOU_PRINTD("ini_get prop: %p\n", prop);
3206
3207 if (prop)
3208 return prop->dat2;
3209 return NULL;
3210}
3211
3212
3213/* */
3214void* tou_ini_set(tou_llist_t** inicontents, const char* section_name, const char* key, char* new_value)
3215{
3216 if (inicontents == NULL || *inicontents == NULL || section_name == NULL || key == NULL || new_value == NULL) {
3217 TOU_PRINTD("[ini_set] received empty params\n");
3218 return NULL;
3219 }
3220
3221 tou_llist_t* sect = tou_llist_find_key(*inicontents, (void*)section_name);
3222 if (sect == NULL) {
3223 TOU_PRINTD("[ini_set] section not found, allocating new...\n");
3224 // TODO: tou_ini_new_section ?
3225 sect = tou_llist_append(inicontents, tou_strdup(section_name), NULL, 1, 0);
3226 }
3227
3228 tou_llist_t* prop = tou_llist_find_key(sect->dat2, (void*)key);
3229
3230 if (prop == NULL) {
3231 // Allocate new property...
3232 TOU_PRINTD("[ini_set] property not found\n");
3233
3234 prop = tou_llist_append(
3235 (tou_llist_t**)(&sect->dat2),
3236 tou_strdup(key), tou_strdup(new_value),
3237 1, 1);
3238
3239 TOU_PRINTD("[ini_set] %s, %s\n", prop->dat1, prop->dat2);
3240 return prop->dat2;
3241
3242 } else {
3243 // ...or set/realloc the existing one
3244 TOU_PRINTD("[ini_set] property found\n");
3245
3246 char* old_value = prop->dat2;
3247 size_t old_len = strlen(old_value);
3248 size_t new_len = strlen(new_value);
3249
3250 if (new_len > old_len)
3251 old_value = realloc(old_value, new_len + 1);
3252
3253 tou_strlcpy(old_value, new_value, new_len + 1);
3254 prop->dat2 = old_value;
3255
3256 return prop->dat2;
3257 }
3258}
3259
3260
3261/* */
3262int tou_ini_save_fp(tou_llist_t* inicontents, FILE* fp)
3263{
3264 if (inicontents == NULL || fp == NULL) {
3265 TOU_PRINTD("[ini_save_fp] received empty params\n");
3266 return -1;
3267 }
3268
3269 tou_llist_t* section = inicontents;
3270 while (section) {
3271 if (section->dat1 == NULL) {
3272 TOU_PRINTD("[ini_save_fp] Invalid section name encountered\n");
3273 return -3;
3274 }
3275 // Print section name
3276 fprintf(fp, "[%s]", (char*)section->dat1);
3277 if (ferror(fp)) {
3278 TOU_PRINTD("[ini_save_fp] Error writing to stream\n");
3279 return -2;
3280 }
3281
3282 tou_llist_t* prop = section->dat2;
3283 while (prop) {
3284 if (prop->dat1 == NULL || prop->dat2 == NULL) {
3285 TOU_PRINTD("[ini_save_fp] Invalid property data encountered\n");
3286 return -4;
3287 }
3288 fprintf(fp, "\n%s = %s", (char*)prop->dat1, (char*)prop->dat2);
3289 prop = prop->prev;
3290 }
3291
3292 fprintf(fp, "\n");
3293 section = section->prev;
3294 }
3295
3296 return 0;
3297}
3298
3299
3300/* */
3301int tou_ini_save_fp_json(tou_llist_t* inicontents, FILE* fp)
3302{
3303 if (inicontents == NULL || fp == NULL) {
3304 TOU_PRINTD("[ini_save_fp_json] received empty params\n");
3305 return -1;
3306 }
3307
3308 // Print initial json struct and metadata
3309 fprintf(fp, "{\n\t\"ver\": " TOU_MSTR(TOU_JSON_DATA_VER) ",\n\t\"sections\": {");
3310 if (ferror(fp)) {
3311 TOU_PRINTD("[ini_save_fp_json] Error writing to stream\n");
3312 return -2;
3313 }
3314
3315 tou_llist_t* section = inicontents;
3316 // size_t nsections = 0;
3317 while (section) {
3318 if (section->dat1 == NULL) {
3319 TOU_PRINTD("[ini_save_fp_json] Invalid section name encountered\n");
3320 return -3;
3321 }
3322 // Print section name
3323 fprintf(fp, "\n\t\t\"%s\": {", section->dat1);
3324
3325 tou_llist_t* prop = section->dat2;
3326 // size_t nprops = 0;
3327 while (prop) {
3328 if (prop->dat1 == NULL || prop->dat2 == NULL) {
3329 TOU_PRINTD("[ini_save_fp_json] Invalid property data encountered\n");
3330 return -4;
3331 }
3332
3333 // Print property
3334 fprintf(fp, "%s\n\t\t\t\"%s\": \"%s\"", (prop==section->dat2 ? "":","), prop->dat1, prop->dat2);
3335 // nprops++;
3336 prop = prop->prev;
3337 }
3338
3339 fprintf(fp, "\n\t\t}%s", (section->prev==NULL ? "":","));
3340 // nsections++;
3341 section = section->prev;
3342 }
3343
3344 // fprintf(fp, "\n\t},\n\t\"section_count\": %zu\n}\n", nsections);
3345 fprintf(fp, "\n\t}\n}");
3346
3347 return 0;
3348}
3349
3350/* */
3351int tou_ini_save_fp_xml(tou_llist_t* inicontents, FILE* fp)
3352{
3353 if (inicontents == NULL || fp == NULL) {
3354 TOU_PRINTD("[ini_save_fp_xml] received empty params\n");
3355 return -1;
3356 }
3357 tou_llist_t* section = inicontents;
3358
3359 // Print initial json struct and metadata
3360 const char* root_tag = "root";
3361 fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
3362 fprintf(fp, "<%s ver="TOU_MSTR(TOU_XML_DATA_VER)" len=\"%zu\">", root_tag, tou_llist_len(inicontents));
3363 if (ferror(fp)) {
3364 TOU_PRINTD("[ini_save_fp_xml] Error writing to stream\n");
3365 return -2;
3366 }
3367
3368 while (section) {
3369 if (section->dat1 == NULL) {
3370 TOU_PRINTD("[ini_save_fp_xml] Invalid section name encountered\n");
3371 return -3;
3372 }
3373 tou_llist_t* prop = section->dat2;
3374
3375 // Print section name and attr(s)
3376 char* sect_name_tag = tou_replace_ch(strdup(section->dat1), ' ', '-');
3377 fprintf(fp, "\n\t<%s len=\"%zu\">", sect_name_tag, tou_llist_len(prop));
3378
3379 while (prop) {
3380 if (prop->dat1 == NULL || prop->dat2 == NULL) {
3381 TOU_PRINTD("[ini_save_fp_xml] Invalid property data encountered\n");
3382 return -4;
3383 }
3384 char* prop_name_tag = tou_replace_ch(tou_strdup(prop->dat1), ' ', '-');
3385
3386 // Print property
3387 fprintf(fp, "\n\t\t<%s>%s</%s>", prop_name_tag, prop->dat2, prop_name_tag);
3388 prop = prop->prev;
3389 }
3390
3391 fprintf(fp, "\n\t</%s>", sect_name_tag);
3392 section = section->prev;
3393 }
3394
3395 fprintf(fp, "\n</%s>", root_tag);
3396
3397 return 0;
3398}
3399
3400#endif
3401
3402
3406
3407#ifndef TOU_LLIST_SINGLE_ELEM
3408
3409/* */
3410tou_llist_t* tou_paramparse(char* str, const char* param_sep, const char* keyval_sep)
3411{
3412 return tou_paramparse_n(str, param_sep, keyval_sep, 0);
3413}
3414
3415
3416/* */
3417tou_llist_t* tou_paramparse_n(char* str, const char* param_sep, const char* keyval_sep, size_t maxlen)
3418{
3419 size_t psep_len = strlen(param_sep);
3420 size_t kvsep_len = strlen(keyval_sep);
3421
3422 if (maxlen == 0)
3423 maxlen = strlen(str);
3424
3425 // save char to restore it later //
3426 char saved = str[maxlen];
3427 str[maxlen] = '\0';
3428
3429 // parse //
3430 // Initially split by param separator and afterwards parse each param
3431 tou_llist_t* params = tou_split(str, param_sep);
3432
3433 while (params) {
3434 if (!params->dat1)
3435 params = params->prev;
3436
3437 bool dont = false;
3438 char* trimmed_both = params->dat1;
3439 tou_trim_string(&trimmed_both); // trim to beginning of the key at the front, and the back of the value
3440 size_t both_len = strlen(trimmed_both);
3441
3442 if (strlen(trimmed_both) > 0) { // in case split() inserted empty "" element
3443 // params->dat1 dupe will be done after processing value
3444
3445 // Find value offset from current key ptr
3446 char* sep = tou_sfind(trimmed_both, keyval_sep);
3447 if (sep) {
3448 *sep = '\0'; // cuts off key name in dat1 to be realloc'd later
3449 char* trimmed_val = sep + kvsep_len;
3450 tou_trim_front(&trimmed_val);
3451
3452 params->dat2 = tou_strdup(trimmed_val);
3453
3454 if (params->dat2 != NULL)
3455 params->destroy_dat2 = 1;
3456 } else {
3457 params->dat2 = NULL;
3458 params->destroy_dat2 = 0;
3459 }
3460
3461 // There's a '\0' either at the separator or at the end
3462 // so this trims back of the key
3463 size_t trimmed_key_len = tou_trim_back(&trimmed_both) - trimmed_both;
3464 memmove(params->dat1, trimmed_both, trimmed_key_len + 1); // move trimmed key to front
3465 params->dat1 = realloc(params->dat1, trimmed_key_len + 1); // free(params->dat1)
3466 params->destroy_dat1 = 1;
3467
3468 } else {
3469 // remove this empty element
3470 // TODO: does the updated llist_remove() perform this operation?
3471 tou_llist_pop(params);
3472 char prev_was_null = (params->prev == NULL);
3473 tou_llist_t* relink = (params->prev) ? params->prev : params->next;
3474 tou_llist_free_element(params);
3475 params = relink;
3476
3477 if (prev_was_null)
3478 break;
3479
3480 dont = true; // don't process params->prev as usual since we just adjusted list
3481 }
3482 if (!dont) params = params->prev;
3483 }
3484
3485 // restore char
3486 str[maxlen] = saved;
3487
3488 return tou_llist_get_head(params);
3489}
3490
3491
3492/* */
3493void tou_paramprint(tou_llist_t* params)
3494{
3495 params = tou_llist_get_oldest(params);
3496 printf("Parameters (%d):\n", tou_llist_len(params));
3497 while (params) {
3498 printf(" \"%s\" : %p\n", params->dat1, params->dat2);
3499 tou_llist_next_newer(&params);
3500 }
3501 printf("\n");
3502}
3503
3504#endif
3505
3506
3507/* Loading icon
3508printf("⣿ ⣾⣽⣻⢿⡿⣟⣯⣷\n");
3509printf("⠿ ⠾⠽⠻⠟⠯⠷\n"); */
3510
3511
3512#endif // TOU_IMPLEMENTATION_DONE
3513#endif // TOU_IMPLEMENTATION
#define TOU_PRINTD(format,...)
Debug print, used like printf()
Definition tou.h:77
void * tou_block_store_cb(void *blockdata, void *len, void *userdata)
Appends the given block to the buffer in tou_block_store_struct through realloc().
void tou_enable_stdout(int saved_fd)
Re-enables STDOUT that had been disabled using the saved file descriptor from previous function.
int _tou_g_saved_stdout
Filedescriptor handle local to this compilation unit used with TOU_SILENCE.
Definition tou.h:722
int tou_disable_stdout()
Redirects STDOUT to /dev/null (or NUL: on Windows)
size_t tou_read_fp_in_blocks(FILE *fp, size_t blocksize, tou_func3 cb, void *userdata)
Reads file in blocks, calling user-provided function for each block.
char * tou_read_file(const char *filename, size_t *read_len)
Reads file from filename.
char * tou_read_fp(FILE *fp, size_t *read_len)
Reads from fp.
tou_llist_t * tou_ini_get_section(tou_llist_t *inicontents, const char *section_name)
Returns pointer to the section element matching given 'section_name'.
tou_llist_t * tou_ini_get_property(tou_llist_t *inicontents, const char *section_name, const char *key)
Returns pointer to the property element matching given 'section_name' and 'key'.
int tou_ini_save_fp_xml(tou_llist_t *inicontents, FILE *fp)
Exports .INI structure data as XML to the file stream.
int tou_ini_save_fp_json(tou_llist_t *inicontents, FILE *fp)
Exports .INI structure data as JSON to the file stream.
tou_llist_t * tou_ini_section(tou_llist_t *inicontents, const char *section_name)
Return a pointer to the llist entry of the matching section, or NULL.
void tou_ini_print(tou_llist_t *inicontents)
Prints the contents of the parsed .INI structure to stdout in a structured graphical format.
void * tou_ini_set(tou_llist_t **inicontents, const char *section_name, const char *key, char *new_value)
Sets the contents of 'key' under the given 'section_name' to the specified value, reallocating memory...
tou_llist_t * tou_ini_parse_buffer(char *buf)
Parses given buffer as .INI file and constructs structured data.
void * tou_ini_property(tou_llist_t *section, const char *property_name)
Return the value of the matching property in the given section, or NULL.
void tou_ini_destroy(tou_llist_t *inicontents)
Destroys contents of .INI structure including deallocation of inner structures; assumes head was pass...
int tou_ini_save_fp(tou_llist_t *inicontents, FILE *fp)
Writes .INI structure data to file stream.
tou_llist_t * tou_ini_parse_fp(FILE *fp)
Parses given FILE* as .INI file and constructs structured data.
void * tou_ini_get(tou_llist_t *inicontents, const char *section_name, const char *key)
Returns the contents of 'key' under the given 'section_name'.
int tou_ini_parse_line(tou_llist_t **inicontents, char *line)
Parses a single line as .INI section/property and adds it to structure.
tou_llist_t * tou_llist_remove(tou_llist_t *elem)
Removes an element from llist and deallocates it.
char tou_llist_is_head(tou_llist_t *elem)
Checks if element is head of the list (.next should be NULL)
tou_llist_t * tou_llist_get_newest(tou_llist_t *list)
Returns the element that was added to the list last.
size_t tou_llist_len(tou_llist_t *list)
Goes through the list and returns amount of elements.
tou_llist_t * tou_llist_prepend(tou_llist_t **elem, void *dat1, void *dat2, char dat1_is_dynalloc, char dat2_is_dynalloc)
Prepends a brand new element to the list/given element.
tou_llist_t * tou_llist_find_exact(tou_llist_t *list, void *dat1, void *dat2)
Traverses the list starting from the passed element and tries to find the first matching element by s...
tou_llist_t * tou_llist_pop(tou_llist_t *elem)
Disconnects an element from llist but does not deallocate it.
tou_llist_t * tou_llist_next_older(tou_llist_t **elem)
Updates elem to point to the element added before itself.
tou_llist_t * tou_llist_appendone(tou_llist_t **elem, void *dat1, char dat1_is_dynalloc)
Appends a brand new element to the list/given element which contains only dat1 and if the pointer was...
void ** tou_llist_gather_dat2(tou_llist_t *list, size_t *len)
Constructs a dynamically allocated ARRAY containing only .dat2 properties (stored as void*).
tou_llist_t * tou_llist_get_newer(tou_llist_t *elem)
Returns the element added after elem.
void ** tou_llist_gather_dat1(tou_llist_t *list, size_t *len)
Constructs a dynamically allocated ARRAY containing only .dat1 properties (stored as void*).
tou_llist_t * tou_llist_find_key(tou_llist_t *list, void *dat1)
Traverses the list starting from the passed element and tries to find the first matching element on t...
void tou_llist_free_element(tou_llist_t *elem)
Frees an element and its contents.
tou_llist_t * tou_llist_append(tou_llist_t **elem, void *dat1, void *dat2, char dat1_is_dynalloc, char dat2_is_dynalloc)
Appends a brand new element to the list/given element and updates it in place.
tou_llist_t * tou_llist_next_newer(tou_llist_t **elem)
Updates elem to point to the element added after itself.
tou_llist_t * tou_llist_find_func(tou_llist_t *list, tou_func2 cb, void *userdata)
Traverses the list starting from the passed element and tries to find the first matching element by c...
tou_llist_t * tou_llist_get_tail(tou_llist_t *list)
Traverses the whole list using .prev and returns the first element that was added to list (where ....
tou_llist_t * tou_llist_prependone(tou_llist_t **elem, void *dat1, char dat1_is_dynalloc)
Prepends a brand new element to the list/given element which only contains dat1.
#define tou_llist_new(...)
Creates/initializes new llist.
Definition tou.h:773
void tou_llist_iter(tou_llist_t *list, tou_func cb)
Iterate through and call the specified function for each element Automatically checks whether given e...
tou_llist_t * tou_llist_find_exactone(tou_llist_t *list, void *dat1)
Traverses the list starting from the passed element and tries to find the first matching element by s...
void tou_llist_destroy(tou_llist_t *list)
Traverses elements using .next or .prev and frees each one including copied category string.
tou_llist_t * tou_llist_get_head(tou_llist_t *list)
Traverses the whole list using .next and returns the last element that was added into list (where ....
tou_llist_t * tou_llist_get_oldest(tou_llist_t *list)
Returns the element that was added to the list first.
tou_llist_t * tou_llist_get_older(tou_llist_t *elem)
Returns the element added before elem.
char tou_llist_is_tail(tou_llist_t *elem)
Checks if element is tail of the list (.prev should be NULL)
tou_llist_t * tou_paramparse(char *str, const char *param_sep, const char *keyval_sep)
Parses "parameter string" and returns a llist of key-value pairs, looking at the whole string (strlen...
void tou_paramprint(tou_llist_t *params)
Attempts to print "params" parsed by tou_paramparse or tou_paramparse_n.
tou_llist_t * tou_paramparse_n(char *str, const char *param_sep, const char *keyval_sep, size_t maxlen)
Parses "parameter string" and returns a llist of key-value pairs.
size_t tou_queue_len(tou_llist_t *queue)
Returns the length of the queue.
void * tou_queue_pop(tou_llist_t **queue)
Pops an element from the top of the Queue.
tou_llist_t tou_queue
Make a queue alias for convenience.
Definition tou.h:1250
void tou_queue_destroy(tou_llist_t *queue)
Destroys existing queue object.
tou_llist_t * tou_queue_new()
Creates a new queue object.
void tou_queue_push(tou_llist_t **queue, void *elem)
Pushes a new element to the top of the Queue.
void * tou_stack_pop(tou_llist_t **stack)
Pops an element from the top of the stack.
void tou_stack_destroy(tou_llist_t *stack)
Destroys existing stack object.
tou_llist_t tou_stack
Make a stack alias for convenience.
Definition tou.h:1199
tou_llist_t * tou_stack_new()
Creates a new stack object.
void tou_stack_push(tou_llist_t **stack, void *elem)
Pushes a new element to the top of the stack.
size_t tou_stack_len(tou_llist_t *stack)
Returns the length of the stack.
char * tou_trim_back(char **str)
Trims whitespaces only from the back of the string.
char * tou_sprepend(char *dst, char *src)
(Re)allocates enough memory for src and prepends it to dst
void tou_sfind_iter_multiple_n(const char *src, const char *kwds[], int n_kwds, tou_func3 cb, void *userdata, size_t maxlen)
Iteratively finds occurences of strings in kwds and calls user function for each one,...
char * tou_sreplace(char *str, char *repl_str, char *with_str)
Helper for tou_sreplace that takes the whole string into consideration.
void tou_trim_string_pure(char *str, char **start, char **end)
Returns pointers to the first and last character that are not whitespaces.
char * tou_strchr(const char *src, int ch)
Finds the first occurence of ch in the string and returns pointer to it, or NULL if not found.
char * tou_trim_front(char **str)
Trims whitespaces only from the front of the string.
char * tou_strdup(const char *src)
Strdup implementation; returns a malloc'd copy of the string.
char * tou_strrchr(const char *src, int ch)
Finds the last occurence of ch in the string and returns pointer to it, or NULL if not found.
char * tou_sfind_multiple_n(const char *str, const char **kwds, int n_kwds, int *found_idx, size_t maxlen)
Like tou_sfind_n but searches for more than one string at a time.
char * tou_sfind_multiple(const char *str, const char **kwds, int n_kwds, int *found_idx)
Like tou_sfind but searches for more than one string at a time.
char * tou_trim_string(char **str)
Trims whitespaces from front and back of the string.
char * tou_trim_back_pure(char *str)
Returns pointer to the first byte AFTER the contents of the string, or the NUL byte.
char * tou_trim_front_pure(char *str)
Returns pointer to the first character from the front that isn't a whitespace.
char * tou_replace_ch(char *ss, char oldch, char newch)
Replaces all occurences of oldch with newch
char * tou_sappend(char *dst, char *src)
(Re)allocates enough memory for src and appends it to dst
size_t tou_strlcpy(char *dst, const char *src, size_t size)
Copies string SRC to DST, always places terminator.
char * tou_sreplace_n(char *str, char *repl_str, char *with_str, size_t *len_ptr)
Replaces string repl_str with with_str in the str, testing str up to the character *len_ptr.
tou_llist_t * tou_split(char *str, const char *delim)
Splits string using a delimiter that may be longer than one character.
size_t tou_strlen(const char *str)
Same as strlen() but checks for null pointer.
size_t tou_strlcat(char *dst, const char *src, size_t size)
Concatenates string SRC to DST, always places terminator.
char * tou_sfind_n(const char *str, const char *kwd, size_t maxlen)
Finds start of substring(keyword) in the given char*, looking at a max of maxlen characters.
char * tou_strndup(const char *src, size_t size)
Returns a newly allocated copy of a string, capped at 'size' length (not including '\0'),...
void tou_sfind_iter_multiple(const char *src, const char *kwds[], int n_kwds, tou_func3 cb, void *userdata)
Iteratively finds occurences of strings in kwds and calls user function for each one.
char * tou_sfind(const char *str, const char *kwd)
Finds start of substring(keyword) in the given char*.
char * tou_slower(char *str)
Converts all characters in str to lowercase in-place.
char * tou_supper(char *str)
Converts all characters in str to uppercase in-place.
tou_iter_action
Can be used while iterating to indicate user wishing to abort or continue as normal.
Definition tou.h:161
void *(* tou_func)(void *)
Arbitrary function pointer with 1 parameter.
Definition tou.h:172
#define TOU_JSON_DATA_VER
Data format version when exporting INI to JSON.
Definition tou.h:111
void *(* tou_func2)(void *, void *)
Arbitrary function pointer with 2 parameters.
Definition tou.h:177
#define TOU_MSTR(s)
Helps convert 's' into C literal.
Definition tou.h:129
#define TOU_DEFAULT_BLOCKSIZE
How many bytes to read when reading a file if unspecified.
Definition tou.h:107
void *(* tou_func3)(void *, void *, void *)
Arbitrary function pointer with 3 parameters.
Definition tou.h:182
#define TOU_XML_DATA_VER
Data format version when exporting INI to JSON.
Definition tou.h:114
#define TOU_IS_BLANK(c)
Is character a whitespace char?
Definition tou.h:136
Struct containing buffer and count to be used in block-reading.
Definition tou.h:636
char * buffer
Buffer to append data to.
Definition tou.h:637
size_t size
Length of the buffer contents.
Definition tou.h:638
Linked list struct definition, typedef'd.
Definition tou.h:198
char destroy_dat1
automatically deallocate this data ?
Definition tou.h:205
void * dat2
useful data
Definition tou.h:203
struct tou_llist * next
next element
Definition tou.h:200
char destroy_dat2
automatically deallocate this data ?
Definition tou.h:207
void * dat1
useful data
Definition tou.h:201
struct tou_llist * prev
previous element
Definition tou.h:199
struct tou_llist tou_llist_elem
Make an element alias for convenience.
Definition tou.h:212