1 /**************************************************************************//**
3 * Source module relating to internal EVEL_JSON_BUFFER manipulation functions.
8 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *****************************************************************************/
25 #include "evel_throttle.h"
27 /*****************************************************************************/
28 /* Local prototypes. */
29 /*****************************************************************************/
30 static char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf);
32 /**************************************************************************//**
33 * Initialize a ::EVEL_JSON_BUFFER.
35 * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to initialise.
36 * @param json Pointer to the underlying working buffer to use.
37 * @param max_size Size of storage available in the JSON buffer.
38 * @param throttle_spec Pointer to throttle specification. Can be NULL.
39 *****************************************************************************/
40 void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf,
43 EVEL_THROTTLE_SPEC * throttle_spec)
50 jbuf->max_size = max_size;
52 jbuf->throttle_spec = throttle_spec;
54 jbuf->checkpoint = -1;
59 /**************************************************************************//**
60 * Encode an integer value to a JSON buffer.
62 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
63 * @param value The integer to add to it.
64 *****************************************************************************/
65 void evel_enc_int(EVEL_JSON_BUFFER * jbuf,
70 /***************************************************************************/
71 /* Check preconditions. */
72 /***************************************************************************/
75 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
76 jbuf->max_size - jbuf->offset,
82 /**************************************************************************//**
83 * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
85 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
86 * @param key Pointer to the key to encode.
87 * @param option Pointer to holder of the corresponding value to encode.
88 * @return true if the key, value was added, false if it was suppressed.
89 *****************************************************************************/
90 bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf,
91 const char * const key,
92 const EVEL_OPTION_STRING * const option)
98 /***************************************************************************/
99 /* Check preconditions. */
100 /***************************************************************************/
101 assert(option != NULL);
105 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
106 (jbuf->throttle_spec != NULL) &&
107 evel_throttle_suppress_field(jbuf->throttle_spec, key))
109 EVEL_INFO("Suppressed: %s, %s", key, option->value);
113 EVEL_DEBUG("Encoded: %s, %s", key, option->value);
114 evel_enc_kv_string(jbuf, key, option->value);
124 /**************************************************************************//**
125 * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
127 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
128 * @param key Pointer to the key to encode.
129 * @param value Pointer to the corresponding value to encode.
130 *****************************************************************************/
131 void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf,
132 const char * const key,
133 const char * const value)
140 /***************************************************************************/
141 /* Check preconditions. */
142 /***************************************************************************/
143 assert(jbuf != NULL);
146 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
147 jbuf->max_size - jbuf->offset,
149 evel_json_kv_comma(jbuf),
152 /***************************************************************************/
153 /* We need to escape quotation marks and backslashes in the value. */
154 /***************************************************************************/
155 length = strlen(value);
157 for (index = 0; index < length; index++)
159 /*************************************************************************/
160 /* Drop out if no more space. */
161 /*************************************************************************/
162 if (jbuf->max_size - jbuf->offset < 2)
167 /*************************************************************************/
168 /* Add an escape character if necessary, then write the character */
170 /*************************************************************************/
171 if ((value[index] == '\"') || (value[index] == '\\'))
173 jbuf->json[jbuf->offset] = '\\';
177 jbuf->json[jbuf->offset] = value[index];
181 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
182 jbuf->max_size - jbuf->offset,
188 /**************************************************************************//**
189 * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
191 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
192 * @param key Pointer to the key to encode.
193 * @param option Pointer to holder of the corresponding value to encode.
194 * @return true if the key, value was added, false if it was suppressed.
195 *****************************************************************************/
196 bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
197 const char * const key,
198 const EVEL_OPTION_INT * const option)
204 /***************************************************************************/
205 /* Check preconditions. */
206 /***************************************************************************/
207 assert(option != NULL);
211 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
212 (jbuf->throttle_spec != NULL) &&
213 evel_throttle_suppress_field(jbuf->throttle_spec, key))
215 EVEL_INFO("Suppressed: %s, %d", key, option->value);
219 EVEL_DEBUG("Encoded: %s, %d", key, option->value);
220 evel_enc_kv_int(jbuf, key, option->value);
230 /**************************************************************************//**
231 * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
233 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
234 * @param key Pointer to the key to encode.
235 * @param value The corresponding value to encode.
236 *****************************************************************************/
237 void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
238 const char * const key,
243 /***************************************************************************/
244 /* Check preconditions. */
245 /***************************************************************************/
246 assert(jbuf != NULL);
249 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
250 jbuf->max_size - jbuf->offset,
252 evel_json_kv_comma(jbuf),
259 /**************************************************************************//**
260 * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
262 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
263 * @param key Pointer to the key to encode.
264 * @param option Pointer to holder of the corresponding value to encode.
265 * @return true if the key, value was added, false if it was suppressed.
266 *****************************************************************************/
267 bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
268 const char * const key,
269 const EVEL_OPTION_DOUBLE * const option)
275 /***************************************************************************/
276 /* Check preconditions. */
277 /***************************************************************************/
278 assert(option != NULL);
282 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
283 (jbuf->throttle_spec != NULL) &&
284 evel_throttle_suppress_field(jbuf->throttle_spec, key))
286 EVEL_INFO("Suppressed: %s, %1f", key, option->value);
290 EVEL_DEBUG("Encoded: %s, %1f", key, option->value);
291 evel_enc_kv_double(jbuf, key, option->value);
301 /**************************************************************************//**
302 * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
304 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
305 * @param key Pointer to the key to encode.
306 * @param value The corresponding value to encode.
307 *****************************************************************************/
308 void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
309 const char * const key,
314 /***************************************************************************/
315 /* Check preconditions. */
316 /***************************************************************************/
317 assert(jbuf != NULL);
320 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
321 jbuf->max_size - jbuf->offset,
323 evel_json_kv_comma(jbuf),
330 /**************************************************************************//**
331 * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
333 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
334 * @param key Pointer to the key to encode.
335 * @param option Pointer to holder of the corresponding value to encode.
336 * @return true if the key, value was added, false if it was suppressed.
337 *****************************************************************************/
338 bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
339 const char * const key,
340 const EVEL_OPTION_ULL * const option)
346 /***************************************************************************/
347 /* Check preconditions. */
348 /***************************************************************************/
349 assert(option != NULL);
353 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
354 (jbuf->throttle_spec != NULL) &&
355 evel_throttle_suppress_field(jbuf->throttle_spec, key))
357 EVEL_INFO("Suppressed: %s, %1lu", key, option->value);
361 EVEL_DEBUG("Encoded: %s, %1lu", key, option->value);
362 evel_enc_kv_ull(jbuf, key, option->value);
372 /**************************************************************************//**
373 * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
375 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
376 * @param key Pointer to the key to encode.
377 * @param value The corresponding value to encode.
378 *****************************************************************************/
379 void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
380 const char * const key,
381 const unsigned long long value)
385 /***************************************************************************/
386 /* Check preconditions. */
387 /***************************************************************************/
388 assert(jbuf != NULL);
391 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
392 jbuf->max_size - jbuf->offset,
394 evel_json_kv_comma(jbuf),
401 /**************************************************************************//**
402 * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
404 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
405 * @param key Pointer to the key to encode.
406 * @param option Pointer to holder of the corresponding value to encode.
407 * @return true if the key, value was added, false if it was suppressed.
408 *****************************************************************************/
409 bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
410 const char * const key,
411 const EVEL_OPTION_TIME * const option)
417 /***************************************************************************/
418 /* Check preconditions. */
419 /***************************************************************************/
420 assert(option != NULL);
424 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
425 (jbuf->throttle_spec != NULL) &&
426 evel_throttle_suppress_field(jbuf->throttle_spec, key))
428 EVEL_INFO("Suppressed time: %s", key);
432 EVEL_DEBUG("Encoded time: %s", key);
433 evel_enc_kv_time(jbuf, key, &option->value);
443 /**************************************************************************//**
444 * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
446 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
447 * @param key Pointer to the key to encode.
448 * @param time Pointer to the time to encode.
449 *****************************************************************************/
450 void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
451 const char * const key,
456 /***************************************************************************/
457 /* Check preconditions. */
458 /***************************************************************************/
459 assert(jbuf != NULL);
461 assert(time != NULL);
463 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
464 jbuf->max_size - jbuf->offset,
466 evel_json_kv_comma(jbuf),
468 jbuf->offset += strftime(jbuf->json + jbuf->offset,
469 jbuf->max_size - jbuf->offset,
470 EVEL_RFC2822_STRFTIME_FORMAT,
472 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
473 jbuf->max_size - jbuf->offset,
478 /**************************************************************************//**
479 * Encode a key and version.
481 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
482 * @param key Pointer to the key to encode.
483 * @param major_version The major version to encode.
484 * @param minor_version The minor version to encode.
485 *****************************************************************************/
486 void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
487 const char * const key,
488 const int major_version,
489 const int minor_version)
493 /***************************************************************************/
494 /* Check preconditions. */
495 /***************************************************************************/
496 assert(jbuf != NULL);
499 evel_enc_kv_int(jbuf, key, major_version);
500 if (minor_version != 0)
502 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
503 jbuf->max_size - jbuf->offset,
511 /**************************************************************************//**
512 * Add the key and opening bracket of an optional named list to a JSON buffer.
514 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
515 * @param key Pointer to the key to encode.
516 * @return true if the list was opened, false if it was suppressed.
517 *****************************************************************************/
518 bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
519 const char * const key)
525 /***************************************************************************/
526 /* Check preconditions. */
527 /***************************************************************************/
528 assert(jbuf != NULL);
531 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
532 (jbuf->throttle_spec != NULL) &&
533 evel_throttle_suppress_field(jbuf->throttle_spec, key))
535 EVEL_INFO("Suppressed: %s", key);
540 evel_json_open_named_list(jbuf, key);
549 /**************************************************************************//**
550 * Add the key and opening bracket of a named list to a JSON buffer.
552 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
553 * @param key Pointer to the key to encode.
554 *****************************************************************************/
555 void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
556 const char * const key)
560 /***************************************************************************/
561 /* Check preconditions. */
562 /***************************************************************************/
563 assert(jbuf != NULL);
566 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
567 jbuf->max_size - jbuf->offset,
569 evel_json_kv_comma(jbuf),
576 /**************************************************************************//**
577 * Add the closing bracket of a list to a JSON buffer.
579 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
580 *****************************************************************************/
581 void evel_json_close_list(EVEL_JSON_BUFFER * jbuf)
585 /***************************************************************************/
586 /* Check preconditions. */
587 /***************************************************************************/
588 assert(jbuf != NULL);
590 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
591 jbuf->max_size - jbuf->offset,
598 /**************************************************************************//**
599 * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
601 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
602 * @param format Format string in standard printf format.
603 * @param ... Variable parameters for format string.
604 *****************************************************************************/
605 void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
606 const char * const format,
613 /***************************************************************************/
614 /* Check preconditions. */
615 /***************************************************************************/
616 assert(jbuf != NULL);
617 assert(format != NULL);
619 /***************************************************************************/
620 /* Add a comma unless we're at the start of the list. */
621 /***************************************************************************/
622 if (jbuf->json[jbuf->offset - 1] != '[')
624 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
625 jbuf->max_size - jbuf->offset,
629 va_start(largs, format);
630 jbuf->offset += vsnprintf(jbuf->json + jbuf->offset,
631 jbuf->max_size - jbuf->offset,
639 /**************************************************************************//**
640 * Add the opening bracket of an optional named object to a JSON buffer.
642 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
643 * @param key Pointer to the key to encode.
644 *****************************************************************************/
645 bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
646 const char * const key)
652 /***************************************************************************/
653 /* Check preconditions. */
654 /***************************************************************************/
655 assert(jbuf != NULL);
658 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
659 (jbuf->throttle_spec != NULL) &&
660 evel_throttle_suppress_field(jbuf->throttle_spec, key))
662 EVEL_INFO("Suppressed: %s", key);
667 evel_json_open_named_object(jbuf, key);
676 /**************************************************************************//**
677 * Add the opening bracket of an object to a JSON buffer.
679 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
680 * @param key Pointer to the key to encode.
681 * @return true if the object was opened, false if it was suppressed.
682 *****************************************************************************/
683 void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
684 const char * const key)
688 /***************************************************************************/
689 /* Check preconditions. */
690 /***************************************************************************/
691 assert(jbuf != NULL);
694 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
695 jbuf->max_size - jbuf->offset,
697 evel_json_kv_comma(jbuf),
704 /**************************************************************************//**
705 * Add the opening bracket of an object to a JSON buffer.
707 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
708 *****************************************************************************/
709 void evel_json_open_object(EVEL_JSON_BUFFER * jbuf)
715 /***************************************************************************/
716 /* Check preconditions. */
717 /***************************************************************************/
718 assert(jbuf != NULL);
720 if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}'))
729 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
730 jbuf->max_size - jbuf->offset,
738 /**************************************************************************//**
739 * Add the closing bracket of an object to a JSON buffer.
741 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
742 *****************************************************************************/
743 void evel_json_close_object(EVEL_JSON_BUFFER * jbuf)
747 /***************************************************************************/
748 /* Check preconditions. */
749 /***************************************************************************/
750 assert(jbuf != NULL);
752 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
753 jbuf->max_size - jbuf->offset,
760 /**************************************************************************//**
761 * Determine whether to add a comma when adding a key-value pair.
763 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
764 * @returns A string containing the comma if it is required.
765 *****************************************************************************/
766 char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf)
772 /***************************************************************************/
773 /* Check preconditions. */
774 /***************************************************************************/
775 assert(jbuf != NULL);
777 if ((jbuf->offset == 0) ||
778 (jbuf->json[jbuf->offset-1] == '{') ||
779 (jbuf->json[jbuf->offset-1] == '['))
793 /**************************************************************************//**
794 * Add a checkpoint - a stake in the ground to which we can rewind.
796 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
797 *****************************************************************************/
798 void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf)
802 /***************************************************************************/
803 /* Check preconditions. */
804 /***************************************************************************/
805 assert(jbuf != NULL);
807 /***************************************************************************/
808 /* Store the current offset. */
809 /***************************************************************************/
810 jbuf->checkpoint = jbuf->offset;
815 /**************************************************************************//**
816 * Rewind to the latest checkoint.
818 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
819 *****************************************************************************/
820 void evel_json_rewind(EVEL_JSON_BUFFER * jbuf)
824 /***************************************************************************/
825 /* Check preconditions. */
826 /***************************************************************************/
827 assert(jbuf != NULL);
828 assert(jbuf->checkpoint >= 0);
829 assert(jbuf->checkpoint <= jbuf->offset);
831 /***************************************************************************/
832 /* Reinstate the offset from the last checkpoint. */
833 /***************************************************************************/
834 jbuf->offset = jbuf->checkpoint;
835 jbuf->checkpoint = -1;