Cleanup code and correct License
[demo.git] / vnfs / VES5.0 / evel / evel-library / code / evel_library / evel_json_buffer.c
1 /*************************************************************************//**
2  *
3  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
4  *
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
9  *
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.
15  *
16  ****************************************************************************/
17
18 /**************************************************************************//**
19  * @file
20  * Source module relating to internal EVEL_JSON_BUFFER manipulation functions.
21  *
22  ****************************************************************************/
23
24 #include <assert.h>
25 #include <string.h>
26
27 #include "evel_throttle.h"
28
29 /*****************************************************************************/
30 /* Local prototypes.                                                         */
31 /*****************************************************************************/
32 static char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf);
33
34 /**************************************************************************//**
35  * Initialize a ::EVEL_JSON_BUFFER.
36  *
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,
43                            char * const json,
44                            const int max_size,
45                            EVEL_THROTTLE_SPEC * throttle_spec)
46 {
47   EVEL_ENTER();
48
49   assert(jbuf != NULL);
50   assert(json != NULL);
51   jbuf->json = json;
52   jbuf->max_size = max_size;
53   jbuf->offset = 0;
54   jbuf->throttle_spec = throttle_spec;
55   jbuf->depth = 0;
56   jbuf->checkpoint = -1;
57
58   EVEL_EXIT();
59 }
60
61 /**************************************************************************//**
62  * Encode an integer value to a JSON buffer.
63  *
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,
68                   const int value)
69 {
70   EVEL_ENTER();
71
72   /***************************************************************************/
73   /* Check preconditions.                                                    */
74   /***************************************************************************/
75   assert(jbuf != NULL);
76
77   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
78                            jbuf->max_size - jbuf->offset,
79                            "%d", value);
80
81   EVEL_EXIT();
82 }
83
84 /**************************************************************************//**
85  * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
86  *
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)
95 {
96   bool added = false;
97
98   EVEL_ENTER();
99
100   /***************************************************************************/
101   /* Check preconditions.                                                    */
102   /***************************************************************************/
103   assert(option != NULL);
104
105   if (option->is_set)
106   {
107     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
108         (jbuf->throttle_spec != NULL) &&
109         evel_throttle_suppress_field(jbuf->throttle_spec, key))
110     {
111       EVEL_INFO("Suppressed: %s, %s", key, option->value);
112     }
113     else
114     {
115       EVEL_DEBUG("Encoded: %s, %s", key, option->value);
116       evel_enc_kv_string(jbuf, key, option->value);
117       added = true;
118     }
119   }
120
121   EVEL_EXIT();
122
123   return added;
124 }
125
126 /**************************************************************************//**
127  * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
128  *
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)
136 {
137   int index;
138   int length;
139
140   EVEL_ENTER();
141
142   /***************************************************************************/
143   /* Check preconditions.                                                    */
144   /***************************************************************************/
145   assert(jbuf != NULL);
146   assert(key != NULL);
147
148   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
149                            jbuf->max_size - jbuf->offset,
150                            "%s\"%s\": \"",
151                            evel_json_kv_comma(jbuf),
152                            key);
153
154   /***************************************************************************/
155   /* We need to escape quotation marks and backslashes in the value.         */
156   /***************************************************************************/
157   length = strlen(value);
158
159   for (index = 0; index < length; index++)
160   {
161     /*************************************************************************/
162     /* Drop out if no more space.                                            */
163     /*************************************************************************/
164     if (jbuf->max_size - jbuf->offset < 2)
165     {
166       break;
167     }
168
169     /*************************************************************************/
170     /* Add an escape character if necessary, then write the character        */
171     /* itself.                                                               */
172     /*************************************************************************/
173     if ((value[index] == '\"') || (value[index] == '\\'))
174     {
175       jbuf->json[jbuf->offset] = '\\';
176       jbuf->offset++;
177     }
178
179     jbuf->json[jbuf->offset] = value[index];
180     jbuf->offset++;
181   }
182
183   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
184                            jbuf->max_size - jbuf->offset,
185                            "\"");
186
187   EVEL_EXIT();
188 }
189
190
191 /**************************************************************************//**
192  * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
193  *
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)
202 {
203   bool added = false;
204
205   EVEL_ENTER();
206
207   /***************************************************************************/
208   /* Check preconditions.                                                    */
209   /***************************************************************************/
210   assert(option != NULL);
211
212   if (option->is_set)
213   {
214     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
215         (jbuf->throttle_spec != NULL) &&
216         evel_throttle_suppress_field(jbuf->throttle_spec, key))
217     {
218       EVEL_INFO("Suppressed: %s, %d", key, option->value);
219     }
220     else
221     {
222       EVEL_DEBUG("Encoded: %s, %d", key, option->value);
223       evel_enc_kv_int(jbuf, key, option->value);
224       added = true;
225     }
226   }
227
228   EVEL_EXIT();
229
230   return added;
231 }
232
233 /**************************************************************************//**
234  * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
235  *
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,
242                      const int value)
243 {
244   EVEL_ENTER();
245
246   /***************************************************************************/
247   /* Check preconditions.                                                    */
248   /***************************************************************************/
249   assert(jbuf != NULL);
250   assert(key != NULL);
251
252   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
253                            jbuf->max_size - jbuf->offset,
254                            "%s\"%s\": %d",
255                            evel_json_kv_comma(jbuf),
256                            key,
257                            value);
258
259   EVEL_EXIT();
260 }
261
262 /**************************************************************************//**
263  * Encode a string key and json object value to a ::EVEL_JSON_BUFFER.
264  *
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,
271                      const char * value)
272 {
273   EVEL_ENTER();
274
275   /***************************************************************************/
276   /* Check preconditions.                                                    */
277   /***************************************************************************/
278   assert(jbuf != NULL);
279   assert(key != NULL);
280
281   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
282                            jbuf->max_size - jbuf->offset,
283                            "%s\"%s\": %s",
284                            evel_json_kv_comma(jbuf),
285                            key,
286                            value);
287
288   EVEL_EXIT();
289 }
290
291 /**************************************************************************//**
292  * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
293  *
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)
302 {
303   bool added = false;
304
305   EVEL_ENTER();
306
307   /***************************************************************************/
308   /* Check preconditions.                                                    */
309   /***************************************************************************/
310   assert(option != NULL);
311
312   if (option->is_set)
313   {
314     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
315         (jbuf->throttle_spec != NULL) &&
316         evel_throttle_suppress_field(jbuf->throttle_spec, key))
317     {
318       EVEL_INFO("Suppressed: %s, %1f", key, option->value);
319     }
320     else
321     {
322       EVEL_DEBUG("Encoded: %s, %1f", key, option->value);
323       evel_enc_kv_double(jbuf, key, option->value);
324       added = true;
325     }
326   }
327
328   EVEL_EXIT();
329
330   return added;
331 }
332
333 /**************************************************************************//**
334  * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
335  *
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,
342                         const double value)
343 {
344   EVEL_ENTER();
345
346   /***************************************************************************/
347   /* Check preconditions.                                                    */
348   /***************************************************************************/
349   assert(jbuf != NULL);
350   assert(key != NULL);
351
352   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
353                            jbuf->max_size - jbuf->offset,
354                            "%s\"%s\": %1f",
355                            evel_json_kv_comma(jbuf),
356                            key,
357                            value);
358
359   EVEL_EXIT();
360 }
361
362 /**************************************************************************//**
363  * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
364  *
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)
373 {
374   bool added = false;
375
376   EVEL_ENTER();
377
378   /***************************************************************************/
379   /* Check preconditions.                                                    */
380   /***************************************************************************/
381   assert(option != NULL);
382
383   if (option->is_set)
384   {
385     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
386         (jbuf->throttle_spec != NULL) &&
387         evel_throttle_suppress_field(jbuf->throttle_spec, key))
388     {
389       EVEL_INFO("Suppressed: %s, %1lu", key, option->value);
390     }
391     else
392     {
393       EVEL_DEBUG("Encoded: %s, %1lu", key, option->value);
394       evel_enc_kv_ull(jbuf, key, option->value);
395       added = true;
396     }
397   }
398
399   EVEL_EXIT();
400
401   return added;
402 }
403
404 /**************************************************************************//**
405  * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
406  *
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)
414 {
415   EVEL_ENTER();
416
417   /***************************************************************************/
418   /* Check preconditions.                                                    */
419   /***************************************************************************/
420   assert(jbuf != NULL);
421   assert(key != NULL);
422
423   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
424                            jbuf->max_size - jbuf->offset,
425                            "%s\"%s\": %llu",
426                            evel_json_kv_comma(jbuf),
427                            key,
428                            value);
429
430   EVEL_EXIT();
431 }
432
433 /**************************************************************************//**
434  * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
435  *
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)
444 {
445   bool added = false;
446
447   EVEL_ENTER();
448
449   /***************************************************************************/
450   /* Check preconditions.                                                    */
451   /***************************************************************************/
452   assert(option != NULL);
453
454   if (option->is_set)
455   {
456     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
457         (jbuf->throttle_spec != NULL) &&
458         evel_throttle_suppress_field(jbuf->throttle_spec, key))
459     {
460       EVEL_INFO("Suppressed time: %s", key);
461     }
462     else
463     {
464       EVEL_DEBUG("Encoded time: %s", key);
465       evel_enc_kv_time(jbuf, key, &option->value);
466       added = true;
467     }
468   }
469
470   EVEL_EXIT();
471
472   return added;
473 }
474
475 /**************************************************************************//**
476  * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
477  *
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,
484                       const time_t * time)
485 {
486   EVEL_ENTER();
487
488   /***************************************************************************/
489   /* Check preconditions.                                                    */
490   /***************************************************************************/
491   assert(jbuf != NULL);
492   assert(key != NULL);
493   assert(time != NULL);
494
495   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
496                            jbuf->max_size - jbuf->offset,
497                            "%s\"%s\": \"",
498                            evel_json_kv_comma(jbuf),
499                            key);
500   jbuf->offset += strftime(jbuf->json + jbuf->offset,
501                            jbuf->max_size - jbuf->offset,
502                            EVEL_RFC2822_STRFTIME_FORMAT,
503                            localtime(time));
504   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
505                            jbuf->max_size - jbuf->offset,
506                            "\"");
507   EVEL_EXIT();
508 }
509
510 /**************************************************************************//**
511  * Encode a key and version.
512  *
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)
522 {
523   EVEL_ENTER();
524
525   /***************************************************************************/
526   /* Check preconditions.                                                    */
527   /***************************************************************************/
528   assert(jbuf != NULL);
529   assert(key != NULL);
530
531   evel_enc_kv_int(jbuf, key, major_version);
532   if (minor_version != 0)
533   {
534     jbuf->offset += snprintf(jbuf->json + jbuf->offset,
535                              jbuf->max_size - jbuf->offset,
536                              ".%d",
537                              minor_version);
538   }
539
540   EVEL_EXIT();
541 }
542
543 /**************************************************************************//**
544  * Add the key and opening bracket of an optional named list to a JSON buffer.
545  *
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)
552 {
553   bool opened = false;
554
555   EVEL_ENTER();
556
557   /***************************************************************************/
558   /* Check preconditions.                                                    */
559   /***************************************************************************/
560   assert(jbuf != NULL);
561   assert(key != NULL);
562
563   if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
564       (jbuf->throttle_spec != NULL) &&
565       evel_throttle_suppress_field(jbuf->throttle_spec, key))
566   {
567     EVEL_INFO("Suppressed: %s", key);
568     opened = false;
569   }
570   else
571   {
572     evel_json_open_named_list(jbuf, key);
573     opened = true;
574   }
575
576   EVEL_EXIT();
577
578   return opened;
579 }
580
581 /**************************************************************************//**
582  * Add the key and opening bracket of a named list to a JSON buffer.
583  *
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)
589 {
590   EVEL_ENTER();
591
592   /***************************************************************************/
593   /* Check preconditions.                                                    */
594   /***************************************************************************/
595   assert(jbuf != NULL);
596   assert(key != NULL);
597
598   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
599                            jbuf->max_size - jbuf->offset,
600                            "%s\"%s\": [",
601                            evel_json_kv_comma(jbuf),
602                            key);
603   jbuf->depth++;
604
605   EVEL_EXIT();
606 }
607
608 /**************************************************************************//**
609  * Add the closing bracket of a list to a JSON buffer.
610  *
611  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
612  *****************************************************************************/
613 void evel_json_close_list(EVEL_JSON_BUFFER * jbuf)
614 {
615   EVEL_ENTER();
616
617   /***************************************************************************/
618   /* Check preconditions.                                                    */
619   /***************************************************************************/
620   assert(jbuf != NULL);
621
622   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
623                            jbuf->max_size - jbuf->offset,
624                            "]");
625   jbuf->depth--;
626
627   EVEL_EXIT();
628 }
629
630 /**************************************************************************//**
631  * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
632  *
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,
639                         ...)
640 {
641   va_list largs;
642
643   EVEL_ENTER();
644
645   /***************************************************************************/
646   /* Check preconditions.                                                    */
647   /***************************************************************************/
648   assert(jbuf != NULL);
649   assert(format != NULL);
650
651   /***************************************************************************/
652   /* Add a comma unless we're at the start of the list.                      */
653   /***************************************************************************/
654   if (jbuf->json[jbuf->offset - 1] != '[')
655   {
656     jbuf->offset += snprintf(jbuf->json + jbuf->offset,
657                              jbuf->max_size - jbuf->offset,
658                              ", ");
659   }
660
661   va_start(largs, format);
662   jbuf->offset += vsnprintf(jbuf->json + jbuf->offset,
663                             jbuf->max_size - jbuf->offset,
664                             format,
665                             largs);
666   va_end(largs);
667
668   EVEL_EXIT();
669 }
670
671 /**************************************************************************//**
672  * Add the opening bracket of an optional named object to a JSON buffer.
673  *
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)
679 {
680   bool opened = false;
681
682   EVEL_ENTER();
683
684   /***************************************************************************/
685   /* Check preconditions.                                                    */
686   /***************************************************************************/
687   assert(jbuf != NULL);
688   assert(key != NULL);
689
690   if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
691       (jbuf->throttle_spec != NULL) &&
692       evel_throttle_suppress_field(jbuf->throttle_spec, key))
693   {
694     EVEL_INFO("Suppressed: %s", key);
695     opened = false;
696   }
697   else
698   {
699     evel_json_open_named_object(jbuf, key);
700     opened = true;
701   }
702
703   EVEL_EXIT();
704
705   return opened;
706 }
707
708 /**************************************************************************//**
709  * Add the opening bracket of an object to a JSON buffer.
710  *
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)
717 {
718   EVEL_ENTER();
719
720   /***************************************************************************/
721   /* Check preconditions.                                                    */
722   /***************************************************************************/
723   assert(jbuf != NULL);
724   assert(key != NULL);
725
726   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
727                            jbuf->max_size - jbuf->offset,
728                            "%s\"%s\": {",
729                            evel_json_kv_comma(jbuf),
730                            key);
731   jbuf->depth++;
732
733   EVEL_EXIT();
734 }
735
736 /**************************************************************************//**
737  * Add the opening bracket of an object to a JSON buffer.
738  *
739  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
740  *****************************************************************************/
741 void evel_json_open_object(EVEL_JSON_BUFFER * jbuf)
742 {
743   char * comma;
744
745   EVEL_ENTER();
746
747   /***************************************************************************/
748   /* Check preconditions.                                                    */
749   /***************************************************************************/
750   assert(jbuf != NULL);
751
752   if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}'))
753   {
754     comma = ", ";
755   }
756   else
757   {
758     comma = "";
759   }
760
761   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
762                            jbuf->max_size - jbuf->offset,
763                            "%s{",
764                            comma);
765   jbuf->depth++;
766
767   EVEL_EXIT();
768 }
769
770 /**************************************************************************//**
771  * Add the closing bracket of an object to a JSON buffer.
772  *
773  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
774  *****************************************************************************/
775 void evel_json_close_object(EVEL_JSON_BUFFER * jbuf)
776 {
777   EVEL_ENTER();
778
779   /***************************************************************************/
780   /* Check preconditions.                                                    */
781   /***************************************************************************/
782   assert(jbuf != NULL);
783
784   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
785                            jbuf->max_size - jbuf->offset,
786                            "}");
787   jbuf->depth--;
788
789   EVEL_EXIT();
790 }
791
792 /**************************************************************************//**
793  * Determine whether to add a comma when adding a key-value pair.
794  *
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)
799 {
800   char * result;
801
802   EVEL_ENTER();
803
804   /***************************************************************************/
805   /* Check preconditions.                                                    */
806   /***************************************************************************/
807   assert(jbuf != NULL);
808
809   if ((jbuf->offset == 0) ||
810       (jbuf->json[jbuf->offset-1] == '{') ||
811       (jbuf->json[jbuf->offset-1] == '['))
812   {
813     result = "";
814   }
815   else
816   {
817     result = ", ";
818   }
819
820   EVEL_EXIT();
821
822   return result;
823 }
824
825 /**************************************************************************//**
826  * Add a checkpoint - a stake in the ground to which we can rewind.
827  *
828  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
829  *****************************************************************************/
830 void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf)
831 {
832   EVEL_ENTER();
833
834   /***************************************************************************/
835   /* Check preconditions.                                                    */
836   /***************************************************************************/
837   assert(jbuf != NULL);
838
839   /***************************************************************************/
840   /* Store the current offset.                                               */
841   /***************************************************************************/
842   jbuf->checkpoint = jbuf->offset;
843
844   EVEL_EXIT();
845 }
846
847 /**************************************************************************//**
848  * Rewind to the latest checkoint.
849  *
850  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
851  *****************************************************************************/
852 void evel_json_rewind(EVEL_JSON_BUFFER * jbuf)
853 {
854   EVEL_ENTER();
855
856   /***************************************************************************/
857   /* Check preconditions.                                                    */
858   /***************************************************************************/
859   assert(jbuf != NULL);
860   assert(jbuf->checkpoint >= 0);
861   assert(jbuf->checkpoint <= jbuf->offset);
862
863   /***************************************************************************/
864   /* Reinstate the offset from the last checkpoint.                          */
865   /***************************************************************************/
866   jbuf->offset = jbuf->checkpoint;
867   jbuf->checkpoint = -1;
868
869   EVEL_EXIT();
870 }