1 /**************************************************************************//**
3 * Source module relating to internal EVEL_JSON_BUFFER manipulation functions.
8 * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement: This product includes
20 * software developed by the AT&T.
21 * 4. Neither the name of AT&T nor the names of its contributors may be used to
22 * endorse or promote products derived from this software without specific
23 * prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
26 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
29 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *****************************************************************************/
40 #include "evel_throttle.h"
42 /*****************************************************************************/
43 /* Local prototypes. */
44 /*****************************************************************************/
45 static char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf);
47 /**************************************************************************//**
48 * Initialize a ::EVEL_JSON_BUFFER.
50 * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to initialise.
51 * @param json Pointer to the underlying working buffer to use.
52 * @param max_size Size of storage available in the JSON buffer.
53 * @param throttle_spec Pointer to throttle specification. Can be NULL.
54 *****************************************************************************/
55 void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf,
58 EVEL_THROTTLE_SPEC * throttle_spec)
65 jbuf->max_size = max_size;
67 jbuf->throttle_spec = throttle_spec;
69 jbuf->checkpoint = -1;
74 /**************************************************************************//**
75 * Encode an integer value to a JSON buffer.
77 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
78 * @param value The integer to add to it.
79 *****************************************************************************/
80 void evel_enc_int(EVEL_JSON_BUFFER * jbuf,
85 /***************************************************************************/
86 /* Check preconditions. */
87 /***************************************************************************/
90 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
91 jbuf->max_size - jbuf->offset,
97 /**************************************************************************//**
98 * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
100 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
101 * @param key Pointer to the key to encode.
102 * @param option Pointer to holder of the corresponding value to encode.
103 * @return true if the key, value was added, false if it was suppressed.
104 *****************************************************************************/
105 bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf,
106 const char * const key,
107 const EVEL_OPTION_STRING * const option)
113 /***************************************************************************/
114 /* Check preconditions. */
115 /***************************************************************************/
116 assert(option != NULL);
120 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
121 (jbuf->throttle_spec != NULL) &&
122 evel_throttle_suppress_field(jbuf->throttle_spec, key))
124 EVEL_INFO("Suppressed: %s, %s", key, option->value);
128 EVEL_DEBUG("Encoded: %s, %s", key, option->value);
129 evel_enc_kv_string(jbuf, key, option->value);
139 /**************************************************************************//**
140 * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
142 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
143 * @param key Pointer to the key to encode.
144 * @param value Pointer to the corresponding value to encode.
145 *****************************************************************************/
146 void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf,
147 const char * const key,
148 const char * const value)
155 /***************************************************************************/
156 /* Check preconditions. */
157 /***************************************************************************/
158 assert(jbuf != NULL);
161 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
162 jbuf->max_size - jbuf->offset,
164 evel_json_kv_comma(jbuf),
167 /***************************************************************************/
168 /* We need to escape quotation marks and backslashes in the value. */
169 /***************************************************************************/
170 length = strlen(value);
172 for (index = 0; index < length; index++)
174 /*************************************************************************/
175 /* Drop out if no more space. */
176 /*************************************************************************/
177 if (jbuf->max_size - jbuf->offset < 2)
182 /*************************************************************************/
183 /* Add an escape character if necessary, then write the character */
185 /*************************************************************************/
186 if ((value[index] == '\"') || (value[index] == '\\'))
188 jbuf->json[jbuf->offset] = '\\';
192 jbuf->json[jbuf->offset] = value[index];
196 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
197 jbuf->max_size - jbuf->offset,
204 /**************************************************************************//**
205 * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
207 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
208 * @param key Pointer to the key to encode.
209 * @param option Pointer to holder of the corresponding value to encode.
210 * @return true if the key, value was added, false if it was suppressed.
211 *****************************************************************************/
212 bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
213 const char * const key,
214 const EVEL_OPTION_INT * const option)
220 /***************************************************************************/
221 /* Check preconditions. */
222 /***************************************************************************/
223 assert(option != NULL);
227 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
228 (jbuf->throttle_spec != NULL) &&
229 evel_throttle_suppress_field(jbuf->throttle_spec, key))
231 EVEL_INFO("Suppressed: %s, %d", key, option->value);
235 EVEL_DEBUG("Encoded: %s, %d", key, option->value);
236 evel_enc_kv_int(jbuf, key, option->value);
246 /**************************************************************************//**
247 * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
249 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
250 * @param key Pointer to the key to encode.
251 * @param value The corresponding value to encode.
252 *****************************************************************************/
253 void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
254 const char * const key,
259 /***************************************************************************/
260 /* Check preconditions. */
261 /***************************************************************************/
262 assert(jbuf != NULL);
265 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
266 jbuf->max_size - jbuf->offset,
268 evel_json_kv_comma(jbuf),
275 /**************************************************************************//**
276 * Encode a string key and json object value to a ::EVEL_JSON_BUFFER.
278 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
279 * @param key Pointer to the key to encode.
280 * @param value The corresponding json string to encode.
281 *****************************************************************************/
282 void evel_enc_kv_object(EVEL_JSON_BUFFER * jbuf,
283 const char * const key,
288 /***************************************************************************/
289 /* Check preconditions. */
290 /***************************************************************************/
291 assert(jbuf != NULL);
294 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
295 jbuf->max_size - jbuf->offset,
297 evel_json_kv_comma(jbuf),
304 /**************************************************************************//**
305 * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
307 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
308 * @param key Pointer to the key to encode.
309 * @param option Pointer to holder of the corresponding value to encode.
310 * @return true if the key, value was added, false if it was suppressed.
311 *****************************************************************************/
312 bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
313 const char * const key,
314 const EVEL_OPTION_DOUBLE * const option)
320 /***************************************************************************/
321 /* Check preconditions. */
322 /***************************************************************************/
323 assert(option != NULL);
327 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
328 (jbuf->throttle_spec != NULL) &&
329 evel_throttle_suppress_field(jbuf->throttle_spec, key))
331 EVEL_INFO("Suppressed: %s, %1f", key, option->value);
335 EVEL_DEBUG("Encoded: %s, %1f", key, option->value);
336 evel_enc_kv_double(jbuf, key, option->value);
346 /**************************************************************************//**
347 * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
349 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
350 * @param key Pointer to the key to encode.
351 * @param value The corresponding value to encode.
352 *****************************************************************************/
353 void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
354 const char * const key,
359 /***************************************************************************/
360 /* Check preconditions. */
361 /***************************************************************************/
362 assert(jbuf != NULL);
365 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
366 jbuf->max_size - jbuf->offset,
368 evel_json_kv_comma(jbuf),
375 /**************************************************************************//**
376 * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
378 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
379 * @param key Pointer to the key to encode.
380 * @param option Pointer to holder of the corresponding value to encode.
381 * @return true if the key, value was added, false if it was suppressed.
382 *****************************************************************************/
383 bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
384 const char * const key,
385 const EVEL_OPTION_ULL * const option)
391 /***************************************************************************/
392 /* Check preconditions. */
393 /***************************************************************************/
394 assert(option != NULL);
398 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
399 (jbuf->throttle_spec != NULL) &&
400 evel_throttle_suppress_field(jbuf->throttle_spec, key))
402 EVEL_INFO("Suppressed: %s, %1lu", key, option->value);
406 EVEL_DEBUG("Encoded: %s, %1lu", key, option->value);
407 evel_enc_kv_ull(jbuf, key, option->value);
417 /**************************************************************************//**
418 * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
420 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
421 * @param key Pointer to the key to encode.
422 * @param value The corresponding value to encode.
423 *****************************************************************************/
424 void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
425 const char * const key,
426 const unsigned long long value)
430 /***************************************************************************/
431 /* Check preconditions. */
432 /***************************************************************************/
433 assert(jbuf != NULL);
436 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
437 jbuf->max_size - jbuf->offset,
439 evel_json_kv_comma(jbuf),
446 /**************************************************************************//**
447 * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
449 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
450 * @param key Pointer to the key to encode.
451 * @param option Pointer to holder of the corresponding value to encode.
452 * @return true if the key, value was added, false if it was suppressed.
453 *****************************************************************************/
454 bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
455 const char * const key,
456 const EVEL_OPTION_TIME * const option)
462 /***************************************************************************/
463 /* Check preconditions. */
464 /***************************************************************************/
465 assert(option != NULL);
469 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
470 (jbuf->throttle_spec != NULL) &&
471 evel_throttle_suppress_field(jbuf->throttle_spec, key))
473 EVEL_INFO("Suppressed time: %s", key);
477 EVEL_DEBUG("Encoded time: %s", key);
478 evel_enc_kv_time(jbuf, key, &option->value);
488 /**************************************************************************//**
489 * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
491 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
492 * @param key Pointer to the key to encode.
493 * @param time Pointer to the time to encode.
494 *****************************************************************************/
495 void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
496 const char * const key,
501 /***************************************************************************/
502 /* Check preconditions. */
503 /***************************************************************************/
504 assert(jbuf != NULL);
506 assert(time != NULL);
508 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
509 jbuf->max_size - jbuf->offset,
511 evel_json_kv_comma(jbuf),
513 jbuf->offset += strftime(jbuf->json + jbuf->offset,
514 jbuf->max_size - jbuf->offset,
515 EVEL_RFC2822_STRFTIME_FORMAT,
517 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
518 jbuf->max_size - jbuf->offset,
523 /**************************************************************************//**
524 * Encode a key and version.
526 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
527 * @param key Pointer to the key to encode.
528 * @param major_version The major version to encode.
529 * @param minor_version The minor version to encode.
530 *****************************************************************************/
531 void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
532 const char * const key,
533 const int major_version,
534 const int minor_version)
538 /***************************************************************************/
539 /* Check preconditions. */
540 /***************************************************************************/
541 assert(jbuf != NULL);
544 evel_enc_kv_int(jbuf, key, major_version);
545 if (minor_version != 0)
547 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
548 jbuf->max_size - jbuf->offset,
556 /**************************************************************************//**
557 * Add the key and opening bracket of an optional named list to a JSON buffer.
559 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
560 * @param key Pointer to the key to encode.
561 * @return true if the list was opened, false if it was suppressed.
562 *****************************************************************************/
563 bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
564 const char * const key)
570 /***************************************************************************/
571 /* Check preconditions. */
572 /***************************************************************************/
573 assert(jbuf != NULL);
576 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
577 (jbuf->throttle_spec != NULL) &&
578 evel_throttle_suppress_field(jbuf->throttle_spec, key))
580 EVEL_INFO("Suppressed: %s", key);
585 evel_json_open_named_list(jbuf, key);
594 /**************************************************************************//**
595 * Add the key and opening bracket of a named list to a JSON buffer.
597 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
598 * @param key Pointer to the key to encode.
599 *****************************************************************************/
600 void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
601 const char * const key)
605 /***************************************************************************/
606 /* Check preconditions. */
607 /***************************************************************************/
608 assert(jbuf != NULL);
611 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
612 jbuf->max_size - jbuf->offset,
614 evel_json_kv_comma(jbuf),
621 /**************************************************************************//**
622 * Add the closing bracket of a list to a JSON buffer.
624 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
625 *****************************************************************************/
626 void evel_json_close_list(EVEL_JSON_BUFFER * jbuf)
630 /***************************************************************************/
631 /* Check preconditions. */
632 /***************************************************************************/
633 assert(jbuf != NULL);
635 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
636 jbuf->max_size - jbuf->offset,
643 /**************************************************************************//**
644 * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
646 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
647 * @param format Format string in standard printf format.
648 * @param ... Variable parameters for format string.
649 *****************************************************************************/
650 void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
651 const char * const format,
658 /***************************************************************************/
659 /* Check preconditions. */
660 /***************************************************************************/
661 assert(jbuf != NULL);
662 assert(format != NULL);
664 /***************************************************************************/
665 /* Add a comma unless we're at the start of the list. */
666 /***************************************************************************/
667 if (jbuf->json[jbuf->offset - 1] != '[')
669 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
670 jbuf->max_size - jbuf->offset,
674 va_start(largs, format);
675 jbuf->offset += vsnprintf(jbuf->json + jbuf->offset,
676 jbuf->max_size - jbuf->offset,
684 /**************************************************************************//**
685 * Add the opening bracket of an optional named object to a JSON buffer.
687 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
688 * @param key Pointer to the key to encode.
689 *****************************************************************************/
690 bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
691 const char * const key)
697 /***************************************************************************/
698 /* Check preconditions. */
699 /***************************************************************************/
700 assert(jbuf != NULL);
703 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
704 (jbuf->throttle_spec != NULL) &&
705 evel_throttle_suppress_field(jbuf->throttle_spec, key))
707 EVEL_INFO("Suppressed: %s", key);
712 evel_json_open_named_object(jbuf, key);
721 /**************************************************************************//**
722 * Add the opening bracket of an object to a JSON buffer.
724 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
725 * @param key Pointer to the key to encode.
726 * @return true if the object was opened, false if it was suppressed.
727 *****************************************************************************/
728 void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
729 const char * const key)
733 /***************************************************************************/
734 /* Check preconditions. */
735 /***************************************************************************/
736 assert(jbuf != NULL);
739 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
740 jbuf->max_size - jbuf->offset,
742 evel_json_kv_comma(jbuf),
749 /**************************************************************************//**
750 * Add the opening bracket of an object to a JSON buffer.
752 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
753 *****************************************************************************/
754 void evel_json_open_object(EVEL_JSON_BUFFER * jbuf)
760 /***************************************************************************/
761 /* Check preconditions. */
762 /***************************************************************************/
763 assert(jbuf != NULL);
765 if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}'))
774 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
775 jbuf->max_size - jbuf->offset,
783 /**************************************************************************//**
784 * Add the closing bracket of an object to a JSON buffer.
786 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
787 *****************************************************************************/
788 void evel_json_close_object(EVEL_JSON_BUFFER * jbuf)
792 /***************************************************************************/
793 /* Check preconditions. */
794 /***************************************************************************/
795 assert(jbuf != NULL);
797 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
798 jbuf->max_size - jbuf->offset,
805 /**************************************************************************//**
806 * Determine whether to add a comma when adding a key-value pair.
808 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
809 * @returns A string containing the comma if it is required.
810 *****************************************************************************/
811 char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf)
817 /***************************************************************************/
818 /* Check preconditions. */
819 /***************************************************************************/
820 assert(jbuf != NULL);
822 if ((jbuf->offset == 0) ||
823 (jbuf->json[jbuf->offset-1] == '{') ||
824 (jbuf->json[jbuf->offset-1] == '['))
838 /**************************************************************************//**
839 * Add a checkpoint - a stake in the ground to which we can rewind.
841 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
842 *****************************************************************************/
843 void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf)
847 /***************************************************************************/
848 /* Check preconditions. */
849 /***************************************************************************/
850 assert(jbuf != NULL);
852 /***************************************************************************/
853 /* Store the current offset. */
854 /***************************************************************************/
855 jbuf->checkpoint = jbuf->offset;
860 /**************************************************************************//**
861 * Rewind to the latest checkoint.
863 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
864 *****************************************************************************/
865 void evel_json_rewind(EVEL_JSON_BUFFER * jbuf)
869 /***************************************************************************/
870 /* Check preconditions. */
871 /***************************************************************************/
872 assert(jbuf != NULL);
873 assert(jbuf->checkpoint >= 0);
874 assert(jbuf->checkpoint <= jbuf->offset);
876 /***************************************************************************/
877 /* Reinstate the offset from the last checkpoint. */
878 /***************************************************************************/
879 jbuf->offset = jbuf->checkpoint;
880 jbuf->checkpoint = -1;