Initial VES for DANOS vRouter
[demo.git] / vnfs / VESreporting_vFW5.0_DANOS / evel / evel-library / code / evel_library / evel_json_buffer.c
1 /*************************************************************************//**
2  *
3  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
4  *
5  * Unless otherwise specified, all software contained herein is
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and 
15  * limitations under the License.
16  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
17  ****************************************************************************/
18
19 /**************************************************************************//**
20  * @file
21  * Source module relating to internal EVEL_JSON_BUFFER manipulation functions.
22  *
23  ****************************************************************************/
24
25 #include <assert.h>
26 #include <string.h>
27
28 #include "evel_throttle.h"
29
30 /*****************************************************************************/
31 /* Local prototypes.                                                         */
32 /*****************************************************************************/
33 static char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf);
34
35 /**************************************************************************//**
36  * Initialize a ::EVEL_JSON_BUFFER.
37  *
38  * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to initialise.
39  * @param json          Pointer to the underlying working buffer to use.
40  * @param max_size      Size of storage available in the JSON buffer.
41  * @param throttle_spec Pointer to throttle specification. Can be NULL.
42  *****************************************************************************/
43 void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf,
44                            char * const json,
45                            const int max_size,
46                            EVEL_THROTTLE_SPEC * throttle_spec)
47 {
48   EVEL_ENTER();
49
50   assert(jbuf != NULL);
51   assert(json != NULL);
52   jbuf->json = json;
53   jbuf->max_size = max_size;
54   jbuf->offset = 0;
55   jbuf->throttle_spec = throttle_spec;
56   jbuf->depth = 0;
57   jbuf->checkpoint = -1;
58
59   EVEL_EXIT();
60 }
61
62 /**************************************************************************//**
63  * Encode an integer value to a JSON buffer.
64  *
65  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
66  * @param value         The integer to add to it.
67  *****************************************************************************/
68 void evel_enc_int(EVEL_JSON_BUFFER * jbuf,
69                   const int value)
70 {
71   EVEL_ENTER();
72
73   /***************************************************************************/
74   /* Check preconditions.                                                    */
75   /***************************************************************************/
76   assert(jbuf != NULL);
77
78   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
79                            jbuf->max_size - jbuf->offset,
80                            "%d", value);
81
82   EVEL_EXIT();
83 }
84
85 /**************************************************************************//**
86  * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
87  *
88  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
89  * @param key           Pointer to the key to encode.
90  * @param option        Pointer to holder of the corresponding value to encode.
91  * @return true if the key, value was added, false if it was suppressed.
92  *****************************************************************************/
93 bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf,
94                             const char * const key,
95                             const EVEL_OPTION_STRING * const option)
96 {
97   bool added = false;
98
99   EVEL_ENTER();
100
101   /***************************************************************************/
102   /* Check preconditions.                                                    */
103   /***************************************************************************/
104   assert(option != NULL);
105
106   if (option->is_set)
107   {
108     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
109         (jbuf->throttle_spec != NULL) &&
110         evel_throttle_suppress_field(jbuf->throttle_spec, key))
111     {
112       EVEL_INFO("Suppressed: %s, %s", key, option->value);
113     }
114     else
115     {
116       EVEL_DEBUG("Encoded: %s, %s", key, option->value);
117       evel_enc_kv_string(jbuf, key, option->value);
118       added = true;
119     }
120   }
121
122   EVEL_EXIT();
123
124   return added;
125 }
126
127 /**************************************************************************//**
128  * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
129  *
130  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
131  * @param key           Pointer to the key to encode.
132  * @param value         Pointer to the corresponding value to encode.
133  *****************************************************************************/
134 void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf,
135                         const char * const key,
136                         const char * const value)
137 {
138   int index;
139   int length;
140
141   EVEL_ENTER();
142
143   /***************************************************************************/
144   /* Check preconditions.                                                    */
145   /***************************************************************************/
146   assert(jbuf != NULL);
147   assert(key != NULL);
148
149   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
150                            jbuf->max_size - jbuf->offset,
151                            "%s\"%s\": \"",
152                            evel_json_kv_comma(jbuf),
153                            key);
154
155   /***************************************************************************/
156   /* We need to escape quotation marks and backslashes in the value.         */
157   /***************************************************************************/
158   length = strlen(value);
159
160   for (index = 0; index < length; index++)
161   {
162     /*************************************************************************/
163     /* Drop out if no more space.                                            */
164     /*************************************************************************/
165     if (jbuf->max_size - jbuf->offset < 2)
166     {
167       break;
168     }
169
170     /*************************************************************************/
171     /* Add an escape character if necessary, then write the character        */
172     /* itself.                                                               */
173     /*************************************************************************/
174     if ((value[index] == '\"') || (value[index] == '\\'))
175     {
176       jbuf->json[jbuf->offset] = '\\';
177       jbuf->offset++;
178     }
179
180     jbuf->json[jbuf->offset] = value[index];
181     jbuf->offset++;
182   }
183
184   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
185                            jbuf->max_size - jbuf->offset,
186                            "\"");
187
188   EVEL_EXIT();
189 }
190
191
192 /**************************************************************************//**
193  * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
194  *
195  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
196  * @param key           Pointer to the key to encode.
197  * @param option        Pointer to holder of the corresponding value to encode.
198  * @return true if the key, value was added, false if it was suppressed.
199  *****************************************************************************/
200 bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
201                          const char * const key,
202                          const EVEL_OPTION_INT * const option)
203 {
204   bool added = false;
205
206   EVEL_ENTER();
207
208   /***************************************************************************/
209   /* Check preconditions.                                                    */
210   /***************************************************************************/
211   assert(option != NULL);
212
213   if (option->is_set)
214   {
215     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
216         (jbuf->throttle_spec != NULL) &&
217         evel_throttle_suppress_field(jbuf->throttle_spec, key))
218     {
219       EVEL_INFO("Suppressed: %s, %d", key, option->value);
220     }
221     else
222     {
223       EVEL_DEBUG("Encoded: %s, %d", key, option->value);
224       evel_enc_kv_int(jbuf, key, option->value);
225       added = true;
226     }
227   }
228
229   EVEL_EXIT();
230
231   return added;
232 }
233
234 /**************************************************************************//**
235  * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
236  *
237  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
238  * @param key           Pointer to the key to encode.
239  * @param value         The corresponding value to encode.
240  *****************************************************************************/
241 void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
242                      const char * const key,
243                      const int value)
244 {
245   EVEL_ENTER();
246
247   /***************************************************************************/
248   /* Check preconditions.                                                    */
249   /***************************************************************************/
250   assert(jbuf != NULL);
251   assert(key != NULL);
252
253   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
254                            jbuf->max_size - jbuf->offset,
255                            "%s\"%s\": %d",
256                            evel_json_kv_comma(jbuf),
257                            key,
258                            value);
259
260   EVEL_EXIT();
261 }
262
263 /**************************************************************************//**
264  * Encode a string key and json object value to a ::EVEL_JSON_BUFFER.
265  *
266  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
267  * @param key           Pointer to the key to encode.
268  * @param value         The corresponding json string to encode.
269  *****************************************************************************/
270 void evel_enc_kv_object(EVEL_JSON_BUFFER * jbuf,
271                      const char * const key,
272                      const char * value)
273 {
274   EVEL_ENTER();
275
276   /***************************************************************************/
277   /* Check preconditions.                                                    */
278   /***************************************************************************/
279   assert(jbuf != NULL);
280   assert(key != NULL);
281
282   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
283                            jbuf->max_size - jbuf->offset,
284                            "%s\"%s\": %s",
285                            evel_json_kv_comma(jbuf),
286                            key,
287                            value);
288
289   EVEL_EXIT();
290 }
291
292 /**************************************************************************//**
293  * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
294  *
295  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
296  * @param key           Pointer to the key to encode.
297  * @param option        Pointer to holder of the corresponding value to encode.
298  * @return true if the key, value was added, false if it was suppressed.
299  *****************************************************************************/
300 bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
301                             const char * const key,
302                             const EVEL_OPTION_DOUBLE * const option)
303 {
304   bool added = false;
305
306   EVEL_ENTER();
307
308   /***************************************************************************/
309   /* Check preconditions.                                                    */
310   /***************************************************************************/
311   assert(option != NULL);
312
313   if (option->is_set)
314   {
315     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
316         (jbuf->throttle_spec != NULL) &&
317         evel_throttle_suppress_field(jbuf->throttle_spec, key))
318     {
319       EVEL_INFO("Suppressed: %s, %1f", key, option->value);
320     }
321     else
322     {
323       EVEL_DEBUG("Encoded: %s, %1f", key, option->value);
324       evel_enc_kv_double(jbuf, key, option->value);
325       added = true;
326     }
327   }
328
329   EVEL_EXIT();
330
331   return added;
332 }
333
334 /**************************************************************************//**
335  * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
336  *
337  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
338  * @param key           Pointer to the key to encode.
339  * @param value         The corresponding value to encode.
340  *****************************************************************************/
341 void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
342                         const char * const key,
343                         const double value)
344 {
345   EVEL_ENTER();
346
347   /***************************************************************************/
348   /* Check preconditions.                                                    */
349   /***************************************************************************/
350   assert(jbuf != NULL);
351   assert(key != NULL);
352
353   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
354                            jbuf->max_size - jbuf->offset,
355                            "%s\"%s\": %1f",
356                            evel_json_kv_comma(jbuf),
357                            key,
358                            value);
359
360   EVEL_EXIT();
361 }
362
363 /**************************************************************************//**
364  * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
365  *
366  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
367  * @param key           Pointer to the key to encode.
368  * @param option        Pointer to holder of the corresponding value to encode.
369  * @return true if the key, value was added, false if it was suppressed.
370  *****************************************************************************/
371 bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
372                          const char * const key,
373                          const EVEL_OPTION_ULL * const option)
374 {
375   bool added = false;
376
377   EVEL_ENTER();
378
379   /***************************************************************************/
380   /* Check preconditions.                                                    */
381   /***************************************************************************/
382   assert(option != NULL);
383
384   if (option->is_set)
385   {
386     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
387         (jbuf->throttle_spec != NULL) &&
388         evel_throttle_suppress_field(jbuf->throttle_spec, key))
389     {
390       EVEL_INFO("Suppressed: %s, %1lu", key, option->value);
391     }
392     else
393     {
394       EVEL_DEBUG("Encoded: %s, %1lu", key, option->value);
395       evel_enc_kv_ull(jbuf, key, option->value);
396       added = true;
397     }
398   }
399
400   EVEL_EXIT();
401
402   return added;
403 }
404
405 /**************************************************************************//**
406  * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
407  *
408  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
409  * @param key           Pointer to the key to encode.
410  * @param value         The corresponding value to encode.
411  *****************************************************************************/
412 void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
413                      const char * const key,
414                      const unsigned long long value)
415 {
416   EVEL_ENTER();
417
418   /***************************************************************************/
419   /* Check preconditions.                                                    */
420   /***************************************************************************/
421   assert(jbuf != NULL);
422   assert(key != NULL);
423
424   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
425                            jbuf->max_size - jbuf->offset,
426                            "%s\"%s\": %llu",
427                            evel_json_kv_comma(jbuf),
428                            key,
429                            value);
430
431   EVEL_EXIT();
432 }
433
434 /**************************************************************************//**
435  * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
436  *
437  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
438  * @param key           Pointer to the key to encode.
439  * @param option        Pointer to holder of the corresponding value to encode.
440  * @return true if the key, value was added, false if it was suppressed.
441  *****************************************************************************/
442 bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
443                           const char * const key,
444                           const EVEL_OPTION_TIME * const option)
445 {
446   bool added = false;
447
448   EVEL_ENTER();
449
450   /***************************************************************************/
451   /* Check preconditions.                                                    */
452   /***************************************************************************/
453   assert(option != NULL);
454
455   if (option->is_set)
456   {
457     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
458         (jbuf->throttle_spec != NULL) &&
459         evel_throttle_suppress_field(jbuf->throttle_spec, key))
460     {
461       EVEL_INFO("Suppressed time: %s", key);
462     }
463     else
464     {
465       EVEL_DEBUG("Encoded time: %s", key);
466       evel_enc_kv_time(jbuf, key, &option->value);
467       added = true;
468     }
469   }
470
471   EVEL_EXIT();
472
473   return added;
474 }
475
476 /**************************************************************************//**
477  * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
478  *
479  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
480  * @param key           Pointer to the key to encode.
481  * @param time          Pointer to the time to encode.
482  *****************************************************************************/
483 void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
484                       const char * const key,
485                       const time_t * time)
486 {
487   EVEL_ENTER();
488
489   /***************************************************************************/
490   /* Check preconditions.                                                    */
491   /***************************************************************************/
492   assert(jbuf != NULL);
493   assert(key != NULL);
494   assert(time != NULL);
495
496   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
497                            jbuf->max_size - jbuf->offset,
498                            "%s\"%s\": \"",
499                            evel_json_kv_comma(jbuf),
500                            key);
501   jbuf->offset += strftime(jbuf->json + jbuf->offset,
502                            jbuf->max_size - jbuf->offset,
503                            EVEL_RFC2822_STRFTIME_FORMAT,
504                            localtime(time));
505   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
506                            jbuf->max_size - jbuf->offset,
507                            "\"");
508   EVEL_EXIT();
509 }
510
511 /**************************************************************************//**
512  * Encode a key and version.
513  *
514  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
515  * @param key           Pointer to the key to encode.
516  * @param major_version The major version to encode.
517  * @param minor_version The minor version to encode.
518  *****************************************************************************/
519 void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
520                       const char * const key,
521                       const int major_version,
522                       const int minor_version)
523 {
524   float ver;
525   EVEL_ENTER();
526
527   /***************************************************************************/
528   /* Check preconditions.                                                    */
529   /***************************************************************************/
530   assert(jbuf != NULL);
531   assert(key != NULL);
532
533   ver = (float)major_version + (float)minor_version/10.0;
534
535     jbuf->offset += snprintf(jbuf->json + jbuf->offset,
536                            jbuf->max_size - jbuf->offset,
537                            "%s\"%s\": %.1f",
538                            evel_json_kv_comma(jbuf),
539                            key,
540                            ver);
541
542   EVEL_EXIT();
543 }
544
545 /**************************************************************************//**
546  * Add the key and opening bracket of an optional named list to a JSON buffer.
547  *
548  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
549  * @param key           Pointer to the key to encode.
550  * @return true if the list was opened, false if it was suppressed.
551  *****************************************************************************/
552 bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
553                                    const char * const key)
554 {
555   bool opened = false;
556
557   EVEL_ENTER();
558
559   /***************************************************************************/
560   /* Check preconditions.                                                    */
561   /***************************************************************************/
562   assert(jbuf != NULL);
563   assert(key != NULL);
564
565   if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
566       (jbuf->throttle_spec != NULL) &&
567       evel_throttle_suppress_field(jbuf->throttle_spec, key))
568   {
569     EVEL_INFO("Suppressed: %s", key);
570     opened = false;
571   }
572   else
573   {
574     evel_json_open_named_list(jbuf, key);
575     opened = true;
576   }
577
578   EVEL_EXIT();
579
580   return opened;
581 }
582
583 /**************************************************************************//**
584  * Add the key and opening bracket of a named list to a JSON buffer.
585  *
586  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
587  * @param key           Pointer to the key to encode.
588  *****************************************************************************/
589 void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
590                                const char * const key)
591 {
592   EVEL_ENTER();
593
594   /***************************************************************************/
595   /* Check preconditions.                                                    */
596   /***************************************************************************/
597   assert(jbuf != NULL);
598   assert(key != NULL);
599
600   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
601                            jbuf->max_size - jbuf->offset,
602                            "%s\"%s\": [",
603                            evel_json_kv_comma(jbuf),
604                            key);
605   jbuf->depth++;
606
607   EVEL_EXIT();
608 }
609
610 /**************************************************************************//**
611  * Add the closing bracket of a list to a JSON buffer.
612  *
613  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
614  *****************************************************************************/
615 void evel_json_close_list(EVEL_JSON_BUFFER * jbuf)
616 {
617   EVEL_ENTER();
618
619   /***************************************************************************/
620   /* Check preconditions.                                                    */
621   /***************************************************************************/
622   assert(jbuf != NULL);
623
624   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
625                            jbuf->max_size - jbuf->offset,
626                            "]");
627   jbuf->depth--;
628
629   EVEL_EXIT();
630 }
631
632 /**************************************************************************//**
633  * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
634  *
635  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
636  * @param format        Format string in standard printf format.
637  * @param ...           Variable parameters for format string.
638  *****************************************************************************/
639 void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
640                         const char * const format,
641                         ...)
642 {
643   va_list largs;
644
645   EVEL_ENTER();
646
647   /***************************************************************************/
648   /* Check preconditions.                                                    */
649   /***************************************************************************/
650   assert(jbuf != NULL);
651   assert(format != NULL);
652
653   /***************************************************************************/
654   /* Add a comma unless we're at the start of the list.                      */
655   /***************************************************************************/
656   if (jbuf->json[jbuf->offset - 1] != '[')
657   {
658     jbuf->offset += snprintf(jbuf->json + jbuf->offset,
659                              jbuf->max_size - jbuf->offset,
660                              ", ");
661   }
662
663   va_start(largs, format);
664   jbuf->offset += vsnprintf(jbuf->json + jbuf->offset,
665                             jbuf->max_size - jbuf->offset,
666                             format,
667                             largs);
668   va_end(largs);
669
670   EVEL_EXIT();
671 }
672
673 /**************************************************************************//**
674  * Add the opening bracket of an optional named object to a JSON buffer.
675  *
676  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
677  * @param key           Pointer to the key to encode.
678  *****************************************************************************/
679 bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
680                                      const char * const key)
681 {
682   bool opened = false;
683
684   EVEL_ENTER();
685
686   /***************************************************************************/
687   /* Check preconditions.                                                    */
688   /***************************************************************************/
689   assert(jbuf != NULL);
690   assert(key != NULL);
691
692   if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
693       (jbuf->throttle_spec != NULL) &&
694       evel_throttle_suppress_field(jbuf->throttle_spec, key))
695   {
696     EVEL_INFO("Suppressed: %s", key);
697     opened = false;
698   }
699   else
700   {
701     evel_json_open_named_object(jbuf, key);
702     opened = true;
703   }
704
705   EVEL_EXIT();
706
707   return opened;
708 }
709
710 /**************************************************************************//**
711  * Add the opening bracket of an object to a JSON buffer.
712  *
713  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
714  * @param key           Pointer to the key to encode.
715  * @return true if the object was opened, false if it was suppressed.
716  *****************************************************************************/
717 void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
718                                  const char * const key)
719 {
720   EVEL_ENTER();
721
722   /***************************************************************************/
723   /* Check preconditions.                                                    */
724   /***************************************************************************/
725   assert(jbuf != NULL);
726   assert(key != NULL);
727
728   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
729                            jbuf->max_size - jbuf->offset,
730                            "%s\"%s\": {",
731                            evel_json_kv_comma(jbuf),
732                            key);
733   jbuf->depth++;
734
735   EVEL_EXIT();
736 }
737
738 /**************************************************************************//**
739  * Add the opening bracket of an object to a JSON buffer.
740  *
741  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
742  *****************************************************************************/
743 void evel_json_open_object(EVEL_JSON_BUFFER * jbuf)
744 {
745   char * comma;
746
747   EVEL_ENTER();
748
749   /***************************************************************************/
750   /* Check preconditions.                                                    */
751   /***************************************************************************/
752   assert(jbuf != NULL);
753
754   if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}'))
755   {
756     comma = ", ";
757   }
758   else
759   {
760     comma = "";
761   }
762
763   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
764                            jbuf->max_size - jbuf->offset,
765                            "%s{",
766                            comma);
767   jbuf->depth++;
768
769   EVEL_EXIT();
770 }
771
772 /**************************************************************************//**
773  * Add the closing bracket of an object to a JSON buffer.
774  *
775  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
776  *****************************************************************************/
777 void evel_json_close_object(EVEL_JSON_BUFFER * jbuf)
778 {
779   EVEL_ENTER();
780
781   /***************************************************************************/
782   /* Check preconditions.                                                    */
783   /***************************************************************************/
784   assert(jbuf != NULL);
785
786   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
787                            jbuf->max_size - jbuf->offset,
788                            "}");
789   jbuf->depth--;
790
791   EVEL_EXIT();
792 }
793
794 /**************************************************************************//**
795  * Determine whether to add a comma when adding a key-value pair.
796  *
797  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
798  * @returns A string containing the comma if it is required.
799  *****************************************************************************/
800 char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf)
801 {
802   char * result;
803
804   EVEL_ENTER();
805
806   /***************************************************************************/
807   /* Check preconditions.                                                    */
808   /***************************************************************************/
809   assert(jbuf != NULL);
810
811   if ((jbuf->offset == 0) ||
812       (jbuf->json[jbuf->offset-1] == '{') ||
813       (jbuf->json[jbuf->offset-1] == '['))
814   {
815     result = "";
816   }
817   else
818   {
819     result = ", ";
820   }
821
822   EVEL_EXIT();
823
824   return result;
825 }
826
827 /**************************************************************************//**
828  * Add a checkpoint - a stake in the ground to which we can rewind.
829  *
830  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
831  *****************************************************************************/
832 void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf)
833 {
834   EVEL_ENTER();
835
836   /***************************************************************************/
837   /* Check preconditions.                                                    */
838   /***************************************************************************/
839   assert(jbuf != NULL);
840
841   /***************************************************************************/
842   /* Store the current offset.                                               */
843   /***************************************************************************/
844   jbuf->checkpoint = jbuf->offset;
845
846   EVEL_EXIT();
847 }
848
849 /**************************************************************************//**
850  * Rewind to the latest checkoint.
851  *
852  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
853  *****************************************************************************/
854 void evel_json_rewind(EVEL_JSON_BUFFER * jbuf)
855 {
856   EVEL_ENTER();
857
858   /***************************************************************************/
859   /* Check preconditions.                                                    */
860   /***************************************************************************/
861   assert(jbuf != NULL);
862   assert(jbuf->checkpoint >= 0);
863   assert(jbuf->checkpoint <= jbuf->offset);
864
865   /***************************************************************************/
866   /* Reinstate the offset from the last checkpoint.                          */
867   /***************************************************************************/
868   jbuf->offset = jbuf->checkpoint;
869   jbuf->checkpoint = -1;
870
871   EVEL_EXIT();
872 }