co.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. co.h
  3. C Object Library
  4. (c) 2024 Oliver Kraus
  5. https://github.com/olikraus/c-object
  6. CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0/
  7. -DCO_USE_ZLIB
  8. will enable autodetection of .gz compressed input files (this will require
  9. linking against "-lz")
  10. co read/and writeable c-object
  11. cco read only c-object
  12. Warning like "discards ‘const’ qualifier" indicate ERRORs!
  13. However the above warnings are not always generated, this means
  14. - if the warning is generated, then create a clone
  15. - if the warning is not generated, then there still might be an isse (see
  16. examples below)
  17. objects assigned to containers are moved, this means, the source obj is
  18. destroyed (unless otherwise mentioned) objects taken out of a container are
  19. read only
  20. Example 1:
  21. co v = coNewVector();
  22. coAdd(v, coNewStr(CO_STRDUP, "abc")); // valid, return value of coNewStr is
  23. deleted by v
  24. Example 2:
  25. co v = coNewVector();
  26. co s = coNewStr(CO_STRDUP, "abc");
  27. coAdd(v, s); // valid, but s is invalid after this statement
  28. coAdd(v, s); // invalid, because s is already illegal
  29. Example 3:
  30. co v = coNewVector();
  31. co s = coNewStr(CO_STRDUP, "abc");
  32. coAdd(v, s); // valid, but s is invalid after this statement
  33. coDelete(s); // invalid, because s will be deleted by v again
  34. Example 4:
  35. co v = coNewVector();
  36. co s;
  37. for( i = 0; i < 10; i++ )
  38. {
  39. s = coNewStr(CO_STRDUP, "abc"); // valid, s is illegal and will be
  40. overwritten coAdd(v, s); // valid, but s is invalid after this
  41. statement
  42. }
  43. Example 5:
  44. coAdd(v, coGetByIdx(v, 0)); // invalid & will generate a warning.. use clone
  45. instead
  46. Hint:
  47. gcc -Wall -fsanitize=address -fsanitize=undefined -fsanitize=leak *.c
  48. gcc -Wall -fsanitize=address -I./co ./co/co.c ./test/co_test.c && ./a.out
  49. Copy operation from somewhere into a container
  50. 1) Move: The remote element becoMapes obsolete and becoMapes part of the
  51. container The moved element will be deleted together with the container The
  52. moved element must not be referenced any more somewhere else 2) Reference: The
  53. element in the container is just a reference to the remote element. The
  54. element of the container is not deleted. Risk: If the remote element becoMapes
  55. deleted, then the element in the container is also invalid 3) Clone: Usually a
  56. manual operation, where the element is cloned and then stored in the
  57. container. Makes only sense with option 1
  58. Vector: isElementDelete --> 0 / 1
  59. Map: isKeyDelete --> 0 / 1, isValueDelete --> 0 / 1
  60. Vector
  61. isElementDelete == true
  62. add( new() ) --> ok
  63. add( clone( new() ) --> wrong, memory leak
  64. add( container_get() ) --> wrong, double delete
  65. add ( clone( container_get() ) ) -> ok
  66. isElementDelete == false
  67. add( new() ) --> wrong, memory leak
  68. add( clone( new() ) ) --> wrong, 2x memory leak
  69. add( container_get() ) --> ok
  70. add( clone( container_get() ) ) -> memory leak
  71. */
  72. #ifndef CO_INCLUDE
  73. #define CO_INCLUDE
  74. #include <stddef.h>
  75. #include <stdint.h>
  76. #include <stdio.h>
  77. #ifdef CO_USE_ZLIB
  78. #include "zlib.h"
  79. #endif /* CO_USE_ZLIB */
  80. /*
  81. #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
  82. # include <fcntl.h>
  83. # include <io.h>
  84. #endif
  85. */
  86. typedef struct coStruct *co;
  87. typedef const struct coStruct *cco;
  88. typedef struct coFnStruct *coFn;
  89. typedef int (*coInitFn)(co o, void *data);
  90. typedef long (*coSizeFn)(cco o);
  91. typedef void (*coPrintFn)(const cco o);
  92. typedef void (*coDestroyFn)(co o);
  93. typedef co (*coCloneFn)(cco o);
  94. struct co_avl_node_struct // structure to build the AVL tree for the "map"
  95. // object
  96. {
  97. const char *key;
  98. void *value;
  99. struct co_avl_node_struct *kid[2];
  100. int height;
  101. };
  102. #define CO_NONE 0
  103. #define CO_FREE_VALS 1
  104. #define CO_FREE_FIRST 2
  105. /* used by str and map objects
  106. CO_STRDUP: execute a strdup on the string or key
  107. If CO_STRDUP is used, then also CO_STRFREE will be enabled
  108. CO_STRFREE: execute free on the string or key
  109. */
  110. #define CO_STRDUP 4
  111. #define CO_STRFREE 8
  112. struct coStruct {
  113. coFn fn;
  114. unsigned flags; // see above, e.g. CO_NONE, CO_FREE_VALS, etc...
  115. union {
  116. struct // vector
  117. {
  118. cco *list;
  119. size_t cnt;
  120. size_t max;
  121. } v;
  122. struct // map
  123. {
  124. struct co_avl_node_struct *root;
  125. } m;
  126. struct // string and memory block
  127. {
  128. char *str;
  129. size_t len; // current str/mem length
  130. size_t memlen; // allocated memory (not used for strings)
  131. } s;
  132. struct // double
  133. {
  134. double n;
  135. } d;
  136. };
  137. };
  138. struct coFnStruct {
  139. coInitFn init; // (*coInitFn)(co o);
  140. coSizeFn size;
  141. coPrintFn print;
  142. coDestroyFn destroy; // counterpart to init
  143. coCloneFn clone;
  144. };
  145. /* object types */
  146. extern coFn coBlankType;
  147. extern coFn coVectorType;
  148. extern coFn coStrType;
  149. extern coFn coMemType;
  150. extern coFn coMapType;
  151. extern coFn coDblType;
  152. /* object construction */
  153. co coNewBlank();
  154. co coNewStr(unsigned flags,
  155. const char *s); // most often CO_STRDUP should be used
  156. co coNewDbl(double n);
  157. co coNewMem(void);
  158. co coNewVector(unsigned flags);
  159. co coNewVectorByMap(
  160. cco map); // constructs a vector from a map, elements of the vector is again
  161. // a vector with two elements, the key and the value
  162. co coNewMap(unsigned flags);
  163. /* object type test procedures */
  164. #define coGetType(o) ((o == NULL) ? 0 : ((o)->fn))
  165. #define coIsVector(o) (coGetType(o) == coVectorType)
  166. #define coIsStr(o) (coGetType(o) == coStrType)
  167. #define coIsMem(o) (coGetType(o) == coMemType)
  168. #define coIsMap(o) (coGetType(o) == coMapType)
  169. #define coIsDbl(o) (coGetType(o) == coDblType)
  170. /* generic object functions */
  171. void coPrint(const cco o); // debug output of the provided object "o"
  172. void coDelete(
  173. co o); // deletes "o" and the childs objects of "o" depending on the flags
  174. co coClone(cco o); // do a deep copy of the object "o"
  175. long coSize(cco o);
  176. /* JSON read/write */
  177. co coReadJSONByString(const char *json);
  178. co coReadJSONByFP(FILE *fp); // supports UTF-8 BOM and detects GZIP (if
  179. // CO_USE_ZLIB is enabled)
  180. void coWriteJSON(cco o, int isCompact, int isUTF8,
  181. FILE *fp); // isUTF8 is 0, then output char codes >=128 via \u
  182. /* string functions */
  183. int coStrAdd(co o, const char *s); // concats the given string to the string
  184. // object, requires the CO_STRDUP flag
  185. char *coStrDeleteAndGetAllocatedStringContent(
  186. co o); // convert a str obj to a string, return value must be free'd
  187. const char *coStrToString(cco o); /* obsolete, use coStrGet() */
  188. const char *coStrGet(cco o); /* return the internal string as a reference */
  189. /* memory functions */
  190. long coMemSize(cco o);
  191. int coMemAdd(co o, const void *mem, size_t len);
  192. const void *coMemGet(cco o);
  193. /* double functions */
  194. double coDblGet(cco o);
  195. /* vector functions */
  196. long coVectorAdd(
  197. co o, cco p); // add object at the end of the list, returns -1 for error
  198. int coVectorAppendVector(co v, cco src); // append elements from src to vector v
  199. cco coVectorGet(cco o,
  200. long idx); // return object at specific position from the vector
  201. void coVectorSet(co v, long i, cco e); // replace an element within the vector
  202. void coVectorErase(
  203. co v, long i); // delete and remove element at the specified position
  204. void coVectorClear(co o); // first if flags are not CO_NONE delete all elements
  205. // and second clear the array to size 0
  206. int coVectorEmpty(cco o); // return 1 if the vector is empty, return 0 otherwise
  207. long coVectorSize(cco o); // return the number of elements in the vector
  208. typedef int (*coVectorForEachCB)(cco o, long idx, cco element, void *data);
  209. int coVectorForEach(cco o, coVectorForEachCB cb, void *data);
  210. typedef co (*coVectorMapCB)(cco o, long idx, cco element, void *data);
  211. co coVectorMap(cco o, coVectorMapCB cb, void *data);
  212. long coVectorPredecessorBinarySearch(
  213. cco v,
  214. const char
  215. *search_key); // assumes structre as returned by "coNewVectorByMap()"
  216. /* map functions */
  217. // int coMapAdd(co o, const char *key, cco value); // insert object into the
  218. // map, returns 0 for memory error
  219. const char *
  220. coMapAdd(co o, const char *key,
  221. cco value); // insert object into map, returns NULL for memory error,
  222. // otherwise the internal pointer to key
  223. // note: if key exists, then the internal pointer to the same key string is
  224. // returned, otherwise the key argument is returned
  225. cco coMapAddValueKey(
  226. co o, const char *key); // add a new entry to the map with key and also the
  227. // value beeing the same key, CO_FREE_VALS must be
  228. // enable for the map. The value object is returned.
  229. int coMapExists(cco o, const char *key); // return 1 if "key" exists in the map
  230. cco coMapGet(cco o, const char *key); // get object from map by key, returns
  231. // NULL if key doesn't exist in the map
  232. const char *
  233. coMapGetKey(cco o, const char *key); // returns the internal pointer to the key
  234. // string or NULL if the key doesn't exist
  235. void coMapErase(co o, const char *key); // removes object from the map
  236. void coMapClear(co o); // delete all elements and clear the array
  237. int coMapEmpty(cco o); // return 1 if the map is empty, return 0 otherwise
  238. long coMapSize(cco o); // O(n) !!
  239. typedef int (*coMapForEachCB)(cco o, long idx, const char *key, cco value,
  240. void *data);
  241. int coMapForEach(
  242. cco o, coMapForEachCB cb,
  243. void *data); // returns 0 as soon as the callback function returns 0
  244. /* https://stackoverflow.com/questions/30769383/finding-the-minimum-and-maximum-height-in-a-avl-tree-given-a-number-of-nodes
  245. */
  246. /* --> floor(1.44*log2(n+2)-.328), with n=2^31 (long), this is 45 */
  247. #define CO_AVL_STACK_MAX_DEPTH 45
  248. struct coMapIteratorStruct {
  249. struct co_avl_node_struct *node[CO_AVL_STACK_MAX_DEPTH];
  250. struct co_avl_node_struct *current_node;
  251. int depth;
  252. };
  253. typedef struct coMapIteratorStruct coMapIterator;
  254. #define coMapLoopKey(iter) ((iter)->current_node->key)
  255. #define coMapLoopValue(iter) ((cco)((iter)->current_node->value))
  256. int coMapLoopFirst(coMapIterator *iter, cco o);
  257. int coMapLoopNext(coMapIterator *iter);
  258. /*
  259. coMapIterator iter;
  260. if ( coMapLoopFirst(&iter, o) )
  261. {
  262. do {
  263. coMapLoopKey(&iter); // return the key of the current key/value
  264. pair (const char *)
  265. coMapLoopValue(&iter); // return the value of the current
  266. key/value pair (cco) } while( coMapLoopNext(&iter) );
  267. }
  268. */
  269. /* file / string reader interface */
  270. #define BOM_NONE 0
  271. #define BOM_UTF8 1
  272. #define BOM_UTF16BE 2
  273. #define BOM_UTF16LE 3
  274. #define BOM_UTF32BE 4
  275. #define BOM_UTF32LE 5
  276. typedef struct co_reader_struct *coReader;
  277. typedef void (*coReaderNextFn)(coReader r);
  278. struct co_reader_struct {
  279. int curr;
  280. int bom; // see constants above
  281. const char *reader_string;
  282. FILE *fp;
  283. coReaderNextFn next_cb;
  284. unsigned char stack_memory[16]; // this is normal last in first out stack for UTF-8 sequence
  285. int stack_pos; // stack size, 0 means, stack is empty
  286. #ifdef CO_USE_ZLIB
  287. #define CHUNK (16 * 1024)
  288. unsigned have;
  289. unsigned pos;
  290. z_stream strm;
  291. unsigned char in[CHUNK];
  292. unsigned char out[CHUNK];
  293. #endif /* CO_USE_ZLIB */
  294. };
  295. int coReaderInitByString(coReader reader, const char *s);
  296. int coReaderInitByFP(coReader reader, FILE *fp);
  297. void coReaderErr(coReader r, const char *msg);
  298. #define coReaderNext(r) ((r)->next_cb(r))
  299. #define coReaderCurr(r) ((r)->curr)
  300. #define coReaderSkipWhiteSpace(r) \
  301. for (;;) { \
  302. if (coReaderCurr(r) < 0) \
  303. break; \
  304. if (coReaderCurr(r) > ' ') \
  305. break; \
  306. coReaderNext(r); \
  307. }
  308. /* functions from co_extra.c */
  309. co coReadA2LByString(const char *json);
  310. co coReadA2LByFP(FILE *fp);
  311. co coReadS19ByFP(FILE *fp); // returns map, key=8digit addres, value=mem block
  312. co coReadHEXByFP(FILE *fp); // returns map, key=8digit addres, value=mem block
  313. co coReadElfMemoryByFP(FILE *fp); // returns map, key=8digit addres, value=mem
  314. // block, .gz is NOT supported
  315. co coReadCSVByFP(
  316. FILE *fp, int separator); // returns vector, separator should be ',' or ';'
  317. co coReadCSVByFPWithPool(
  318. FILE *fp, int separator,
  319. co pool); // same as coReadCSVByFP, but will allocate all strings in the
  320. // pool, which must be a map with CO_FREE_VALS flag, pool can be
  321. // NULL
  322. co coGetCSVRow(struct co_reader_struct *r, int separator);
  323. #endif /* CO_INCLUDE */