7ae3453bafd5298ca9c7ef9db5debb9d976d044c
[demo.git] / vnfs / VES / 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  * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
205  *
206  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
207  * @param key           Pointer to the key to encode.
208  * @param option        Pointer to holder of the corresponding value to encode.
209  * @return true if the key, value was added, false if it was suppressed.
210  *****************************************************************************/
211 bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
212                          const char * const key,
213                          const EVEL_OPTION_INT * const option)
214 {
215   bool added = false;
216
217   EVEL_ENTER();
218
219   /***************************************************************************/
220   /* Check preconditions.                                                    */
221   /***************************************************************************/
222   assert(option != NULL);
223
224   if (option->is_set)
225   {
226     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
227         (jbuf->throttle_spec != NULL) &&
228         evel_throttle_suppress_field(jbuf->throttle_spec, key))
229     {
230       EVEL_INFO("Suppressed: %s, %d", key, option->value);
231     }
232     else
233     {
234       EVEL_DEBUG("Encoded: %s, %d", key, option->value);
235       evel_enc_kv_int(jbuf, key, option->value);
236       added = true;
237     }
238   }
239
240   EVEL_EXIT();
241
242   return added;
243 }
244
245 /**************************************************************************//**
246  * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
247  *
248  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
249  * @param key           Pointer to the key to encode.
250  * @param value         The corresponding value to encode.
251  *****************************************************************************/
252 void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
253                      const char * const key,
254                      const int value)
255 {
256   EVEL_ENTER();
257
258   /***************************************************************************/
259   /* Check preconditions.                                                    */
260   /***************************************************************************/
261   assert(jbuf != NULL);
262   assert(key != NULL);
263
264   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
265                            jbuf->max_size - jbuf->offset,
266                            "%s\"%s\": %d",
267                            evel_json_kv_comma(jbuf),
268                            key,
269                            value);
270
271   EVEL_EXIT();
272 }
273
274 /**************************************************************************//**
275  * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
276  *
277  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
278  * @param key           Pointer to the key to encode.
279  * @param option        Pointer to holder of the corresponding value to encode.
280  * @return true if the key, value was added, false if it was suppressed.
281  *****************************************************************************/
282 bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
283                             const char * const key,
284                             const EVEL_OPTION_DOUBLE * const option)
285 {
286   bool added = false;
287
288   EVEL_ENTER();
289
290   /***************************************************************************/
291   /* Check preconditions.                                                    */
292   /***************************************************************************/
293   assert(option != NULL);
294
295   if (option->is_set)
296   {
297     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
298         (jbuf->throttle_spec != NULL) &&
299         evel_throttle_suppress_field(jbuf->throttle_spec, key))
300     {
301       EVEL_INFO("Suppressed: %s, %1f", key, option->value);
302     }
303     else
304     {
305       EVEL_DEBUG("Encoded: %s, %1f", key, option->value);
306       evel_enc_kv_double(jbuf, key, option->value);
307       added = true;
308     }
309   }
310
311   EVEL_EXIT();
312
313   return added;
314 }
315
316 /**************************************************************************//**
317  * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
318  *
319  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
320  * @param key           Pointer to the key to encode.
321  * @param value         The corresponding value to encode.
322  *****************************************************************************/
323 void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
324                         const char * const key,
325                         const double value)
326 {
327   EVEL_ENTER();
328
329   /***************************************************************************/
330   /* Check preconditions.                                                    */
331   /***************************************************************************/
332   assert(jbuf != NULL);
333   assert(key != NULL);
334
335   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
336                            jbuf->max_size - jbuf->offset,
337                            "%s\"%s\": %1f",
338                            evel_json_kv_comma(jbuf),
339                            key,
340                            value);
341
342   EVEL_EXIT();
343 }
344
345 /**************************************************************************//**
346  * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
347  *
348  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
349  * @param key           Pointer to the key to encode.
350  * @param option        Pointer to holder of the corresponding value to encode.
351  * @return true if the key, value was added, false if it was suppressed.
352  *****************************************************************************/
353 bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
354                          const char * const key,
355                          const EVEL_OPTION_ULL * const option)
356 {
357   bool added = false;
358
359   EVEL_ENTER();
360
361   /***************************************************************************/
362   /* Check preconditions.                                                    */
363   /***************************************************************************/
364   assert(option != NULL);
365
366   if (option->is_set)
367   {
368     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
369         (jbuf->throttle_spec != NULL) &&
370         evel_throttle_suppress_field(jbuf->throttle_spec, key))
371     {
372       EVEL_INFO("Suppressed: %s, %1lu", key, option->value);
373     }
374     else
375     {
376       EVEL_DEBUG("Encoded: %s, %1lu", key, option->value);
377       evel_enc_kv_ull(jbuf, key, option->value);
378       added = true;
379     }
380   }
381
382   EVEL_EXIT();
383
384   return added;
385 }
386
387 /**************************************************************************//**
388  * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
389  *
390  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
391  * @param key           Pointer to the key to encode.
392  * @param value         The corresponding value to encode.
393  *****************************************************************************/
394 void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
395                      const char * const key,
396                      const unsigned long long value)
397 {
398   EVEL_ENTER();
399
400   /***************************************************************************/
401   /* Check preconditions.                                                    */
402   /***************************************************************************/
403   assert(jbuf != NULL);
404   assert(key != NULL);
405
406   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
407                            jbuf->max_size - jbuf->offset,
408                            "%s\"%s\": %llu",
409                            evel_json_kv_comma(jbuf),
410                            key,
411                            value);
412
413   EVEL_EXIT();
414 }
415
416 /**************************************************************************//**
417  * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
418  *
419  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
420  * @param key           Pointer to the key to encode.
421  * @param option        Pointer to holder of the corresponding value to encode.
422  * @return true if the key, value was added, false if it was suppressed.
423  *****************************************************************************/
424 bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
425                           const char * const key,
426                           const EVEL_OPTION_TIME * const option)
427 {
428   bool added = false;
429
430   EVEL_ENTER();
431
432   /***************************************************************************/
433   /* Check preconditions.                                                    */
434   /***************************************************************************/
435   assert(option != NULL);
436
437   if (option->is_set)
438   {
439     if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
440         (jbuf->throttle_spec != NULL) &&
441         evel_throttle_suppress_field(jbuf->throttle_spec, key))
442     {
443       EVEL_INFO("Suppressed time: %s", key);
444     }
445     else
446     {
447       EVEL_DEBUG("Encoded time: %s", key);
448       evel_enc_kv_time(jbuf, key, &option->value);
449       added = true;
450     }
451   }
452
453   EVEL_EXIT();
454
455   return added;
456 }
457
458 /**************************************************************************//**
459  * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
460  *
461  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
462  * @param key           Pointer to the key to encode.
463  * @param time          Pointer to the time to encode.
464  *****************************************************************************/
465 void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
466                       const char * const key,
467                       const time_t * time)
468 {
469   EVEL_ENTER();
470
471   /***************************************************************************/
472   /* Check preconditions.                                                    */
473   /***************************************************************************/
474   assert(jbuf != NULL);
475   assert(key != NULL);
476   assert(time != NULL);
477
478   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
479                            jbuf->max_size - jbuf->offset,
480                            "%s\"%s\": \"",
481                            evel_json_kv_comma(jbuf),
482                            key);
483   jbuf->offset += strftime(jbuf->json + jbuf->offset,
484                            jbuf->max_size - jbuf->offset,
485                            EVEL_RFC2822_STRFTIME_FORMAT,
486                            localtime(time));
487   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
488                            jbuf->max_size - jbuf->offset,
489                            "\"");
490   EVEL_EXIT();
491 }
492
493 /**************************************************************************//**
494  * Encode a key and version.
495  *
496  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
497  * @param key           Pointer to the key to encode.
498  * @param major_version The major version to encode.
499  * @param minor_version The minor version to encode.
500  *****************************************************************************/
501 void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
502                       const char * const key,
503                       const int major_version,
504                       const int minor_version)
505 {
506   EVEL_ENTER();
507
508   /***************************************************************************/
509   /* Check preconditions.                                                    */
510   /***************************************************************************/
511   assert(jbuf != NULL);
512   assert(key != NULL);
513
514   evel_enc_kv_int(jbuf, key, major_version);
515   if (minor_version != 0)
516   {
517     jbuf->offset += snprintf(jbuf->json + jbuf->offset,
518                              jbuf->max_size - jbuf->offset,
519                              ".%d",
520                              minor_version);
521   }
522
523   EVEL_EXIT();
524 }
525
526 /**************************************************************************//**
527  * Add the key and opening bracket of an optional named list to a JSON buffer.
528  *
529  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
530  * @param key           Pointer to the key to encode.
531  * @return true if the list was opened, false if it was suppressed.
532  *****************************************************************************/
533 bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
534                                    const char * const key)
535 {
536   bool opened = false;
537
538   EVEL_ENTER();
539
540   /***************************************************************************/
541   /* Check preconditions.                                                    */
542   /***************************************************************************/
543   assert(jbuf != NULL);
544   assert(key != NULL);
545
546   if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
547       (jbuf->throttle_spec != NULL) &&
548       evel_throttle_suppress_field(jbuf->throttle_spec, key))
549   {
550     EVEL_INFO("Suppressed: %s", key);
551     opened = false;
552   }
553   else
554   {
555     evel_json_open_named_list(jbuf, key);
556     opened = true;
557   }
558
559   EVEL_EXIT();
560
561   return opened;
562 }
563
564 /**************************************************************************//**
565  * Add the key and opening bracket of a named list to a JSON buffer.
566  *
567  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
568  * @param key           Pointer to the key to encode.
569  *****************************************************************************/
570 void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
571                                const char * const key)
572 {
573   EVEL_ENTER();
574
575   /***************************************************************************/
576   /* Check preconditions.                                                    */
577   /***************************************************************************/
578   assert(jbuf != NULL);
579   assert(key != NULL);
580
581   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
582                            jbuf->max_size - jbuf->offset,
583                            "%s\"%s\": [",
584                            evel_json_kv_comma(jbuf),
585                            key);
586   jbuf->depth++;
587
588   EVEL_EXIT();
589 }
590
591 /**************************************************************************//**
592  * Add the closing bracket of a list to a JSON buffer.
593  *
594  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
595  *****************************************************************************/
596 void evel_json_close_list(EVEL_JSON_BUFFER * jbuf)
597 {
598   EVEL_ENTER();
599
600   /***************************************************************************/
601   /* Check preconditions.                                                    */
602   /***************************************************************************/
603   assert(jbuf != NULL);
604
605   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
606                            jbuf->max_size - jbuf->offset,
607                            "]");
608   jbuf->depth--;
609
610   EVEL_EXIT();
611 }
612
613 /**************************************************************************//**
614  * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
615  *
616  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
617  * @param format        Format string in standard printf format.
618  * @param ...           Variable parameters for format string.
619  *****************************************************************************/
620 void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
621                         const char * const format,
622                         ...)
623 {
624   va_list largs;
625
626   EVEL_ENTER();
627
628   /***************************************************************************/
629   /* Check preconditions.                                                    */
630   /***************************************************************************/
631   assert(jbuf != NULL);
632   assert(format != NULL);
633
634   /***************************************************************************/
635   /* Add a comma unless we're at the start of the list.                      */
636   /***************************************************************************/
637   if (jbuf->json[jbuf->offset - 1] != '[')
638   {
639     jbuf->offset += snprintf(jbuf->json + jbuf->offset,
640                              jbuf->max_size - jbuf->offset,
641                              ", ");
642   }
643
644   va_start(largs, format);
645   jbuf->offset += vsnprintf(jbuf->json + jbuf->offset,
646                             jbuf->max_size - jbuf->offset,
647                             format,
648                             largs);
649   va_end(largs);
650
651   EVEL_EXIT();
652 }
653
654 /**************************************************************************//**
655  * Add the opening bracket of an optional named object to a JSON buffer.
656  *
657  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
658  * @param key           Pointer to the key to encode.
659  *****************************************************************************/
660 bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
661                                      const char * const key)
662 {
663   bool opened = false;
664
665   EVEL_ENTER();
666
667   /***************************************************************************/
668   /* Check preconditions.                                                    */
669   /***************************************************************************/
670   assert(jbuf != NULL);
671   assert(key != NULL);
672
673   if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
674       (jbuf->throttle_spec != NULL) &&
675       evel_throttle_suppress_field(jbuf->throttle_spec, key))
676   {
677     EVEL_INFO("Suppressed: %s", key);
678     opened = false;
679   }
680   else
681   {
682     evel_json_open_named_object(jbuf, key);
683     opened = true;
684   }
685
686   EVEL_EXIT();
687
688   return opened;
689 }
690
691 /**************************************************************************//**
692  * Add the opening bracket of an object to a JSON buffer.
693  *
694  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
695  * @param key           Pointer to the key to encode.
696  * @return true if the object was opened, false if it was suppressed.
697  *****************************************************************************/
698 void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
699                                  const char * const key)
700 {
701   EVEL_ENTER();
702
703   /***************************************************************************/
704   /* Check preconditions.                                                    */
705   /***************************************************************************/
706   assert(jbuf != NULL);
707   assert(key != NULL);
708
709   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
710                            jbuf->max_size - jbuf->offset,
711                            "%s\"%s\": {",
712                            evel_json_kv_comma(jbuf),
713                            key);
714   jbuf->depth++;
715
716   EVEL_EXIT();
717 }
718
719 /**************************************************************************//**
720  * Add the opening bracket of an object to a JSON buffer.
721  *
722  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
723  *****************************************************************************/
724 void evel_json_open_object(EVEL_JSON_BUFFER * jbuf)
725 {
726   char * comma;
727
728   EVEL_ENTER();
729
730   /***************************************************************************/
731   /* Check preconditions.                                                    */
732   /***************************************************************************/
733   assert(jbuf != NULL);
734
735   if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}'))
736   {
737     comma = ", ";
738   }
739   else
740   {
741     comma = "";
742   }
743
744   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
745                            jbuf->max_size - jbuf->offset,
746                            "%s{",
747                            comma);
748   jbuf->depth++;
749
750   EVEL_EXIT();
751 }
752
753 /**************************************************************************//**
754  * Add the closing bracket of an object to a JSON buffer.
755  *
756  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
757  *****************************************************************************/
758 void evel_json_close_object(EVEL_JSON_BUFFER * jbuf)
759 {
760   EVEL_ENTER();
761
762   /***************************************************************************/
763   /* Check preconditions.                                                    */
764   /***************************************************************************/
765   assert(jbuf != NULL);
766
767   jbuf->offset += snprintf(jbuf->json + jbuf->offset,
768                            jbuf->max_size - jbuf->offset,
769                            "}");
770   jbuf->depth--;
771
772   EVEL_EXIT();
773 }
774
775 /**************************************************************************//**
776  * Determine whether to add a comma when adding a key-value pair.
777  *
778  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
779  * @returns A string containing the comma if it is required.
780  *****************************************************************************/
781 char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf)
782 {
783   char * result;
784
785   EVEL_ENTER();
786
787   /***************************************************************************/
788   /* Check preconditions.                                                    */
789   /***************************************************************************/
790   assert(jbuf != NULL);
791
792   if ((jbuf->offset == 0) ||
793       (jbuf->json[jbuf->offset-1] == '{') ||
794       (jbuf->json[jbuf->offset-1] == '['))
795   {
796     result = "";
797   }
798   else
799   {
800     result = ", ";
801   }
802
803   EVEL_EXIT();
804
805   return result;
806 }
807
808 /**************************************************************************//**
809  * Add a checkpoint - a stake in the ground to which we can rewind.
810  *
811  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
812  *****************************************************************************/
813 void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf)
814 {
815   EVEL_ENTER();
816
817   /***************************************************************************/
818   /* Check preconditions.                                                    */
819   /***************************************************************************/
820   assert(jbuf != NULL);
821
822   /***************************************************************************/
823   /* Store the current offset.                                               */
824   /***************************************************************************/
825   jbuf->checkpoint = jbuf->offset;
826
827   EVEL_EXIT();
828 }
829
830 /**************************************************************************//**
831  * Rewind to the latest checkoint.
832  *
833  * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
834  *****************************************************************************/
835 void evel_json_rewind(EVEL_JSON_BUFFER * jbuf)
836 {
837   EVEL_ENTER();
838
839   /***************************************************************************/
840   /* Check preconditions.                                                    */
841   /***************************************************************************/
842   assert(jbuf != NULL);
843   assert(jbuf->checkpoint >= 0);
844   assert(jbuf->checkpoint <= jbuf->offset);
845
846   /***************************************************************************/
847   /* Reinstate the offset from the last checkpoint.                          */
848   /***************************************************************************/
849   jbuf->offset = jbuf->checkpoint;
850   jbuf->checkpoint = -1;
851
852   EVEL_EXIT();
853 }