buffer.h 37 KB

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