core.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #ifndef _LSUP_CORE_H
  2. #define _LSUP_CORE_H
  3. #include <ctype.h>
  4. #include <dirent.h>
  5. #include <errno.h>
  6. #include <inttypes.h>
  7. #include <limits.h>
  8. #include <stdbool.h>
  9. #include <stddef.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <sys/stat.h>
  14. #include <uuid/uuid.h>
  15. #ifdef DEBUG
  16. #define DEBUG_TEST 1
  17. #else
  18. #define DEBUG_TEST 0
  19. #endif
  20. #define STR "%s"
  21. #define TRACE(fmt, ...) \
  22. do {\
  23. if (DEBUG_TEST) \
  24. fprintf(stderr, "%s:%d:%s(): " fmt "\n", \
  25. __FILE__, __LINE__, __func__, __VA_ARGS__); \
  26. } while (0)
  27. #define LIKELY(x) __builtin_expect(!!(x), true)
  28. #define UNLIKELY(x) __builtin_expect(!!(x), false)
  29. // TODO Cross-platform ramdisk path.
  30. #define TMPDIR "/tmp"
  31. #define KLEN sizeof(LSUP_Key)
  32. #define DBL_KLEN sizeof(LSUP_DoubleKey)
  33. #define TRP_KLEN sizeof(LSUP_TripleKey)
  34. #define QUAD_KLEN sizeof(LSUP_QuadKey)
  35. # define UUIDSTR_SIZE 37
  36. // Handy flags operations.
  37. #define SET_FLAG(n, f) ((n) |= (f))
  38. #define CLR_FLAG(n, f) ((n) &= ~(f))
  39. #define TGL_FLAG(n, f) ((n) ^= (f))
  40. #define CHK_FLAG(n, f) ((n) & (f))
  41. /* * * RETURN CODES * * */
  42. /**
  43. * 0 is success, positive integers (>88800) are warnings, and negative integers
  44. * (<-88800) are errors.
  45. */
  46. typedef enum {
  47. LSUP_OK = 0,
  48. LSUP_NOACTION = 88801,
  49. LSUP_NORESULT = 88802,
  50. LSUP_END = 88803,
  51. LSUP_ERROR = -88801,
  52. LSUP_PARSE_ERR = -88802,
  53. LSUP_VALUE_ERR = -88803,
  54. LSUP_TXN_ERR = -88804,
  55. LSUP_DB_ERR = -88805,
  56. LSUP_NOT_IMPL_ERR = -88806,
  57. LSUP_IO_ERR = -88807,
  58. LSUP_MEM_ERR = -88808,
  59. } LSUP_rc;
  60. typedef enum {
  61. LSUP_BOOL_UNION,
  62. LSUP_BOOL_SUBTRACTION,
  63. LSUP_BOOL_INTERSECTION,
  64. LSUP_BOOL_XOR,
  65. } LSUP_bool_op;
  66. typedef size_t LSUP_Key;
  67. typedef LSUP_Key LSUP_DoubleKey[2];
  68. typedef LSUP_Key LSUP_TripleKey[3];
  69. typedef LSUP_Key LSUP_QuadKey[4];
  70. typedef char uuid_str_t[UUIDSTR_SIZE];
  71. // Yes, a textbook mistake; but writing min and max for all int types is crazy.
  72. #define min(x, y) (x) < (y) ? (x) : (y)
  73. #define max(x, y) (x) > (y) ? (x) : (y)
  74. /** @brief Make recursive directories.
  75. *
  76. * from https://gist.github.com/JonathonReinhart/8c0d90191c38af2dcadb102c4e202950
  77. */
  78. LSUP_rc mkdir_p(const char *path, mode_t mode);
  79. /** @brief Remove a directory recursively, as in Unix "rm -r".
  80. *
  81. * @param path[in] Path of directory to remove.
  82. */
  83. LSUP_rc
  84. rm_r (const char *path);
  85. /** @brief Convert a Unicode (UTF-8) code point to 4-byte sequence.
  86. */
  87. /*
  88. inline uint16_t utf8_to_bytes (uint16_t c) {
  89. unsigned char b[4] = {0};
  90. if (c<0x80) *b++=c;
  91. else if (c<0x800) *b++=192+c/64, *b++=128+c%64;
  92. else if (c-0xd800u<0x800) goto error;
  93. else if (c<0x10000) *b++=224+c/4096, *b++=128+c/64%64, *b++=128+c%64;
  94. else if (c<0x110000)
  95. *b++=240+c/262144, *b++=128+c/4096%64, *b++=128+c/64%64, *b++=128+c%64;
  96. else return NULL;
  97. return (uint16_t)b;
  98. }
  99. */
  100. /**
  101. * Encode a code point using UTF-8
  102. *
  103. * @author Ondřej Hruška <ondra@ondrovo.com>
  104. * @license MIT
  105. * https://gist.github.com/MightyPork/52eda3e5677b4b03524e40c9f0ab1da5
  106. *
  107. * @param out - output buffer (min 5 characters), will be 0-terminated
  108. * @param utf - code point 0-0x10FFFF
  109. * @return number of bytes on success, 0 on failure (also produces U+FFFD, which uses 3 bytes)
  110. */
  111. inline int utf8_encode(const uint32_t utf, unsigned char *out)
  112. {
  113. if (utf <= 0x7F) {
  114. // Plain ASCII
  115. out[0] = (char) utf;
  116. out[1] = 0;
  117. return 1;
  118. }
  119. else if (utf <= 0x07FF) {
  120. // 2-byte unicode
  121. out[0] = (char) (((utf >> 6) & 0x1F) | 0xC0);
  122. out[1] = (char) (((utf >> 0) & 0x3F) | 0x80);
  123. out[2] = 0;
  124. return 2;
  125. }
  126. else if (utf <= 0xFFFF) {
  127. // 3-byte unicode
  128. out[0] = (char) (((utf >> 12) & 0x0F) | 0xE0);
  129. out[1] = (char) (((utf >> 6) & 0x3F) | 0x80);
  130. out[2] = (char) (((utf >> 0) & 0x3F) | 0x80);
  131. out[3] = 0;
  132. return 3;
  133. }
  134. else if (utf <= 0x10FFFF) {
  135. // 4-byte unicode
  136. out[0] = (char) (((utf >> 18) & 0x07) | 0xF0);
  137. out[1] = (char) (((utf >> 12) & 0x3F) | 0x80);
  138. out[2] = (char) (((utf >> 6) & 0x3F) | 0x80);
  139. out[3] = (char) (((utf >> 0) & 0x3F) | 0x80);
  140. out[4] = 0;
  141. return 4;
  142. }
  143. else {
  144. // error - use replacement character
  145. out[0] = (char) 0xEF;
  146. out[1] = (char) 0xBF;
  147. out[2] = (char) 0xBD;
  148. out[3] = 0;
  149. return 0;
  150. }
  151. }
  152. // Error handling via goto.
  153. #define CHECK(exp, rc, marker) (rc) = (exp); if ((rc) != LSUP_OK) goto marker
  154. // Jump if rc is negative (skip warnings).
  155. #define PCHECK(exp, rc, marker) (rc) = (exp); if ((rc) < LSUP_OK) goto marker
  156. // Return rc if it is of LSUP_rc type and is negative (=error)
  157. #define RCCK(exp) LSUP_rc _rc = (exp); if (_rc < 0) return _rc
  158. // Return NULL if it is of LSUP_rc type and is negative (=error)
  159. #define RCNL(exp) if((exp) < 0) return NULL
  160. #define MALLOC_GUARD(var, rc) do { \
  161. (var) = malloc (sizeof *(var)); \
  162. if (UNLIKELY (var == NULL)) return (rc); \
  163. } while (0);
  164. #define CALLOC_GUARD(var, rc) do { \
  165. (var) = calloc (1, sizeof *(var)); \
  166. if (UNLIKELY (var == NULL)) return (rc); \
  167. } while (0);
  168. /*
  169. #define MALLOC_GUARD_ME(var) MALLOC_GUARD((var), LSUP_MEM_ERR) \
  170. #define CALLOC_GUARD_ME(var) CALLOC_GUARD((var), LSUP_MEM_ERR) \
  171. #define MALLOC_GUARD_NL(var) MALLOC_GUARD((var), NULL) \
  172. #define CALLOC_GUARD_NL(var) CALLOC_GUARD((var), NULL) \
  173. */
  174. #endif