buffer.h 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #ifndef NETDATA_WEB_BUFFER_H
  3. #define NETDATA_WEB_BUFFER_H 1
  4. #include "../string/utf8.h"
  5. #include "../libnetdata.h"
  6. #define BUFFER_JSON_MAX_DEPTH 32 // max is 255
  7. extern const char hex_digits[16];
  8. extern const char base64_digits[64];
  9. extern unsigned char hex_value_from_ascii[256];
  10. extern unsigned char base64_value_from_ascii[256];
  11. typedef enum __attribute__ ((__packed__)) {
  12. BUFFER_JSON_EMPTY = 0,
  13. BUFFER_JSON_OBJECT,
  14. BUFFER_JSON_ARRAY,
  15. } BUFFER_JSON_NODE_TYPE;
  16. typedef struct web_buffer_json_node {
  17. BUFFER_JSON_NODE_TYPE type;
  18. uint32_t count:24;
  19. } BUFFER_JSON_NODE;
  20. #define BUFFER_QUOTE_MAX_SIZE 7
  21. typedef enum __attribute__ ((__packed__)) {
  22. WB_CONTENT_CACHEABLE = (1 << 0),
  23. WB_CONTENT_NO_CACHEABLE = (1 << 1),
  24. } BUFFER_OPTIONS;
  25. typedef enum __attribute__ ((__packed__)) {
  26. BUFFER_JSON_OPTIONS_DEFAULT = 0,
  27. BUFFER_JSON_OPTIONS_MINIFY = (1 << 0),
  28. BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS = (1 << 1),
  29. BUFFER_JSON_OPTIONS_NON_ANONYMOUS = (1 << 2),
  30. } BUFFER_JSON_OPTIONS;
  31. typedef struct web_buffer {
  32. size_t size; // allocation size of buffer, in bytes
  33. size_t len; // current data length in buffer, in bytes
  34. char *buffer; // the buffer itself
  35. HTTP_CONTENT_TYPE content_type; // the content type of the data in the buffer
  36. BUFFER_OPTIONS options; // options related to the content
  37. time_t date; // the timestamp this content has been generated
  38. time_t expires; // the timestamp this content expires
  39. size_t *statistics;
  40. struct {
  41. char key_quote[BUFFER_QUOTE_MAX_SIZE + 1];
  42. char value_quote[BUFFER_QUOTE_MAX_SIZE + 1];
  43. int8_t depth;
  44. BUFFER_JSON_OPTIONS options;
  45. BUFFER_JSON_NODE stack[BUFFER_JSON_MAX_DEPTH];
  46. } json;
  47. } BUFFER;
  48. #define CLEAN_BUFFER _cleanup_(buffer_freep) BUFFER
  49. #define buffer_cacheable(wb) do { (wb)->options |= WB_CONTENT_CACHEABLE; if((wb)->options & WB_CONTENT_NO_CACHEABLE) (wb)->options &= ~WB_CONTENT_NO_CACHEABLE; } while(0)
  50. #define buffer_no_cacheable(wb) do { (wb)->options |= WB_CONTENT_NO_CACHEABLE; if((wb)->options & WB_CONTENT_CACHEABLE) (wb)->options &= ~WB_CONTENT_CACHEABLE; (wb)->expires = 0; } while(0)
  51. #define buffer_strlen(wb) ((wb)->len)
  52. #define BUFFER_OVERFLOW_EOF "EOF"
  53. #ifdef NETDATA_INTERNAL_CHECKS
  54. #define buffer_overflow_check(b) _buffer_overflow_check(b)
  55. #else
  56. #define buffer_overflow_check(b)
  57. #endif
  58. static inline void _buffer_overflow_check(BUFFER *b __maybe_unused) {
  59. assert(b->len <= b->size &&
  60. "BUFFER: length is above buffer size.");
  61. assert(!(b->buffer && (b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF) != 0)) &&
  62. "BUFFER: detected overflow.");
  63. }
  64. static inline void buffer_flush(BUFFER *wb) {
  65. wb->len = 0;
  66. wb->json.depth = 0;
  67. wb->json.stack[0].type = BUFFER_JSON_EMPTY;
  68. wb->json.stack[0].count = 0;
  69. if(wb->buffer)
  70. wb->buffer[0] = '\0';
  71. }
  72. void buffer_reset(BUFFER *wb);
  73. void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
  74. void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
  75. BUFFER *buffer_create(size_t size, size_t *statistics);
  76. void buffer_free(BUFFER *b);
  77. void buffer_increase(BUFFER *b, size_t free_size_required);
  78. static inline void buffer_freep(BUFFER **bp) {
  79. if(bp) buffer_free(*bp);
  80. }
  81. void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...) PRINTFLIKE(3, 4);
  82. void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args);
  83. void buffer_sprintf(BUFFER *wb, const char *fmt, ...) PRINTFLIKE(2,3);
  84. void buffer_strcat_htmlescape(BUFFER *wb, const char *txt);
  85. void buffer_char_replace(BUFFER *wb, char from, char to);
  86. void buffer_print_sn_flags(BUFFER *wb, SN_FLAGS flags, bool send_anomaly_bit);
  87. static inline void buffer_need_bytes(BUFFER *buffer, size_t needed_free_size) {
  88. if(unlikely(buffer->len + needed_free_size >= buffer->size))
  89. buffer_increase(buffer, needed_free_size + 1);
  90. }
  91. void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth,
  92. bool add_anonymous_object, BUFFER_JSON_OPTIONS options);
  93. void buffer_json_finalize(BUFFER *wb);
  94. static const char *buffer_tostring(BUFFER *wb)
  95. {
  96. if(unlikely(!wb))
  97. return NULL;
  98. buffer_need_bytes(wb, 1);
  99. wb->buffer[wb->len] = '\0';
  100. buffer_overflow_check(wb);
  101. return(wb->buffer);
  102. }
  103. static inline void _buffer_json_depth_push(BUFFER *wb, BUFFER_JSON_NODE_TYPE type) {
  104. #ifdef NETDATA_INTERNAL_CHECKS
  105. assert(wb->json.depth <= BUFFER_JSON_MAX_DEPTH && "BUFFER JSON: max nesting reached");
  106. #endif
  107. wb->json.depth++;
  108. wb->json.stack[wb->json.depth].count = 0;
  109. wb->json.stack[wb->json.depth].type = type;
  110. }
  111. static inline void _buffer_json_depth_pop(BUFFER *wb) {
  112. wb->json.depth--;
  113. }
  114. static inline void buffer_fast_charcat(BUFFER *wb, const char c) {
  115. buffer_need_bytes(wb, 2);
  116. *(&wb->buffer[wb->len]) = c;
  117. wb->len += 1;
  118. wb->buffer[wb->len] = '\0';
  119. buffer_overflow_check(wb);
  120. }
  121. static inline void buffer_fast_rawcat(BUFFER *wb, const char *txt, size_t len) {
  122. if(unlikely(!txt || !*txt || !len)) return;
  123. buffer_need_bytes(wb, len + 1);
  124. const char *t = txt;
  125. const char *e = &txt[len];
  126. char *d = &wb->buffer[wb->len];
  127. while(t != e)
  128. *d++ = *t++;
  129. wb->len += len;
  130. wb->buffer[wb->len] = '\0';
  131. buffer_overflow_check(wb);
  132. }
  133. static inline void buffer_putc(BUFFER *wb, char c) {
  134. buffer_need_bytes(wb, 2);
  135. wb->buffer[wb->len++] = c;
  136. wb->buffer[wb->len] = '\0';
  137. buffer_overflow_check(wb);
  138. }
  139. static inline void buffer_fast_strcat(BUFFER *wb, const char *txt, size_t len) {
  140. if(unlikely(!txt || !*txt || !len)) return;
  141. buffer_need_bytes(wb, len + 1);
  142. const char *t = txt;
  143. const char *e = &txt[len];
  144. char *d = &wb->buffer[wb->len];
  145. while(t != e
  146. #ifdef NETDATA_INTERNAL_CHECKS
  147. && *t
  148. #endif
  149. )
  150. *d++ = *t++;
  151. #ifdef NETDATA_INTERNAL_CHECKS
  152. assert(!(t != e && !*t) && "BUFFER: source string is shorter than the length given.");
  153. #endif
  154. wb->len += len;
  155. wb->buffer[wb->len] = '\0';
  156. buffer_overflow_check(wb);
  157. }
  158. static inline void buffer_strcat(BUFFER *wb, const char *txt) {
  159. if(unlikely(!txt || !*txt)) return;
  160. const char *t = txt;
  161. while(*t) {
  162. buffer_need_bytes(wb, 100);
  163. char *s = &wb->buffer[wb->len];
  164. char *d = s;
  165. const char *e = &wb->buffer[wb->size];
  166. while(*t && d < e)
  167. *d++ = *t++;
  168. wb->len += d - s;
  169. }
  170. buffer_need_bytes(wb, 1);
  171. wb->buffer[wb->len] = '\0';
  172. buffer_overflow_check(wb);
  173. }
  174. static inline void buffer_contents_replace(BUFFER *wb, const char *txt, size_t len) {
  175. wb->len = 0;
  176. buffer_need_bytes(wb, len + 1);
  177. memcpy(wb->buffer, txt, len);
  178. wb->len = len;
  179. wb->buffer[wb->len] = '\0';
  180. buffer_overflow_check(wb);
  181. }
  182. static inline void buffer_strncat(BUFFER *wb, const char *txt, size_t len) {
  183. if(unlikely(!txt || !*txt)) return;
  184. buffer_need_bytes(wb, len + 1);
  185. memcpy(&wb->buffer[wb->len], txt, len);
  186. wb->len += len;
  187. wb->buffer[wb->len] = '\0';
  188. buffer_overflow_check(wb);
  189. }
  190. static inline void buffer_memcat(BUFFER *wb, const void *mem, size_t bytes) {
  191. if(unlikely(!mem)) return;
  192. buffer_need_bytes(wb, bytes + 1);
  193. memcpy(&wb->buffer[wb->len], mem, bytes);
  194. wb->len += bytes;
  195. wb->buffer[wb->len] = '\0';
  196. buffer_overflow_check(wb);
  197. }
  198. static inline void buffer_json_strcat(BUFFER *wb, const char *txt)
  199. {
  200. if(unlikely(!txt || !*txt)) return;
  201. const unsigned char *t = (const unsigned char *)txt;
  202. while(*t) {
  203. buffer_need_bytes(wb, 110);
  204. unsigned char *s = (unsigned char *)&wb->buffer[wb->len];
  205. unsigned char *d = s;
  206. const unsigned char *e = (unsigned char *)&wb->buffer[wb->size - 10]; // make room for the max escape sequence
  207. while(*t && d < e) {
  208. #ifdef BUFFER_JSON_ESCAPE_UTF
  209. if(unlikely(IS_UTF8_STARTBYTE(*t) && IS_UTF8_BYTE(t[1]))) {
  210. // UTF-8 multi-byte encoded character
  211. // find how big this character is (2-4 bytes)
  212. size_t utf_character_size = 2;
  213. while(utf_character_size < 4 && t[utf_character_size] && IS_UTF8_BYTE(t[utf_character_size]) && !IS_UTF8_STARTBYTE(t[utf_character_size]))
  214. utf_character_size++;
  215. uint32_t code_point = 0;
  216. for (size_t i = 0; i < utf_character_size; i++) {
  217. code_point <<= 6;
  218. code_point |= (t[i] & 0x3F);
  219. }
  220. t += utf_character_size;
  221. // encode as \u escape sequence
  222. *d++ = '\\';
  223. *d++ = 'u';
  224. *d++ = hex_digits[(code_point >> 12) & 0xf];
  225. *d++ = hex_digits[(code_point >> 8) & 0xf];
  226. *d++ = hex_digits[(code_point >> 4) & 0xf];
  227. *d++ = hex_digits[code_point & 0xf];
  228. }
  229. else
  230. #endif
  231. if(unlikely(*t < ' ')) {
  232. uint32_t v = *t++;
  233. *d++ = '\\';
  234. *d++ = 'u';
  235. *d++ = hex_digits[(v >> 12) & 0xf];
  236. *d++ = hex_digits[(v >> 8) & 0xf];
  237. *d++ = hex_digits[(v >> 4) & 0xf];
  238. *d++ = hex_digits[v & 0xf];
  239. }
  240. else {
  241. if (unlikely(*t == '\\' || *t == '\"'))
  242. *d++ = '\\';
  243. *d++ = *t++;
  244. }
  245. }
  246. wb->len += d - s;
  247. }
  248. buffer_need_bytes(wb, 1);
  249. wb->buffer[wb->len] = '\0';
  250. buffer_overflow_check(wb);
  251. }
  252. static inline void buffer_json_quoted_strcat(BUFFER *wb, const char *txt) {
  253. if(unlikely(!txt || !*txt)) return;
  254. if(*txt == '"')
  255. txt++;
  256. const char *t = txt;
  257. while(*t) {
  258. buffer_need_bytes(wb, 100);
  259. char *s = &wb->buffer[wb->len];
  260. char *d = s;
  261. const char *e = &wb->buffer[wb->size - 1]; // remove 1 to make room for the escape character
  262. while(*t && d < e) {
  263. if(unlikely(*t == '"' && !t[1])) {
  264. t++;
  265. continue;
  266. }
  267. if(unlikely(*t == '\\' || *t == '"'))
  268. *d++ = '\\';
  269. *d++ = *t++;
  270. }
  271. wb->len += d - s;
  272. }
  273. buffer_need_bytes(wb, 1);
  274. wb->buffer[wb->len] = '\0';
  275. buffer_overflow_check(wb);
  276. }
  277. // This trick seems to give an 80% speed increase in 32bit systems
  278. // print_number_llu_r() will just print the digits up to the
  279. // point the remaining value fits in 32 bits, and then calls
  280. // print_number_lu_r() to print the rest with 32 bit arithmetic.
  281. static inline char *print_uint32_reversed(char *dst, uint32_t value) {
  282. char *d = dst;
  283. do *d++ = (char)('0' + (value % 10)); while((value /= 10));
  284. return d;
  285. }
  286. static inline char *print_uint64_reversed(char *dst, uint64_t value) {
  287. #ifdef ENV32BIT
  288. if(value <= (uint64_t)0xffffffff)
  289. return print_uint32_reversed(dst, value);
  290. char *d = dst;
  291. do *d++ = (char)('0' + (value % 10)); while((value /= 10) && value > (uint64_t)0xffffffff);
  292. if(value) return print_uint32_reversed(d, value);
  293. return d;
  294. #else
  295. char *d = dst;
  296. do *d++ = (char)('0' + (value % 10)); while((value /= 10));
  297. return d;
  298. #endif
  299. }
  300. static inline char *print_uint32_hex_reversed(char *dst, uint32_t value) {
  301. static const char *digits = "0123456789ABCDEF";
  302. char *d = dst;
  303. do *d++ = digits[value & 0xf]; while((value >>= 4));
  304. return d;
  305. }
  306. static inline char *print_uint64_hex_reversed(char *dst, uint64_t value) {
  307. #ifdef ENV32BIT
  308. if(value <= (uint64_t)0xffffffff)
  309. return print_uint32_hex_reversed(dst, value);
  310. char *d = dst;
  311. do *d++ = hex_digits[value & 0xf]; while((value >>= 4) && value > (uint64_t)0xffffffff);
  312. if(value) return print_uint32_hex_reversed(d, value);
  313. return d;
  314. #else
  315. char *d = dst;
  316. do *d++ = hex_digits[value & 0xf]; while((value >>= 4));
  317. return d;
  318. #endif
  319. }
  320. static inline char *print_uint64_base64_reversed(char *dst, uint64_t value) {
  321. char *d = dst;
  322. do *d++ = base64_digits[value & 63]; while ((value >>= 6));
  323. return d;
  324. }
  325. static inline void char_array_reverse(char *from, char *to) {
  326. // from and to are inclusive
  327. char *begin = from, *end = to, aux;
  328. while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
  329. }
  330. static inline int print_netdata_double(char *dst, NETDATA_DOUBLE value) {
  331. char *s = dst;
  332. if(unlikely(value < 0)) {
  333. *s++ = '-';
  334. value = fabsndd(value);
  335. }
  336. uint64_t fractional_precision = 10000000ULL; // fractional part 7 digits
  337. int fractional_wanted_digits = 7;
  338. int exponent = 0;
  339. if(unlikely(value >= (NETDATA_DOUBLE)(UINT64_MAX / 10))) {
  340. // the number is too big to print using 64bit numbers
  341. // so, let's convert it to exponential notation
  342. exponent = (int)(floorndd(log10ndd(value)));
  343. value /= powndd(10, exponent);
  344. // the max precision we can support is 18 digits
  345. // (UINT64_MAX is 20, but the first is 1)
  346. fractional_precision = 1000000000000000000ULL; // fractional part 18 digits
  347. fractional_wanted_digits = 18;
  348. }
  349. char *d = s;
  350. NETDATA_DOUBLE integral_d, fractional_d;
  351. fractional_d = modfndd(value, &integral_d);
  352. // get the integral and the fractional parts as 64-bit integers
  353. uint64_t integral = (uint64_t)integral_d;
  354. uint64_t fractional = (uint64_t)llrintndd(fractional_d * (NETDATA_DOUBLE)fractional_precision);
  355. if(unlikely(fractional >= fractional_precision)) {
  356. integral++;
  357. fractional -= fractional_precision;
  358. }
  359. // convert the integral part to string (reversed)
  360. d = print_uint64_reversed(d, integral);
  361. char_array_reverse(s, d - 1); // copy reversed the integral string
  362. if(likely(fractional != 0)) {
  363. *d++ = '.'; // add the dot
  364. // convert the fractional part to string (reversed)
  365. d = print_uint64_reversed(s = d, fractional);
  366. while(d - s < fractional_wanted_digits) *d++ = '0'; // prepend zeros to reach precision
  367. char_array_reverse(s, d - 1); // copy reversed the fractional string
  368. // remove trailing zeros from the fractional part
  369. while(*(d - 1) == '0') d--;
  370. }
  371. if(unlikely(exponent != 0)) {
  372. *d++ = 'e';
  373. *d++ = '+';
  374. d = print_uint32_reversed(s = d, exponent);
  375. char_array_reverse(s, d - 1);
  376. }
  377. *d = '\0';
  378. return (int)(d - dst);
  379. }
  380. static inline void buffer_print_uint64(BUFFER *wb, uint64_t value) {
  381. buffer_need_bytes(wb, 50);
  382. char *s = &wb->buffer[wb->len];
  383. char *d = print_uint64_reversed(s, value);
  384. char_array_reverse(s, d - 1);
  385. *d = '\0';
  386. wb->len += d - s;
  387. buffer_overflow_check(wb);
  388. }
  389. static inline void buffer_print_int64(BUFFER *wb, int64_t value) {
  390. buffer_need_bytes(wb, 50);
  391. if(value < 0) {
  392. buffer_fast_strcat(wb, "-", 1);
  393. value = -value;
  394. }
  395. buffer_print_uint64(wb, (uint64_t)value);
  396. buffer_overflow_check(wb);
  397. }
  398. static inline void buffer_print_uint64_hex(BUFFER *wb, uint64_t value) {
  399. buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1);
  400. buffer_fast_strcat(wb, HEX_PREFIX, sizeof(HEX_PREFIX) - 1);
  401. char *s = &wb->buffer[wb->len];
  402. char *d = print_uint64_hex_reversed(s, value);
  403. char_array_reverse(s, d - 1);
  404. *d = '\0';
  405. wb->len += d - s;
  406. buffer_overflow_check(wb);
  407. }
  408. static inline void buffer_print_uint64_base64(BUFFER *wb, uint64_t value) {
  409. buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1);
  410. buffer_fast_strcat(wb, IEEE754_UINT64_B64_PREFIX, sizeof(IEEE754_UINT64_B64_PREFIX) - 1);
  411. char *s = &wb->buffer[wb->len];
  412. char *d = print_uint64_base64_reversed(s, value);
  413. char_array_reverse(s, d - 1);
  414. *d = '\0';
  415. wb->len += d - s;
  416. buffer_overflow_check(wb);
  417. }
  418. static inline void buffer_print_int64_hex(BUFFER *wb, int64_t value) {
  419. buffer_need_bytes(wb, 2);
  420. if(value < 0) {
  421. buffer_fast_strcat(wb, "-", 1);
  422. value = -value;
  423. }
  424. buffer_print_uint64_hex(wb, (uint64_t)value);
  425. buffer_overflow_check(wb);
  426. }
  427. static inline void buffer_print_int64_base64(BUFFER *wb, int64_t value) {
  428. buffer_need_bytes(wb, 2);
  429. if(value < 0) {
  430. buffer_fast_strcat(wb, "-", 1);
  431. value = -value;
  432. }
  433. buffer_print_uint64_base64(wb, (uint64_t)value);
  434. buffer_overflow_check(wb);
  435. }
  436. static inline void buffer_print_netdata_double(BUFFER *wb, NETDATA_DOUBLE value) {
  437. buffer_need_bytes(wb, 512 + 2);
  438. if(isnan(value) || isinf(value)) {
  439. buffer_fast_strcat(wb, "null", 4);
  440. return;
  441. }
  442. else
  443. wb->len += print_netdata_double(&wb->buffer[wb->len], value);
  444. // terminate it
  445. buffer_need_bytes(wb, 1);
  446. wb->buffer[wb->len] = '\0';
  447. buffer_overflow_check(wb);
  448. }
  449. static inline void buffer_print_netdata_double_hex(BUFFER *wb, NETDATA_DOUBLE value) {
  450. buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1 + 1);
  451. uint64_t *ptr = (uint64_t *) (&value);
  452. buffer_fast_strcat(wb, IEEE754_DOUBLE_HEX_PREFIX, sizeof(IEEE754_DOUBLE_HEX_PREFIX) - 1);
  453. char *s = &wb->buffer[wb->len];
  454. char *d = print_uint64_hex_reversed(s, *ptr);
  455. char_array_reverse(s, d - 1);
  456. *d = '\0';
  457. wb->len += d - s;
  458. buffer_overflow_check(wb);
  459. }
  460. static inline void buffer_print_netdata_double_base64(BUFFER *wb, NETDATA_DOUBLE value) {
  461. buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1 + 1);
  462. uint64_t *ptr = (uint64_t *) (&value);
  463. buffer_fast_strcat(wb, IEEE754_DOUBLE_B64_PREFIX, sizeof(IEEE754_DOUBLE_B64_PREFIX) - 1);
  464. char *s = &wb->buffer[wb->len];
  465. char *d = print_uint64_base64_reversed(s, *ptr);
  466. char_array_reverse(s, d - 1);
  467. *d = '\0';
  468. wb->len += d - s;
  469. buffer_overflow_check(wb);
  470. }
  471. typedef enum {
  472. NUMBER_ENCODING_DECIMAL,
  473. NUMBER_ENCODING_HEX,
  474. NUMBER_ENCODING_BASE64,
  475. } NUMBER_ENCODING;
  476. static inline void buffer_print_int64_encoded(BUFFER *wb, NUMBER_ENCODING encoding, int64_t value) {
  477. if(encoding == NUMBER_ENCODING_BASE64)
  478. return buffer_print_int64_base64(wb, value);
  479. if(encoding == NUMBER_ENCODING_HEX)
  480. return buffer_print_int64_hex(wb, value);
  481. return buffer_print_int64(wb, value);
  482. }
  483. static inline void buffer_print_uint64_encoded(BUFFER *wb, NUMBER_ENCODING encoding, uint64_t value) {
  484. if(encoding == NUMBER_ENCODING_BASE64)
  485. return buffer_print_uint64_base64(wb, value);
  486. if(encoding == NUMBER_ENCODING_HEX)
  487. return buffer_print_uint64_hex(wb, value);
  488. return buffer_print_uint64(wb, value);
  489. }
  490. static inline void buffer_print_netdata_double_encoded(BUFFER *wb, NUMBER_ENCODING encoding, NETDATA_DOUBLE value) {
  491. if(encoding == NUMBER_ENCODING_BASE64)
  492. return buffer_print_netdata_double_base64(wb, value);
  493. if(encoding == NUMBER_ENCODING_HEX)
  494. return buffer_print_netdata_double_hex(wb, value);
  495. return buffer_print_netdata_double(wb, value);
  496. }
  497. static inline void buffer_print_spaces(BUFFER *wb, size_t spaces) {
  498. buffer_need_bytes(wb, spaces * 4 + 1);
  499. char *d = &wb->buffer[wb->len];
  500. for(size_t i = 0; i < spaces; i++) {
  501. *d++ = ' ';
  502. *d++ = ' ';
  503. *d++ = ' ';
  504. *d++ = ' ';
  505. }
  506. *d = '\0';
  507. wb->len += spaces * 4;
  508. buffer_overflow_check(wb);
  509. }
  510. static inline void buffer_print_json_comma(BUFFER *wb) {
  511. if(wb->json.stack[wb->json.depth].count)
  512. buffer_fast_strcat(wb, ",", 1);
  513. }
  514. static inline void buffer_print_json_comma_newline_spacing(BUFFER *wb) {
  515. buffer_print_json_comma(wb);
  516. if((wb->json.options & BUFFER_JSON_OPTIONS_MINIFY) ||
  517. (wb->json.stack[wb->json.depth].type == BUFFER_JSON_ARRAY && !(wb->json.options & BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS)))
  518. return;
  519. buffer_fast_strcat(wb, "\n", 1);
  520. buffer_print_spaces(wb, wb->json.depth + 1);
  521. }
  522. static inline void buffer_print_json_key(BUFFER *wb, const char *key) {
  523. buffer_strcat(wb, wb->json.key_quote);
  524. buffer_json_strcat(wb, key);
  525. buffer_strcat(wb, wb->json.key_quote);
  526. }
  527. static inline void buffer_json_add_string_value(BUFFER *wb, const char *value) {
  528. if(value) {
  529. buffer_strcat(wb, wb->json.value_quote);
  530. buffer_json_strcat(wb, value);
  531. buffer_strcat(wb, wb->json.value_quote);
  532. }
  533. else
  534. buffer_fast_strcat(wb, "null", 4);
  535. }
  536. static inline void buffer_json_add_quoted_string_value(BUFFER *wb, const char *value) {
  537. if(value) {
  538. buffer_strcat(wb, wb->json.value_quote);
  539. buffer_json_quoted_strcat(wb, value);
  540. buffer_strcat(wb, wb->json.value_quote);
  541. }
  542. else
  543. buffer_fast_strcat(wb, "null", 4);
  544. }
  545. static inline void buffer_json_member_add_object(BUFFER *wb, const char *key) {
  546. buffer_print_json_comma_newline_spacing(wb);
  547. buffer_print_json_key(wb, key);
  548. buffer_fast_strcat(wb, ":{", 2);
  549. wb->json.stack[wb->json.depth].count++;
  550. _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
  551. }
  552. static inline void buffer_json_object_close(BUFFER *wb) {
  553. #ifdef NETDATA_INTERNAL_CHECKS
  554. assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
  555. assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_OBJECT && "BUFFER JSON: an object is not open to close it");
  556. #endif
  557. if(!(wb->json.options & BUFFER_JSON_OPTIONS_MINIFY)) {
  558. buffer_fast_strcat(wb, "\n", 1);
  559. buffer_print_spaces(wb, wb->json.depth);
  560. }
  561. buffer_fast_strcat(wb, "}", 1);
  562. _buffer_json_depth_pop(wb);
  563. }
  564. static inline void buffer_json_member_add_string(BUFFER *wb, const char *key, const char *value) {
  565. buffer_print_json_comma_newline_spacing(wb);
  566. buffer_print_json_key(wb, key);
  567. buffer_fast_strcat(wb, ":", 1);
  568. buffer_json_add_string_value(wb, value);
  569. wb->json.stack[wb->json.depth].count++;
  570. }
  571. static inline void buffer_json_member_add_string_or_omit(BUFFER *wb, const char *key, const char *value) {
  572. if(value && *value)
  573. buffer_json_member_add_string(wb, key, value);
  574. }
  575. static inline void buffer_json_member_add_string_or_empty(BUFFER *wb, const char *key, const char *value) {
  576. if(!value)
  577. value = "";
  578. buffer_json_member_add_string(wb, key, value);
  579. }
  580. static inline void buffer_json_member_add_quoted_string(BUFFER *wb, const char *key, const char *value) {
  581. buffer_print_json_comma_newline_spacing(wb);
  582. buffer_print_json_key(wb, key);
  583. buffer_fast_strcat(wb, ":", 1);
  584. if(!value || strcmp(value, "null") == 0)
  585. buffer_fast_strcat(wb, "null", 4);
  586. else
  587. buffer_json_add_quoted_string_value(wb, value);
  588. wb->json.stack[wb->json.depth].count++;
  589. }
  590. static inline void buffer_json_member_add_uuid(BUFFER *wb, const char *key, uuid_t *value) {
  591. buffer_print_json_comma_newline_spacing(wb);
  592. buffer_print_json_key(wb, key);
  593. buffer_fast_strcat(wb, ":", 1);
  594. if(value && !uuid_is_null(*value)) {
  595. char uuid[GUID_LEN + 1];
  596. uuid_unparse_lower(*value, uuid);
  597. buffer_json_add_string_value(wb, uuid);
  598. }
  599. else
  600. buffer_json_add_string_value(wb, NULL);
  601. wb->json.stack[wb->json.depth].count++;
  602. }
  603. static inline void buffer_json_member_add_boolean(BUFFER *wb, const char *key, bool value) {
  604. buffer_print_json_comma_newline_spacing(wb);
  605. buffer_print_json_key(wb, key);
  606. buffer_fast_strcat(wb, ":", 1);
  607. buffer_strcat(wb, value?"true":"false");
  608. wb->json.stack[wb->json.depth].count++;
  609. }
  610. static inline void buffer_json_member_add_array(BUFFER *wb, const char *key) {
  611. buffer_print_json_comma_newline_spacing(wb);
  612. if (key) {
  613. buffer_print_json_key(wb, key);
  614. buffer_fast_strcat(wb, ":[", 2);
  615. }
  616. else
  617. buffer_fast_strcat(wb, "[", 1);
  618. wb->json.stack[wb->json.depth].count++;
  619. _buffer_json_depth_push(wb, BUFFER_JSON_ARRAY);
  620. }
  621. static inline void buffer_json_add_array_item_array(BUFFER *wb) {
  622. if(!(wb->json.options & BUFFER_JSON_OPTIONS_MINIFY) && wb->json.stack[wb->json.depth].type == BUFFER_JSON_ARRAY) {
  623. // an array inside another array
  624. buffer_print_json_comma(wb);
  625. buffer_fast_strcat(wb, "\n", 1);
  626. buffer_print_spaces(wb, wb->json.depth + 1);
  627. }
  628. else
  629. buffer_print_json_comma_newline_spacing(wb);
  630. buffer_fast_strcat(wb, "[", 1);
  631. wb->json.stack[wb->json.depth].count++;
  632. _buffer_json_depth_push(wb, BUFFER_JSON_ARRAY);
  633. }
  634. static inline void buffer_json_add_array_item_string(BUFFER *wb, const char *value) {
  635. buffer_print_json_comma_newline_spacing(wb);
  636. buffer_json_add_string_value(wb, value);
  637. wb->json.stack[wb->json.depth].count++;
  638. }
  639. static inline void buffer_json_add_array_item_uuid(BUFFER *wb, uuid_t *value) {
  640. if(value && !uuid_is_null(*value)) {
  641. char uuid[GUID_LEN + 1];
  642. uuid_unparse_lower(*value, uuid);
  643. buffer_json_add_array_item_string(wb, uuid);
  644. }
  645. else
  646. buffer_json_add_array_item_string(wb, NULL);
  647. }
  648. static inline void buffer_json_add_array_item_uuid_compact(BUFFER *wb, uuid_t *value) {
  649. if(value && !uuid_is_null(*value)) {
  650. char uuid[GUID_LEN + 1];
  651. uuid_unparse_lower_compact(*value, uuid);
  652. buffer_json_add_array_item_string(wb, uuid);
  653. }
  654. else
  655. buffer_json_add_array_item_string(wb, NULL);
  656. }
  657. static inline void buffer_json_add_array_item_double(BUFFER *wb, NETDATA_DOUBLE value) {
  658. buffer_print_json_comma_newline_spacing(wb);
  659. buffer_print_netdata_double(wb, value);
  660. wb->json.stack[wb->json.depth].count++;
  661. }
  662. static inline void buffer_json_add_array_item_int64(BUFFER *wb, int64_t value) {
  663. buffer_print_json_comma_newline_spacing(wb);
  664. buffer_print_int64(wb, value);
  665. wb->json.stack[wb->json.depth].count++;
  666. }
  667. static inline void buffer_json_add_array_item_uint64(BUFFER *wb, uint64_t value) {
  668. buffer_print_json_comma_newline_spacing(wb);
  669. buffer_print_uint64(wb, value);
  670. wb->json.stack[wb->json.depth].count++;
  671. }
  672. static inline void buffer_json_add_array_item_boolean(BUFFER *wb, bool value) {
  673. buffer_print_json_comma_newline_spacing(wb);
  674. buffer_strcat(wb, value ? "true" : "false");
  675. wb->json.stack[wb->json.depth].count++;
  676. }
  677. static inline void buffer_json_add_array_item_time_t(BUFFER *wb, time_t value) {
  678. buffer_print_json_comma_newline_spacing(wb);
  679. buffer_print_int64(wb, value);
  680. wb->json.stack[wb->json.depth].count++;
  681. }
  682. static inline void buffer_json_add_array_item_time_ms(BUFFER *wb, time_t value) {
  683. buffer_print_json_comma_newline_spacing(wb);
  684. buffer_print_int64(wb, value);
  685. buffer_fast_strcat(wb, "000", 3);
  686. wb->json.stack[wb->json.depth].count++;
  687. }
  688. static inline void buffer_json_add_array_item_time_t2ms(BUFFER *wb, time_t value) {
  689. buffer_print_json_comma_newline_spacing(wb);
  690. buffer_print_int64(wb, value);
  691. buffer_fast_strcat(wb, "000", 3);
  692. wb->json.stack[wb->json.depth].count++;
  693. }
  694. static inline void buffer_json_add_array_item_object(BUFFER *wb) {
  695. buffer_print_json_comma_newline_spacing(wb);
  696. buffer_fast_strcat(wb, "{", 1);
  697. wb->json.stack[wb->json.depth].count++;
  698. _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
  699. }
  700. static inline void buffer_json_member_add_time_t(BUFFER *wb, const char *key, time_t value) {
  701. buffer_print_json_comma_newline_spacing(wb);
  702. buffer_print_json_key(wb, key);
  703. buffer_fast_strcat(wb, ":", 1);
  704. buffer_print_int64(wb, value);
  705. wb->json.stack[wb->json.depth].count++;
  706. }
  707. static inline void buffer_json_member_add_time_t2ms(BUFFER *wb, const char *key, time_t value) {
  708. buffer_print_json_comma_newline_spacing(wb);
  709. buffer_print_json_key(wb, key);
  710. buffer_fast_strcat(wb, ":", 1);
  711. buffer_print_int64(wb, value);
  712. buffer_fast_strcat(wb, "000", 3);
  713. wb->json.stack[wb->json.depth].count++;
  714. }
  715. static inline void buffer_json_member_add_uint64(BUFFER *wb, const char *key, uint64_t value) {
  716. buffer_print_json_comma_newline_spacing(wb);
  717. buffer_print_json_key(wb, key);
  718. buffer_fast_strcat(wb, ":", 1);
  719. buffer_print_uint64(wb, value);
  720. wb->json.stack[wb->json.depth].count++;
  721. }
  722. static inline void buffer_json_member_add_int64(BUFFER *wb, const char *key, int64_t value) {
  723. buffer_print_json_comma_newline_spacing(wb);
  724. buffer_print_json_key(wb, key);
  725. buffer_fast_strcat(wb, ":", 1);
  726. buffer_print_int64(wb, value);
  727. wb->json.stack[wb->json.depth].count++;
  728. }
  729. static inline void buffer_json_member_add_double(BUFFER *wb, const char *key, NETDATA_DOUBLE value) {
  730. buffer_print_json_comma_newline_spacing(wb);
  731. buffer_print_json_key(wb, key);
  732. buffer_fast_strcat(wb, ":", 1);
  733. buffer_print_netdata_double(wb, value);
  734. wb->json.stack[wb->json.depth].count++;
  735. }
  736. static inline void buffer_json_array_close(BUFFER *wb) {
  737. #ifdef NETDATA_INTERNAL_CHECKS
  738. assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
  739. assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_ARRAY && "BUFFER JSON: an array is not open to close it");
  740. #endif
  741. if(wb->json.options & BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS) {
  742. buffer_fast_strcat(wb, "\n", 1);
  743. buffer_print_spaces(wb, wb->json.depth);
  744. }
  745. buffer_fast_strcat(wb, "]", 1);
  746. _buffer_json_depth_pop(wb);
  747. }
  748. typedef enum __attribute__((packed)) {
  749. RRDF_FIELD_OPTS_NONE = 0,
  750. RRDF_FIELD_OPTS_UNIQUE_KEY = (1 << 0), // the field is the unique key of the row
  751. RRDF_FIELD_OPTS_VISIBLE = (1 << 1), // the field should be visible by default
  752. RRDF_FIELD_OPTS_STICKY = (1 << 2), // the field should be sticky
  753. RRDF_FIELD_OPTS_FULL_WIDTH = (1 << 3), // the field should get full width
  754. RRDF_FIELD_OPTS_WRAP = (1 << 4), // the field should wrap
  755. RRDF_FIELD_OPTS_DUMMY = (1 << 5), // not a presentable field
  756. RRDF_FIELD_OPTS_EXPANDED_FILTER = (1 << 6), // show the filter expanded
  757. } RRDF_FIELD_OPTIONS;
  758. typedef enum __attribute__((packed)) {
  759. RRDF_FIELD_TYPE_NONE,
  760. RRDF_FIELD_TYPE_INTEGER,
  761. RRDF_FIELD_TYPE_BOOLEAN,
  762. RRDF_FIELD_TYPE_STRING,
  763. RRDF_FIELD_TYPE_DETAIL_STRING,
  764. RRDF_FIELD_TYPE_BAR_WITH_INTEGER,
  765. RRDF_FIELD_TYPE_DURATION,
  766. RRDF_FIELD_TYPE_TIMESTAMP,
  767. RRDF_FIELD_TYPE_ARRAY,
  768. } RRDF_FIELD_TYPE;
  769. static inline const char *rrdf_field_type_to_string(RRDF_FIELD_TYPE type) {
  770. switch(type) {
  771. default:
  772. case RRDF_FIELD_TYPE_NONE:
  773. return "none";
  774. case RRDF_FIELD_TYPE_INTEGER:
  775. return "integer";
  776. case RRDF_FIELD_TYPE_BOOLEAN:
  777. return "boolean";
  778. case RRDF_FIELD_TYPE_STRING:
  779. return "string";
  780. case RRDF_FIELD_TYPE_DETAIL_STRING:
  781. return "detail-string";
  782. case RRDF_FIELD_TYPE_BAR_WITH_INTEGER:
  783. return "bar-with-integer";
  784. case RRDF_FIELD_TYPE_DURATION:
  785. return "duration";
  786. case RRDF_FIELD_TYPE_TIMESTAMP:
  787. return "timestamp";
  788. case RRDF_FIELD_TYPE_ARRAY:
  789. return "array";
  790. }
  791. }
  792. typedef enum __attribute__((packed)) {
  793. RRDF_FIELD_VISUAL_VALUE, // show the value, possibly applying a transformation
  794. RRDF_FIELD_VISUAL_BAR, // show the value and a bar, respecting the max field to fill the bar at 100%
  795. RRDF_FIELD_VISUAL_PILL, //
  796. RRDF_FIELD_VISUAL_RICH, //
  797. RRDR_FIELD_VISUAL_ROW_OPTIONS, // this is a dummy column that is used for row options
  798. } RRDF_FIELD_VISUAL;
  799. static inline const char *rrdf_field_visual_to_string(RRDF_FIELD_VISUAL visual) {
  800. switch(visual) {
  801. default:
  802. case RRDF_FIELD_VISUAL_VALUE:
  803. return "value";
  804. case RRDF_FIELD_VISUAL_BAR:
  805. return "bar";
  806. case RRDF_FIELD_VISUAL_PILL:
  807. return "pill";
  808. case RRDF_FIELD_VISUAL_RICH:
  809. return "richValue";
  810. case RRDR_FIELD_VISUAL_ROW_OPTIONS:
  811. return "rowOptions";
  812. }
  813. }
  814. typedef enum __attribute__((packed)) {
  815. RRDF_FIELD_TRANSFORM_NONE, // show the value as-is
  816. RRDF_FIELD_TRANSFORM_NUMBER, // show the value respecting the decimal_points
  817. RRDF_FIELD_TRANSFORM_DURATION_S, // transform as duration in second to a human-readable duration
  818. RRDF_FIELD_TRANSFORM_DATETIME_MS, // UNIX epoch timestamp in ms
  819. RRDF_FIELD_TRANSFORM_DATETIME_USEC, // UNIX epoch timestamp in usec
  820. } RRDF_FIELD_TRANSFORM;
  821. static inline const char *rrdf_field_transform_to_string(RRDF_FIELD_TRANSFORM transform) {
  822. switch(transform) {
  823. default:
  824. case RRDF_FIELD_TRANSFORM_NONE:
  825. return "none";
  826. case RRDF_FIELD_TRANSFORM_NUMBER:
  827. return "number";
  828. case RRDF_FIELD_TRANSFORM_DURATION_S:
  829. return "duration";
  830. case RRDF_FIELD_TRANSFORM_DATETIME_MS:
  831. return "datetime";
  832. case RRDF_FIELD_TRANSFORM_DATETIME_USEC:
  833. return "datetime_usec";
  834. }
  835. }
  836. typedef enum __attribute__((packed)) {
  837. RRDF_FIELD_SORT_ASCENDING = (1 << 0),
  838. RRDF_FIELD_SORT_DESCENDING = (1 << 1),
  839. RRDF_FIELD_SORT_FIXED = (1 << 7),
  840. } RRDF_FIELD_SORT;
  841. static inline const char *rrdf_field_sort_to_string(RRDF_FIELD_SORT sort) {
  842. if(sort & RRDF_FIELD_SORT_DESCENDING)
  843. return "descending";
  844. else
  845. return "ascending";
  846. }
  847. typedef enum __attribute__((packed)) {
  848. RRDF_FIELD_SUMMARY_UNIQUECOUNT, // Finds the number of unique values of a group of rows
  849. RRDF_FIELD_SUMMARY_SUM, // Sums the values of a group of rows
  850. RRDF_FIELD_SUMMARY_MIN, // Finds the minimum value of a group of rows
  851. RRDF_FIELD_SUMMARY_MAX, // Finds the maximum value of a group of rows
  852. // RRDF_FIELD_SUMMARY_EXTENT, // Finds the minimum and maximum values of a group of rows
  853. RRDF_FIELD_SUMMARY_MEAN, // Finds the mean/average value of a group of rows
  854. RRDF_FIELD_SUMMARY_MEDIAN, // Finds the median value of a group of rows
  855. // RRDF_FIELD_SUMMARY_UNIQUE, // Finds the unique values of a group of rows
  856. RRDF_FIELD_SUMMARY_COUNT, // Calculates the number of rows in a group
  857. } RRDF_FIELD_SUMMARY;
  858. static inline const char *rrdf_field_summary_to_string(RRDF_FIELD_SUMMARY summary) {
  859. switch(summary) {
  860. default:
  861. case RRDF_FIELD_SUMMARY_COUNT:
  862. return "count";
  863. case RRDF_FIELD_SUMMARY_UNIQUECOUNT:
  864. return "uniqueCount";
  865. case RRDF_FIELD_SUMMARY_SUM:
  866. return "sum";
  867. case RRDF_FIELD_SUMMARY_MIN:
  868. return "min";
  869. case RRDF_FIELD_SUMMARY_MEAN:
  870. return "mean";
  871. case RRDF_FIELD_SUMMARY_MEDIAN:
  872. return "median";
  873. case RRDF_FIELD_SUMMARY_MAX:
  874. return "max";
  875. }
  876. }
  877. typedef enum __attribute__((packed)) {
  878. RRDF_FIELD_FILTER_NONE = 0,
  879. RRDF_FIELD_FILTER_RANGE,
  880. RRDF_FIELD_FILTER_MULTISELECT,
  881. RRDF_FIELD_FILTER_FACET,
  882. } RRDF_FIELD_FILTER;
  883. static inline const char *rrdf_field_filter_to_string(RRDF_FIELD_FILTER filter) {
  884. switch(filter) {
  885. case RRDF_FIELD_FILTER_RANGE:
  886. return "range";
  887. case RRDF_FIELD_FILTER_MULTISELECT:
  888. return "multiselect";
  889. case RRDF_FIELD_FILTER_FACET:
  890. return "facet";
  891. default:
  892. case RRDF_FIELD_FILTER_NONE:
  893. return "none";
  894. }
  895. }
  896. static inline void
  897. buffer_rrdf_table_add_field(BUFFER *wb, size_t field_id, const char *key, const char *name, RRDF_FIELD_TYPE type,
  898. RRDF_FIELD_VISUAL visual, RRDF_FIELD_TRANSFORM transform, size_t decimal_points,
  899. const char *units, NETDATA_DOUBLE max, RRDF_FIELD_SORT sort, const char *pointer_to,
  900. RRDF_FIELD_SUMMARY summary, RRDF_FIELD_FILTER filter, RRDF_FIELD_OPTIONS options,
  901. const char *default_value) {
  902. buffer_json_member_add_object(wb, key);
  903. {
  904. buffer_json_member_add_uint64(wb, "index", field_id);
  905. buffer_json_member_add_boolean(wb, "unique_key", options & RRDF_FIELD_OPTS_UNIQUE_KEY);
  906. buffer_json_member_add_string(wb, "name", name);
  907. buffer_json_member_add_boolean(wb, "visible", options & RRDF_FIELD_OPTS_VISIBLE);
  908. buffer_json_member_add_string(wb, "type", rrdf_field_type_to_string(type));
  909. buffer_json_member_add_string_or_omit(wb, "units", units);
  910. buffer_json_member_add_string(wb, "visualization", rrdf_field_visual_to_string(visual));
  911. buffer_json_member_add_object(wb, "value_options");
  912. {
  913. buffer_json_member_add_string_or_omit(wb, "units", units);
  914. buffer_json_member_add_string(wb, "transform", rrdf_field_transform_to_string(transform));
  915. buffer_json_member_add_uint64(wb, "decimal_points", decimal_points);
  916. buffer_json_member_add_string(wb, "default_value", default_value);
  917. }
  918. buffer_json_object_close(wb);
  919. if (!isnan((NETDATA_DOUBLE) (max)))
  920. buffer_json_member_add_double(wb, "max", (NETDATA_DOUBLE) (max));
  921. buffer_json_member_add_string_or_omit(wb, "pointer_to", pointer_to);
  922. buffer_json_member_add_string(wb, "sort", rrdf_field_sort_to_string(sort));
  923. buffer_json_member_add_boolean(wb, "sortable", !(sort & RRDF_FIELD_SORT_FIXED));
  924. buffer_json_member_add_boolean(wb, "sticky", options & RRDF_FIELD_OPTS_STICKY);
  925. buffer_json_member_add_string(wb, "summary", rrdf_field_summary_to_string(summary));
  926. buffer_json_member_add_string(wb, "filter", rrdf_field_filter_to_string(filter));
  927. buffer_json_member_add_boolean(wb, "full_width", options & RRDF_FIELD_OPTS_FULL_WIDTH);
  928. buffer_json_member_add_boolean(wb, "wrap", options & RRDF_FIELD_OPTS_WRAP);
  929. buffer_json_member_add_boolean(wb, "default_expanded_filter", options & RRDF_FIELD_OPTS_EXPANDED_FILTER);
  930. if(options & RRDF_FIELD_OPTS_DUMMY)
  931. buffer_json_member_add_boolean(wb, "dummy", true);
  932. }
  933. buffer_json_object_close(wb);
  934. }
  935. static inline void buffer_copy(BUFFER *dst, BUFFER *src) {
  936. if(!src || !dst)
  937. return;
  938. buffer_contents_replace(dst, buffer_tostring(src), buffer_strlen(src));
  939. dst->content_type = src->content_type;
  940. dst->options = src->options;
  941. dst->date = src->date;
  942. dst->expires = src->expires;
  943. dst->json = src->json;
  944. }
  945. static inline BUFFER *buffer_dup(BUFFER *src) {
  946. if(!src)
  947. return NULL;
  948. BUFFER *dst = buffer_create(buffer_strlen(src) + 1, src->statistics);
  949. buffer_copy(dst, src);
  950. return dst;
  951. }
  952. #endif /* NETDATA_WEB_BUFFER_H */