core.h 5.6 KB

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