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