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