1 /*************************************************************************//**
3 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 ****************************************************************************/
18 /**************************************************************************//**
20 * Source module relating to internal EVEL_JSON_BUFFER manipulation functions.
22 ****************************************************************************/
27 #include "evel_throttle.h"
29 /*****************************************************************************/
30 /* Local prototypes. */
31 /*****************************************************************************/
32 static char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf);
34 /**************************************************************************//**
35 * Initialize a ::EVEL_JSON_BUFFER.
37 * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to initialise.
38 * @param json Pointer to the underlying working buffer to use.
39 * @param max_size Size of storage available in the JSON buffer.
40 * @param throttle_spec Pointer to throttle specification. Can be NULL.
41 *****************************************************************************/
42 void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf,
45 EVEL_THROTTLE_SPEC * throttle_spec)
52 jbuf->max_size = max_size;
54 jbuf->throttle_spec = throttle_spec;
56 jbuf->checkpoint = -1;
61 /**************************************************************************//**
62 * Encode an integer value to a JSON buffer.
64 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
65 * @param value The integer to add to it.
66 *****************************************************************************/
67 void evel_enc_int(EVEL_JSON_BUFFER * jbuf,
72 /***************************************************************************/
73 /* Check preconditions. */
74 /***************************************************************************/
77 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
78 jbuf->max_size - jbuf->offset,
84 /**************************************************************************//**
85 * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
87 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
88 * @param key Pointer to the key to encode.
89 * @param option Pointer to holder of the corresponding value to encode.
90 * @return true if the key, value was added, false if it was suppressed.
91 *****************************************************************************/
92 bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf,
93 const char * const key,
94 const EVEL_OPTION_STRING * const option)
100 /***************************************************************************/
101 /* Check preconditions. */
102 /***************************************************************************/
103 assert(option != NULL);
107 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
108 (jbuf->throttle_spec != NULL) &&
109 evel_throttle_suppress_field(jbuf->throttle_spec, key))
111 EVEL_INFO("Suppressed: %s, %s", key, option->value);
115 EVEL_DEBUG("Encoded: %s, %s", key, option->value);
116 evel_enc_kv_string(jbuf, key, option->value);
126 /**************************************************************************//**
127 * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
129 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
130 * @param key Pointer to the key to encode.
131 * @param value Pointer to the corresponding value to encode.
132 *****************************************************************************/
133 void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf,
134 const char * const key,
135 const char * const value)
142 /***************************************************************************/
143 /* Check preconditions. */
144 /***************************************************************************/
145 assert(jbuf != NULL);
148 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
149 jbuf->max_size - jbuf->offset,
151 evel_json_kv_comma(jbuf),
154 /***************************************************************************/
155 /* We need to escape quotation marks and backslashes in the value. */
156 /***************************************************************************/
157 length = strlen(value);
159 for (index = 0; index < length; index++)
161 /*************************************************************************/
162 /* Drop out if no more space. */
163 /*************************************************************************/
164 if (jbuf->max_size - jbuf->offset < 2)
169 /*************************************************************************/
170 /* Add an escape character if necessary, then write the character */
172 /*************************************************************************/
173 if ((value[index] == '\"') || (value[index] == '\\'))
175 jbuf->json[jbuf->offset] = '\\';
179 jbuf->json[jbuf->offset] = value[index];
183 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
184 jbuf->max_size - jbuf->offset,
191 /**************************************************************************//**
192 * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
194 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
195 * @param key Pointer to the key to encode.
196 * @param option Pointer to holder of the corresponding value to encode.
197 * @return true if the key, value was added, false if it was suppressed.
198 *****************************************************************************/
199 bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
200 const char * const key,
201 const EVEL_OPTION_INT * const option)
207 /***************************************************************************/
208 /* Check preconditions. */
209 /***************************************************************************/
210 assert(option != NULL);
214 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
215 (jbuf->throttle_spec != NULL) &&
216 evel_throttle_suppress_field(jbuf->throttle_spec, key))
218 EVEL_INFO("Suppressed: %s, %d", key, option->value);
222 EVEL_DEBUG("Encoded: %s, %d", key, option->value);
223 evel_enc_kv_int(jbuf, key, option->value);
233 /**************************************************************************//**
234 * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
236 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
237 * @param key Pointer to the key to encode.
238 * @param value The corresponding value to encode.
239 *****************************************************************************/
240 void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
241 const char * const key,
246 /***************************************************************************/
247 /* Check preconditions. */
248 /***************************************************************************/
249 assert(jbuf != NULL);
252 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
253 jbuf->max_size - jbuf->offset,
255 evel_json_kv_comma(jbuf),
262 /**************************************************************************//**
263 * Encode a string key and json object value to a ::EVEL_JSON_BUFFER.
265 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
266 * @param key Pointer to the key to encode.
267 * @param value The corresponding json string to encode.
268 *****************************************************************************/
269 void evel_enc_kv_object(EVEL_JSON_BUFFER * jbuf,
270 const char * const key,
275 /***************************************************************************/
276 /* Check preconditions. */
277 /***************************************************************************/
278 assert(jbuf != NULL);
281 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
282 jbuf->max_size - jbuf->offset,
284 evel_json_kv_comma(jbuf),
291 /**************************************************************************//**
292 * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
294 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
295 * @param key Pointer to the key to encode.
296 * @param option Pointer to holder of the corresponding value to encode.
297 * @return true if the key, value was added, false if it was suppressed.
298 *****************************************************************************/
299 bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
300 const char * const key,
301 const EVEL_OPTION_DOUBLE * const option)
307 /***************************************************************************/
308 /* Check preconditions. */
309 /***************************************************************************/
310 assert(option != NULL);
314 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
315 (jbuf->throttle_spec != NULL) &&
316 evel_throttle_suppress_field(jbuf->throttle_spec, key))
318 EVEL_INFO("Suppressed: %s, %1f", key, option->value);
322 EVEL_DEBUG("Encoded: %s, %1f", key, option->value);
323 evel_enc_kv_double(jbuf, key, option->value);
333 /**************************************************************************//**
334 * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
336 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
337 * @param key Pointer to the key to encode.
338 * @param value The corresponding value to encode.
339 *****************************************************************************/
340 void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
341 const char * const key,
346 /***************************************************************************/
347 /* Check preconditions. */
348 /***************************************************************************/
349 assert(jbuf != NULL);
352 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
353 jbuf->max_size - jbuf->offset,
355 evel_json_kv_comma(jbuf),
362 /**************************************************************************//**
363 * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
365 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
366 * @param key Pointer to the key to encode.
367 * @param option Pointer to holder of the corresponding value to encode.
368 * @return true if the key, value was added, false if it was suppressed.
369 *****************************************************************************/
370 bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
371 const char * const key,
372 const EVEL_OPTION_ULL * const option)
378 /***************************************************************************/
379 /* Check preconditions. */
380 /***************************************************************************/
381 assert(option != NULL);
385 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
386 (jbuf->throttle_spec != NULL) &&
387 evel_throttle_suppress_field(jbuf->throttle_spec, key))
389 EVEL_INFO("Suppressed: %s, %1lu", key, option->value);
393 EVEL_DEBUG("Encoded: %s, %1lu", key, option->value);
394 evel_enc_kv_ull(jbuf, key, option->value);
404 /**************************************************************************//**
405 * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
407 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
408 * @param key Pointer to the key to encode.
409 * @param value The corresponding value to encode.
410 *****************************************************************************/
411 void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
412 const char * const key,
413 const unsigned long long value)
417 /***************************************************************************/
418 /* Check preconditions. */
419 /***************************************************************************/
420 assert(jbuf != NULL);
423 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
424 jbuf->max_size - jbuf->offset,
426 evel_json_kv_comma(jbuf),
433 /**************************************************************************//**
434 * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
436 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
437 * @param key Pointer to the key to encode.
438 * @param option Pointer to holder of the corresponding value to encode.
439 * @return true if the key, value was added, false if it was suppressed.
440 *****************************************************************************/
441 bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
442 const char * const key,
443 const EVEL_OPTION_TIME * const option)
449 /***************************************************************************/
450 /* Check preconditions. */
451 /***************************************************************************/
452 assert(option != NULL);
456 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
457 (jbuf->throttle_spec != NULL) &&
458 evel_throttle_suppress_field(jbuf->throttle_spec, key))
460 EVEL_INFO("Suppressed time: %s", key);
464 EVEL_DEBUG("Encoded time: %s", key);
465 evel_enc_kv_time(jbuf, key, &option->value);
475 /**************************************************************************//**
476 * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
478 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
479 * @param key Pointer to the key to encode.
480 * @param time Pointer to the time to encode.
481 *****************************************************************************/
482 void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
483 const char * const key,
488 /***************************************************************************/
489 /* Check preconditions. */
490 /***************************************************************************/
491 assert(jbuf != NULL);
493 assert(time != NULL);
495 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
496 jbuf->max_size - jbuf->offset,
498 evel_json_kv_comma(jbuf),
500 jbuf->offset += strftime(jbuf->json + jbuf->offset,
501 jbuf->max_size - jbuf->offset,
502 EVEL_RFC2822_STRFTIME_FORMAT,
504 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
505 jbuf->max_size - jbuf->offset,
510 /**************************************************************************//**
511 * Encode a key and version.
513 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
514 * @param key Pointer to the key to encode.
515 * @param major_version The major version to encode.
516 * @param minor_version The minor version to encode.
517 *****************************************************************************/
518 void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
519 const char * const key,
520 const int major_version,
521 const int minor_version)
525 /***************************************************************************/
526 /* Check preconditions. */
527 /***************************************************************************/
528 assert(jbuf != NULL);
531 evel_enc_kv_int(jbuf, key, major_version);
532 if (minor_version != 0)
534 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
535 jbuf->max_size - jbuf->offset,
543 /**************************************************************************//**
544 * Add the key and opening bracket of an optional named list to a JSON buffer.
546 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
547 * @param key Pointer to the key to encode.
548 * @return true if the list was opened, false if it was suppressed.
549 *****************************************************************************/
550 bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
551 const char * const key)
557 /***************************************************************************/
558 /* Check preconditions. */
559 /***************************************************************************/
560 assert(jbuf != NULL);
563 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
564 (jbuf->throttle_spec != NULL) &&
565 evel_throttle_suppress_field(jbuf->throttle_spec, key))
567 EVEL_INFO("Suppressed: %s", key);
572 evel_json_open_named_list(jbuf, key);
581 /**************************************************************************//**
582 * Add the key and opening bracket of a named list to a JSON buffer.
584 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
585 * @param key Pointer to the key to encode.
586 *****************************************************************************/
587 void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
588 const char * const key)
592 /***************************************************************************/
593 /* Check preconditions. */
594 /***************************************************************************/
595 assert(jbuf != NULL);
598 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
599 jbuf->max_size - jbuf->offset,
601 evel_json_kv_comma(jbuf),
608 /**************************************************************************//**
609 * Add the closing bracket of a list to a JSON buffer.
611 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
612 *****************************************************************************/
613 void evel_json_close_list(EVEL_JSON_BUFFER * jbuf)
617 /***************************************************************************/
618 /* Check preconditions. */
619 /***************************************************************************/
620 assert(jbuf != NULL);
622 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
623 jbuf->max_size - jbuf->offset,
630 /**************************************************************************//**
631 * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
633 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
634 * @param format Format string in standard printf format.
635 * @param ... Variable parameters for format string.
636 *****************************************************************************/
637 void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
638 const char * const format,
645 /***************************************************************************/
646 /* Check preconditions. */
647 /***************************************************************************/
648 assert(jbuf != NULL);
649 assert(format != NULL);
651 /***************************************************************************/
652 /* Add a comma unless we're at the start of the list. */
653 /***************************************************************************/
654 if (jbuf->json[jbuf->offset - 1] != '[')
656 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
657 jbuf->max_size - jbuf->offset,
661 va_start(largs, format);
662 jbuf->offset += vsnprintf(jbuf->json + jbuf->offset,
663 jbuf->max_size - jbuf->offset,
671 /**************************************************************************//**
672 * Add the opening bracket of an optional named object to a JSON buffer.
674 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
675 * @param key Pointer to the key to encode.
676 *****************************************************************************/
677 bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
678 const char * const key)
684 /***************************************************************************/
685 /* Check preconditions. */
686 /***************************************************************************/
687 assert(jbuf != NULL);
690 if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
691 (jbuf->throttle_spec != NULL) &&
692 evel_throttle_suppress_field(jbuf->throttle_spec, key))
694 EVEL_INFO("Suppressed: %s", key);
699 evel_json_open_named_object(jbuf, key);
708 /**************************************************************************//**
709 * Add the opening bracket of an object to a JSON buffer.
711 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
712 * @param key Pointer to the key to encode.
713 * @return true if the object was opened, false if it was suppressed.
714 *****************************************************************************/
715 void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
716 const char * const key)
720 /***************************************************************************/
721 /* Check preconditions. */
722 /***************************************************************************/
723 assert(jbuf != NULL);
726 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
727 jbuf->max_size - jbuf->offset,
729 evel_json_kv_comma(jbuf),
736 /**************************************************************************//**
737 * Add the opening bracket of an object to a JSON buffer.
739 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
740 *****************************************************************************/
741 void evel_json_open_object(EVEL_JSON_BUFFER * jbuf)
747 /***************************************************************************/
748 /* Check preconditions. */
749 /***************************************************************************/
750 assert(jbuf != NULL);
752 if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}'))
761 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
762 jbuf->max_size - jbuf->offset,
770 /**************************************************************************//**
771 * Add the closing bracket of an object to a JSON buffer.
773 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
774 *****************************************************************************/
775 void evel_json_close_object(EVEL_JSON_BUFFER * jbuf)
779 /***************************************************************************/
780 /* Check preconditions. */
781 /***************************************************************************/
782 assert(jbuf != NULL);
784 jbuf->offset += snprintf(jbuf->json + jbuf->offset,
785 jbuf->max_size - jbuf->offset,
792 /**************************************************************************//**
793 * Determine whether to add a comma when adding a key-value pair.
795 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
796 * @returns A string containing the comma if it is required.
797 *****************************************************************************/
798 char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf)
804 /***************************************************************************/
805 /* Check preconditions. */
806 /***************************************************************************/
807 assert(jbuf != NULL);
809 if ((jbuf->offset == 0) ||
810 (jbuf->json[jbuf->offset-1] == '{') ||
811 (jbuf->json[jbuf->offset-1] == '['))
825 /**************************************************************************//**
826 * Add a checkpoint - a stake in the ground to which we can rewind.
828 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
829 *****************************************************************************/
830 void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf)
834 /***************************************************************************/
835 /* Check preconditions. */
836 /***************************************************************************/
837 assert(jbuf != NULL);
839 /***************************************************************************/
840 /* Store the current offset. */
841 /***************************************************************************/
842 jbuf->checkpoint = jbuf->offset;
847 /**************************************************************************//**
848 * Rewind to the latest checkoint.
850 * @param jbuf Pointer to working ::EVEL_JSON_BUFFER.
851 *****************************************************************************/
852 void evel_json_rewind(EVEL_JSON_BUFFER * jbuf)
856 /***************************************************************************/
857 /* Check preconditions. */
858 /***************************************************************************/
859 assert(jbuf != NULL);
860 assert(jbuf->checkpoint >= 0);
861 assert(jbuf->checkpoint <= jbuf->offset);
863 /***************************************************************************/
864 /* Reinstate the offset from the last checkpoint. */
865 /***************************************************************************/
866 jbuf->offset = jbuf->checkpoint;
867 jbuf->checkpoint = -1;