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,
203 /**************************************************************************//**
204 * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
206 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
207 * @param key Pointer to the key to encode.
208 * @param option Pointer to holder of the corresponding value to encode.
209 * @return true if the key, value was added, false if it was suppressed.
210 *****************************************************************************/
211 bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
212 const char * const key,
213 const EVEL_OPTION_INT * const option)
219 /***************************************************************************/
220 /* Check preconditions. */
221 /***************************************************************************/
222 assert(option != NULL);
226 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
227 (jbuf->throttle_spec != NULL) &&
228 evel_throttle_suppress_field(jbuf->throttle_spec, key))
230 EVEL_INFO("Suppressed: %s, %d", key, option->value);
234 EVEL_DEBUG("Encoded: %s, %d", key, option->value);
235 evel_enc_kv_int(jbuf, key, option->value);
245 /**************************************************************************//**
246 * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
248 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
249 * @param key Pointer to the key to encode.
250 * @param value The corresponding value to encode.
251 *****************************************************************************/
252 void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
253 const char * const key,
258 /***************************************************************************/
259 /* Check preconditions. */
260 /***************************************************************************/
261 assert(jbuf != NULL);
264 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
265 jbuf->max_size - jbuf->offset,
267 evel_json_kv_comma(jbuf),
274 /**************************************************************************//**
275 * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
277 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
278 * @param key Pointer to the key to encode.
279 * @param option Pointer to holder of the corresponding value to encode.
280 * @return true if the key, value was added, false if it was suppressed.
281 *****************************************************************************/
282 bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
283 const char * const key,
284 const EVEL_OPTION_DOUBLE * const option)
290 /***************************************************************************/
291 /* Check preconditions. */
292 /***************************************************************************/
293 assert(option != NULL);
297 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
298 (jbuf->throttle_spec != NULL) &&
299 evel_throttle_suppress_field(jbuf->throttle_spec, key))
301 EVEL_INFO("Suppressed: %s, %1f", key, option->value);
305 EVEL_DEBUG("Encoded: %s, %1f", key, option->value);
306 evel_enc_kv_double(jbuf, key, option->value);
316 /**************************************************************************//**
317 * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
319 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
320 * @param key Pointer to the key to encode.
321 * @param value The corresponding value to encode.
322 *****************************************************************************/
323 void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
324 const char * const key,
329 /***************************************************************************/
330 /* Check preconditions. */
331 /***************************************************************************/
332 assert(jbuf != NULL);
335 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
336 jbuf->max_size - jbuf->offset,
338 evel_json_kv_comma(jbuf),
345 /**************************************************************************//**
346 * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
348 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
349 * @param key Pointer to the key to encode.
350 * @param option Pointer to holder of the corresponding value to encode.
351 * @return true if the key, value was added, false if it was suppressed.
352 *****************************************************************************/
353 bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
354 const char * const key,
355 const EVEL_OPTION_ULL * const option)
361 /***************************************************************************/
362 /* Check preconditions. */
363 /***************************************************************************/
364 assert(option != NULL);
368 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
369 (jbuf->throttle_spec != NULL) &&
370 evel_throttle_suppress_field(jbuf->throttle_spec, key))
372 EVEL_INFO("Suppressed: %s, %1lu", key, option->value);
376 EVEL_DEBUG("Encoded: %s, %1lu", key, option->value);
377 evel_enc_kv_ull(jbuf, key, option->value);
387 /**************************************************************************//**
388 * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
390 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
391 * @param key Pointer to the key to encode.
392 * @param value The corresponding value to encode.
393 *****************************************************************************/
394 void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
395 const char * const key,
396 const unsigned long long value)
400 /***************************************************************************/
401 /* Check preconditions. */
402 /***************************************************************************/
403 assert(jbuf != NULL);
406 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
407 jbuf->max_size - jbuf->offset,
409 evel_json_kv_comma(jbuf),
416 /**************************************************************************//**
417 * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
419 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
420 * @param key Pointer to the key to encode.
421 * @param option Pointer to holder of the corresponding value to encode.
422 * @return true if the key, value was added, false if it was suppressed.
423 *****************************************************************************/
424 bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
425 const char * const key,
426 const EVEL_OPTION_TIME * const option)
432 /***************************************************************************/
433 /* Check preconditions. */
434 /***************************************************************************/
435 assert(option != NULL);
439 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
440 (jbuf->throttle_spec != NULL) &&
441 evel_throttle_suppress_field(jbuf->throttle_spec, key))
443 EVEL_INFO("Suppressed time: %s", key);
447 EVEL_DEBUG("Encoded time: %s", key);
448 evel_enc_kv_time(jbuf, key, &option->value);
458 /**************************************************************************//**
459 * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
461 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
462 * @param key Pointer to the key to encode.
463 * @param time Pointer to the time to encode.
464 *****************************************************************************/
465 void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
466 const char * const key,
471 /***************************************************************************/
472 /* Check preconditions. */
473 /***************************************************************************/
474 assert(jbuf != NULL);
476 assert(time != NULL);
478 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
479 jbuf->max_size - jbuf->offset,
481 evel_json_kv_comma(jbuf),
483 jbuf->offset += strftime(jbuf->json + jbuf->offset,
484 jbuf->max_size - jbuf->offset,
485 EVEL_RFC2822_STRFTIME_FORMAT,
487 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
488 jbuf->max_size - jbuf->offset,
493 /**************************************************************************//**
494 * Encode a key and version.
496 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
497 * @param key Pointer to the key to encode.
498 * @param major_version The major version to encode.
499 * @param minor_version The minor version to encode.
500 *****************************************************************************/
501 void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
502 const char * const key,
503 const int major_version,
504 const int minor_version)
508 /***************************************************************************/
509 /* Check preconditions. */
510 /***************************************************************************/
511 assert(jbuf != NULL);
514 evel_enc_kv_int(jbuf, key, major_version);
515 if (minor_version != 0)
517 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
518 jbuf->max_size - jbuf->offset,
526 /**************************************************************************//**
527 * Add the key and opening bracket of an optional named list to a JSON buffer.
529 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
530 * @param key Pointer to the key to encode.
531 * @return true if the list was opened, false if it was suppressed.
532 *****************************************************************************/
533 bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
534 const char * const key)
540 /***************************************************************************/
541 /* Check preconditions. */
542 /***************************************************************************/
543 assert(jbuf != NULL);
546 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
547 (jbuf->throttle_spec != NULL) &&
548 evel_throttle_suppress_field(jbuf->throttle_spec, key))
550 EVEL_INFO("Suppressed: %s", key);
555 evel_json_open_named_list(jbuf, key);
564 /**************************************************************************//**
565 * Add the key and opening bracket of a named list to a JSON buffer.
567 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
568 * @param key Pointer to the key to encode.
569 *****************************************************************************/
570 void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
571 const char * const key)
575 /***************************************************************************/
576 /* Check preconditions. */
577 /***************************************************************************/
578 assert(jbuf != NULL);
581 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
582 jbuf->max_size - jbuf->offset,
584 evel_json_kv_comma(jbuf),
591 /**************************************************************************//**
592 * Add the closing bracket of a list to a JSON buffer.
594 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
595 *****************************************************************************/
596 void evel_json_close_list(EVEL_JSON_BUFFER * jbuf)
600 /***************************************************************************/
601 /* Check preconditions. */
602 /***************************************************************************/
603 assert(jbuf != NULL);
605 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
606 jbuf->max_size - jbuf->offset,
613 /**************************************************************************//**
614 * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
616 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
617 * @param format Format string in standard printf format.
618 * @param ... Variable parameters for format string.
619 *****************************************************************************/
620 void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
621 const char * const format,
628 /***************************************************************************/
629 /* Check preconditions. */
630 /***************************************************************************/
631 assert(jbuf != NULL);
632 assert(format != NULL);
634 /***************************************************************************/
635 /* Add a comma unless we're at the start of the list. */
636 /***************************************************************************/
637 if (jbuf->json[jbuf->offset - 1] != '[')
639 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
640 jbuf->max_size - jbuf->offset,
644 va_start(largs, format);
645 jbuf->offset += vsnprintf(jbuf->json + jbuf->offset,
646 jbuf->max_size - jbuf->offset,
654 /**************************************************************************//**
655 * Add the opening bracket of an optional named object to a JSON buffer.
657 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
658 * @param key Pointer to the key to encode.
659 *****************************************************************************/
660 bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
661 const char * const key)
667 /***************************************************************************/
668 /* Check preconditions. */
669 /***************************************************************************/
670 assert(jbuf != NULL);
673 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
674 (jbuf->throttle_spec != NULL) &&
675 evel_throttle_suppress_field(jbuf->throttle_spec, key))
677 EVEL_INFO("Suppressed: %s", key);
682 evel_json_open_named_object(jbuf, key);
691 /**************************************************************************//**
692 * Add the opening bracket of an object to a JSON buffer.
694 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
695 * @param key Pointer to the key to encode.
696 * @return true if the object was opened, false if it was suppressed.
697 *****************************************************************************/
698 void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
699 const char * const key)
703 /***************************************************************************/
704 /* Check preconditions. */
705 /***************************************************************************/
706 assert(jbuf != NULL);
709 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
710 jbuf->max_size - jbuf->offset,
712 evel_json_kv_comma(jbuf),
719 /**************************************************************************//**
720 * Add the opening bracket of an object to a JSON buffer.
722 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
723 *****************************************************************************/
724 void evel_json_open_object(EVEL_JSON_BUFFER * jbuf)
730 /***************************************************************************/
731 /* Check preconditions. */
732 /***************************************************************************/
733 assert(jbuf != NULL);
735 if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}'))
744 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
745 jbuf->max_size - jbuf->offset,
753 /**************************************************************************//**
754 * Add the closing bracket of an object to a JSON buffer.
756 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
757 *****************************************************************************/
758 void evel_json_close_object(EVEL_JSON_BUFFER * jbuf)
762 /***************************************************************************/
763 /* Check preconditions. */
764 /***************************************************************************/
765 assert(jbuf != NULL);
767 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
768 jbuf->max_size - jbuf->offset,
775 /**************************************************************************//**
776 * Determine whether to add a comma when adding a key-value pair.
778 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
779 * @returns A string containing the comma if it is required.
780 *****************************************************************************/
781 char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf)
787 /***************************************************************************/
788 /* Check preconditions. */
789 /***************************************************************************/
790 assert(jbuf != NULL);
792 if ((jbuf->offset == 0) ||
793 (jbuf->json[jbuf->offset-1] == '{') ||
794 (jbuf->json[jbuf->offset-1] == '['))
808 /**************************************************************************//**
809 * Add a checkpoint - a stake in the ground to which we can rewind.
811 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
812 *****************************************************************************/
813 void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf)
817 /***************************************************************************/
818 /* Check preconditions. */
819 /***************************************************************************/
820 assert(jbuf != NULL);
822 /***************************************************************************/
823 /* Store the current offset. */
824 /***************************************************************************/
825 jbuf->checkpoint = jbuf->offset;
830 /**************************************************************************//**
831 * Rewind to the latest checkoint.
833 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
834 *****************************************************************************/
835 void evel_json_rewind(EVEL_JSON_BUFFER * jbuf)
839 /***************************************************************************/
840 /* Check preconditions. */
841 /***************************************************************************/
842 assert(jbuf != NULL);
843 assert(jbuf->checkpoint >= 0);
844 assert(jbuf->checkpoint <= jbuf->offset);
846 /***************************************************************************/
847 /* Reinstate the offset from the last checkpoint. */
848 /***************************************************************************/
849 jbuf->offset = jbuf->checkpoint;
850 jbuf->checkpoint = -1;