1 /*
2  * Copyright (c) 2014-2015, Juniper Networks, Inc.
3  * All rights reserved.
4  * This SOFTWARE is licensed under the LICENSE provided in the
5  * ../Copyright file. By downloading, installing, copying, or otherwise
6  * using the SOFTWARE, you agree to be bound by the terms of that
7  * LICENSE.
8  * Phil Shafer, July 2014
9  */
10 
11 /**
12  * libxo provides a means of generating text, XML, JSON, and HTML output
13  * using a single set of function calls, maximizing the value of output
14  * while minimizing the cost/impact on the code.
15  *
16  * Full documentation is available in ./doc/libxo.txt or online at:
17  *   http://juniper.github.io/libxo/libxo-manual.html
18  */
19 
20 #ifndef INCLUDE_XO_H
21 #define INCLUDE_XO_H
22 
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 
29 #ifdef __dead2
30 #define NORETURN __dead2
31 #else
32 #define NORETURN
33 #endif /* __dead2 */
34 
35 /*
36  * Normally we'd use the HAVE_PRINTFLIKE define triggered by the
37  * --enable-printflike option to configure, but we don't install
38  * our internal "xoconfig.h", and I'd rather not.  Taking the
39  * coward's path, we'll turn it on inside a #if that allows
40  * others to turn it off where needed.  Not ideal, but functional.
41  */
42 #if !defined(NO_PRINTFLIKE) && !defined(__linux__)
43 #define PRINTFLIKE(_x, _y) __printflike(_x, _y)
44 #else
45 #define PRINTFLIKE(_x, _y)
46 #endif /* NO_PRINTFLIKE */
47 
48 /** Formatting types */
49 typedef unsigned short xo_style_t;
50 #define XO_STYLE_TEXT	0	/** Generate text output */
51 #define XO_STYLE_XML	1	/** Generate XML output */
52 #define XO_STYLE_JSON	2	/** Generate JSON output */
53 #define XO_STYLE_HTML	3	/** Generate HTML output */
54 #define XO_STYLE_SDPARAMS 4	/* Generate syslog structured data params */
55 #define XO_STYLE_ENCODER 5	/* Generate calls to external encoder */
56 
57 /** Flags for libxo */
58 typedef unsigned long long xo_xof_flags_t;
59 #define XOF_BIT(_n) ((xo_xof_flags_t) 1 << (_n))
60 #define XOF_CLOSE_FP	XOF_BIT(0) /** Close file pointer on xo_close() */
61 #define XOF_PRETTY	XOF_BIT(1) /** Make 'pretty printed' output */
62 #define XOF_LOG_SYSLOG	XOF_BIT(2) /** Log (on stderr) our syslog content */
63 #define XOF_RESV3	XOF_BIT(3) /* Unused */
64 
65 #define XOF_WARN	XOF_BIT(4) /** Generate warnings for broken calls */
66 #define XOF_XPATH	XOF_BIT(5) /** Emit XPath attributes in HTML  */
67 #define XOF_INFO	XOF_BIT(6) /** Emit additional info fields (HTML) */
68 #define XOF_WARN_XML	XOF_BIT(7) /** Emit warnings in XML (on stdout) */
69 
70 #define XOF_NO_ENV	XOF_BIT(8) /** Don't look at LIBXO_OPTIONS env var */
71 #define XOF_NO_VA_ARG	XOF_BIT(9) /** Don't advance va_list w/ va_arg() */
72 #define XOF_DTRT	XOF_BIT(10) /** Enable "do the right thing" mode */
73 #define XOF_KEYS	XOF_BIT(11) /** Flag 'key' fields for xml and json */
74 
75 #define XOF_IGNORE_CLOSE XOF_BIT(12) /** Ignore errors on close tags */
76 #define XOF_NOT_FIRST	XOF_BIT(13) /* Not the first item (JSON)  */
77 #define XOF_NO_LOCALE	XOF_BIT(14) /** Don't bother with locale */
78 #define XOF_RESV15	XOF_BIT(15) /* Unused */
79 
80 #define XOF_NO_TOP	XOF_BIT(16) /** Don't emit the top braces in JSON */
81 #define XOF_RESV17	XOF_BIT(17) /* Unused  */
82 #define XOF_UNITS	XOF_BIT(18) /** Encode units in XML */
83 #define XOF_RESV19	XOF_BIT(19) /* Unused */
84 
85 #define XOF_UNDERSCORES	XOF_BIT(20) /** Replace dashes with underscores (JSON)*/
86 #define XOF_COLUMNS	XOF_BIT(21) /** xo_emit should return a column count */
87 #define XOF_FLUSH	XOF_BIT(22) /** Flush after each xo_emit call */
88 #define XOF_FLUSH_LINE	XOF_BIT(23) /** Flush after each newline */
89 
90 #define XOF_NO_CLOSE	XOF_BIT(24) /** xo_finish won't close open elements */
91 #define XOF_COLOR_ALLOWED XOF_BIT(25) /** Allow color/effects to be enabled */
92 #define XOF_COLOR	XOF_BIT(26) /** Enable color and effects */
93 #define XOF_NO_HUMANIZE	XOF_BIT(27) /** Block the {h:} modifier */
94 
95 #define XOF_LOG_GETTEXT	XOF_BIT(28) /** Log (stderr) gettext lookup strings */
96 #define XOF_UTF8	XOF_BIT(29) /** Force text output to be UTF8 */
97 #define XOF_RETAIN_ALL	XOF_BIT(30) /** Force use of XOEF_RETAIN */
98 #define XOF_RETAIN_NONE	XOF_BIT(31) /** Prevent use of XOEF_RETAIN */
99 
100 typedef unsigned xo_emit_flags_t; /* Flags to xo_emit() and friends */
101 #define XOEF_RETAIN	(1<<0)	  /* Retain parsed formatting information */
102 
103 /*
104  * The xo_info_t structure provides a mapping between names and
105  * additional data emitted via HTML.
106  */
107 typedef struct xo_info_s {
108     const char *xi_name;	/* Name of the element */
109     const char *xi_type;	/* Type of field */
110     const char *xi_help;	/* Description of field */
111 } xo_info_t;
112 
113 #define XO_INFO_NULL NULL, NULL, NULL /* Use '{ XO_INFO_NULL }' to end lists */
114 
115 struct xo_handle_s;		/* Opaque structure forward */
116 typedef struct xo_handle_s xo_handle_t; /* Handle for XO output */
117 
118 typedef int (*xo_write_func_t)(void *, const char *);
119 typedef void (*xo_close_func_t)(void *);
120 typedef int (*xo_flush_func_t)(void *);
121 typedef void *(*xo_realloc_func_t)(void *, size_t);
122 typedef void (*xo_free_func_t)(void *);
123 
124 /*
125  * The formatter function mirrors "vsnprintf", with an additional argument
126  * of the xo handle.  The caller should return the number of bytes _needed_
127  * to fit the data, even if this exceeds 'len'.
128  */
129 typedef int (*xo_formatter_t)(xo_handle_t *, char *, int,
130 				const char *, va_list);
131 typedef void (*xo_checkpointer_t)(xo_handle_t *, va_list, int);
132 
133 xo_handle_t *
134 xo_create (xo_style_t style, xo_xof_flags_t flags);
135 
136 xo_handle_t *
137 xo_create_to_file (FILE *fp, xo_style_t style, xo_xof_flags_t flags);
138 
139 void
140 xo_destroy (xo_handle_t *xop);
141 
142 void
143 xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func,
144 	       xo_close_func_t close_func, xo_flush_func_t flush_func);
145 
146 void
147 xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func);
148 
149 void
150 xo_set_style (xo_handle_t *xop, xo_style_t style);
151 
152 xo_style_t
153 xo_get_style (xo_handle_t *xop);
154 
155 int
156 xo_set_style_name (xo_handle_t *xop, const char *style);
157 
158 int
159 xo_set_options (xo_handle_t *xop, const char *input);
160 
161 xo_xof_flags_t
162 xo_get_flags (xo_handle_t *xop);
163 
164 void
165 xo_set_flags (xo_handle_t *xop, xo_xof_flags_t flags);
166 
167 void
168 xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags);
169 
170 int
171 xo_set_file_h (xo_handle_t *xop, FILE *fp);
172 
173 int
174 xo_set_file (FILE *fp);
175 
176 void
177 xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count);
178 
179 void
180 xo_set_formatter (xo_handle_t *xop, xo_formatter_t func, xo_checkpointer_t);
181 
182 void
183 xo_set_depth (xo_handle_t *xop, int depth);
184 
185 int
186 xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap);
187 
188 int
189 xo_emit_h (xo_handle_t *xop, const char *fmt, ...);
190 
191 int
192 xo_emit (const char *fmt, ...);
193 
194 int
195 xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
196 	     const char *fmt, va_list vap);
197 
198 int
199 xo_emit_hf (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt, ...);
200 
201 int
202 xo_emit_f (xo_emit_flags_t flags, const char *fmt, ...);
203 
204 PRINTFLIKE(2, 0)
205 static inline int
xo_emit_hvp(xo_handle_t * xop,const char * fmt,va_list vap)206 xo_emit_hvp (xo_handle_t *xop, const char *fmt, va_list vap)
207 {
208     return xo_emit_hv(xop, fmt, vap);
209 }
210 
211 PRINTFLIKE(2, 3)
212 static inline int
xo_emit_hp(xo_handle_t * xop,const char * fmt,...)213 xo_emit_hp (xo_handle_t *xop, const char *fmt, ...)
214 {
215     va_list vap;
216     va_start(vap, fmt);
217     int rc = xo_emit_hv(xop, fmt, vap);
218     va_end(vap);
219     return rc;
220 }
221 
222 PRINTFLIKE(1, 2)
223 static inline int
xo_emit_p(const char * fmt,...)224 xo_emit_p (const char *fmt, ...)
225 {
226     va_list vap;
227     va_start(vap, fmt);
228     int rc = xo_emit_hv(NULL, fmt, vap);
229     va_end(vap);
230     return rc;
231 }
232 
233 PRINTFLIKE(3, 0)
234 static inline int
xo_emit_hvfp(xo_handle_t * xop,xo_emit_flags_t flags,const char * fmt,va_list vap)235 xo_emit_hvfp (xo_handle_t *xop, xo_emit_flags_t flags,
236 	      const char *fmt, va_list vap)
237 {
238     return xo_emit_hvf(xop, flags, fmt, vap);
239 }
240 
241 PRINTFLIKE(3, 4)
242 static inline int
xo_emit_hfp(xo_handle_t * xop,xo_emit_flags_t flags,const char * fmt,...)243 xo_emit_hfp (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt, ...)
244 {
245     va_list vap;
246     va_start(vap, fmt);
247     int rc = xo_emit_hvf(xop, flags, fmt, vap);
248     va_end(vap);
249     return rc;
250 }
251 
252 PRINTFLIKE(2, 3)
253 static inline int
xo_emit_fp(xo_emit_flags_t flags,const char * fmt,...)254 xo_emit_fp (xo_emit_flags_t flags, const char *fmt, ...)
255 {
256     va_list vap;
257     va_start(vap, fmt);
258     int rc = xo_emit_hvf(NULL, flags, fmt, vap);
259     va_end(vap);
260     return rc;
261 }
262 
263 int
264 xo_open_container_h (xo_handle_t *xop, const char *name);
265 
266 int
267 xo_open_container (const char *name);
268 
269 int
270 xo_open_container_hd (xo_handle_t *xop, const char *name);
271 
272 int
273 xo_open_container_d (const char *name);
274 
275 int
276 xo_close_container_h (xo_handle_t *xop, const char *name);
277 
278 int
279 xo_close_container (const char *name);
280 
281 int
282 xo_close_container_hd (xo_handle_t *xop);
283 
284 int
285 xo_close_container_d (void);
286 
287 int
288 xo_open_list_h (xo_handle_t *xop, const char *name);
289 
290 int
291 xo_open_list (const char *name);
292 
293 int
294 xo_open_list_hd (xo_handle_t *xop, const char *name);
295 
296 int
297 xo_open_list_d (const char *name);
298 
299 int
300 xo_close_list_h (xo_handle_t *xop, const char *name);
301 
302 int
303 xo_close_list (const char *name);
304 
305 int
306 xo_close_list_hd (xo_handle_t *xop);
307 
308 int
309 xo_close_list_d (void);
310 
311 int
312 xo_open_instance_h (xo_handle_t *xop, const char *name);
313 
314 int
315 xo_open_instance (const char *name);
316 
317 int
318 xo_open_instance_hd (xo_handle_t *xop, const char *name);
319 
320 int
321 xo_open_instance_d (const char *name);
322 
323 int
324 xo_close_instance_h (xo_handle_t *xop, const char *name);
325 
326 int
327 xo_close_instance (const char *name);
328 
329 int
330 xo_close_instance_hd (xo_handle_t *xop);
331 
332 int
333 xo_close_instance_d (void);
334 
335 int
336 xo_open_marker_h (xo_handle_t *xop, const char *name);
337 
338 int
339 xo_open_marker (const char *name);
340 
341 int
342 xo_close_marker_h (xo_handle_t *xop, const char *name);
343 
344 int
345 xo_close_marker (const char *name);
346 
347 int
348 xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...);
349 
350 int
351 xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap);
352 
353 int
354 xo_attr (const char *name, const char *fmt, ...);
355 
356 void
357 xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap);
358 
359 void
360 xo_error_h (xo_handle_t *xop, const char *fmt, ...);
361 
362 void
363 xo_error (const char *fmt, ...);
364 
365 int
366 xo_flush_h (xo_handle_t *xop);
367 
368 int
369 xo_flush (void);
370 
371 int
372 xo_finish_h (xo_handle_t *xop);
373 
374 int
375 xo_finish (void);
376 
377 void
378 xo_finish_atexit (void);
379 
380 void
381 xo_set_leading_xpath (xo_handle_t *xop, const char *path);
382 
383 void
384 xo_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4);
385 
386 void
387 xo_warn_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3);
388 
389 void
390 xo_warn (const char *fmt, ...) PRINTFLIKE(1, 2);
391 
392 void
393 xo_warnx (const char *fmt, ...) PRINTFLIKE(1, 2);
394 
395 void
396 xo_err (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3);
397 
398 void
399 xo_errx (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3);
400 
401 void
402 xo_errc (int eval, int code, const char *fmt, ...) NORETURN PRINTFLIKE(3, 4);
403 
404 void
405 xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap) PRINTFLIKE(3, 0);
406 
407 void
408 xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4);
409 
410 void
411 xo_message_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3);
412 
413 void
414 xo_message_e (const char *fmt, ...) PRINTFLIKE(1, 2);
415 
416 void
417 xo_message (const char *fmt, ...) PRINTFLIKE(1, 2);
418 
419 void
420 xo_emit_warn_hcv (xo_handle_t *xop, int as_warning, int code,
421 		  const char *fmt, va_list vap);
422 
423 void
424 xo_emit_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...);
425 
426 void
427 xo_emit_warn_c (int code, const char *fmt, ...);
428 
429 void
430 xo_emit_warn (const char *fmt, ...);
431 
432 void
433 xo_emit_warnx (const char *fmt, ...);
434 
435 void
436 xo_emit_err (int eval, const char *fmt, ...) NORETURN;
437 
438 void
439 xo_emit_errx (int eval, const char *fmt, ...) NORETURN;
440 
441 void
442 xo_emit_errc (int eval, int code, const char *fmt, ...) NORETURN;
443 
444 PRINTFLIKE(4, 0)
445 static inline void
xo_emit_warn_hcvp(xo_handle_t * xop,int as_warning,int code,const char * fmt,va_list vap)446 xo_emit_warn_hcvp (xo_handle_t *xop, int as_warning, int code,
447 		  const char *fmt, va_list vap)
448 {
449     xo_emit_warn_hcv(xop, as_warning, code, fmt, vap);
450 }
451 
452 PRINTFLIKE(3, 4)
453 static inline void
xo_emit_warn_hcp(xo_handle_t * xop,int code,const char * fmt,...)454 xo_emit_warn_hcp (xo_handle_t *xop, int code, const char *fmt, ...)
455 {
456     va_list vap;
457     va_start(vap, fmt);
458     xo_emit_warn_hcv(xop, 1, code, fmt, vap);
459     va_end(vap);
460 }
461 
462 PRINTFLIKE(2, 3)
463 static inline void
xo_emit_warn_cp(int code,const char * fmt,...)464 xo_emit_warn_cp (int code, const char *fmt, ...)
465 {
466     va_list vap;
467     va_start(vap, fmt);
468     xo_emit_warn_hcv(NULL, 1, code, fmt, vap);
469     va_end(vap);
470 }
471 
472 PRINTFLIKE(1, 2)
473 static inline void
xo_emit_warn_p(const char * fmt,...)474 xo_emit_warn_p (const char *fmt, ...)
475 {
476     int code = errno;
477     va_list vap;
478     va_start(vap, fmt);
479     xo_emit_warn_hcv(NULL, 1, code, fmt, vap);
480     va_end(vap);
481 }
482 
483 PRINTFLIKE(1, 2)
484 static inline void
xo_emit_warnx_p(const char * fmt,...)485 xo_emit_warnx_p (const char *fmt, ...)
486 {
487     va_list vap;
488     va_start(vap, fmt);
489     xo_emit_warn_hcv(NULL, 1, -1, fmt, vap);
490     va_end(vap);
491 }
492 
493 NORETURN PRINTFLIKE(2, 3)
494 static inline void
xo_emit_err_p(int eval,const char * fmt,...)495 xo_emit_err_p (int eval, const char *fmt, ...)
496 {
497     int code = errno;
498     va_list vap;
499     va_start(vap, fmt);
500     xo_emit_warn_hcv(NULL, 0, code, fmt, vap);
501     va_end(vap);
502 
503     exit(eval);
504 }
505 
506 PRINTFLIKE(2, 3)
507 static inline void
xo_emit_errx_p(int eval,const char * fmt,...)508 xo_emit_errx_p (int eval, const char *fmt, ...)
509 {
510     va_list vap;
511     va_start(vap, fmt);
512     xo_emit_warn_hcv(NULL, 0, -1, fmt, vap);
513     va_end(vap);
514     exit(eval);
515 }
516 
517 PRINTFLIKE(3, 4)
518 static inline void
xo_emit_errc_p(int eval,int code,const char * fmt,...)519 xo_emit_errc_p (int eval, int code, const char *fmt, ...)
520 {
521     va_list vap;
522     va_start(vap, fmt);
523     xo_emit_warn_hcv(NULL, 0, code, fmt, vap);
524     va_end(vap);
525     exit(eval);
526 }
527 
528 void
529 xo_emit_err_v (int eval, int code, const char *fmt, va_list vap) NORETURN PRINTFLIKE(3, 0);
530 
531 void
532 xo_no_setlocale (void);
533 
534 /**
535  * @brief Lift libxo-specific arguments from a set of arguments
536  *
537  * libxo-enable programs typically use command line options to enable
538  * all the nifty-cool libxo features.  xo_parse_args() makes this simple
539  * by pre-processing the command line arguments given to main(), handling
540  * and removing the libxo-specific ones, meaning anything starting with
541  * "--libxo".  A full description of these arguments is in the base
542  * documentation.
543  * @param[in] argc Number of arguments (ala #main())
544  * @param[in] argc Array of argument strings (ala #main())
545  * @return New number of arguments, or -1 for failure.
546  */
547 int
548 xo_parse_args (int argc, char **argv);
549 
550 /**
551  * This is the "magic" number returned by libxo-supporting commands
552  * when passed the equally magic "--libxo-check" option.  If you
553  * return this, we can (unsafely) assume that since you know the magic
554  * handshake, you'll happily handle future --libxo options and not do
555  * something violent like reboot the box or create another hole in the
556  * ozone layer.
557  */
558 #define XO_HAS_LIBXO	121
559 
560 /**
561  * externs for libxo's version number strings
562  */
563 extern const char xo_version[];	      /** Base version triple string */
564 extern const char xo_version_extra[]; /** Extra version magic content */
565 
566 /**
567  * @brief Dump the internal stack of a libxo handle.
568  *
569  * This diagnostic function is something I will ask you to call from
570  * your program when you write to tell me libxo has gone bat-stink
571  * crazy and has discarded your list or container or content.  Output
572  * content will be what we lovingly call "developer entertainment".
573  * @param[in] xop A valid libxo handle, or NULL for the default handle
574  */
575 void
576 xo_dump_stack (xo_handle_t *xop);
577 
578 /**
579  * @brief Recode the name of the program, suitable for error output.
580  *
581  * libxo will record the given name for use while generating error
582  * messages.  The contents are not copied, so the value must continue
583  * to point to a valid memory location.  This allows the caller to change
584  * the value, but requires the caller to manage the memory.  Typically
585  * this is called with argv[0] from main().
586  * @param[in] name The name of the current application program
587  */
588 void
589 xo_set_program (const char *name);
590 
591 /**
592  * @brief Add a version string to the output, where possible.
593  *
594  * Adds a version number to the output, suitable for tracking
595  * changes in the content.  This is only important for the "encoding"
596  * format styles (XML and JSON) and allows a user of the data to
597  * discern which version of the data model is in use.
598  * @param[in] version The version number, encoded as a string
599  */
600 void
601 xo_set_version (const char *version);
602 
603 /**
604  * #xo_set_version with a handle.
605  * @param[in] xop A valid libxo handle, or NULL for the default handle
606  * @param[in] version The version number, encoded as a string
607  */
608 void
609 xo_set_version_h (xo_handle_t *xop, const char *version);
610 
611 void
612 xo_open_log (const char *ident, int logopt, int facility);
613 
614 void
615 xo_close_log (void);
616 
617 int
618 xo_set_logmask (int maskpri);
619 
620 void
621 xo_set_unit_test_mode (int value);
622 
623 void
624 xo_syslog (int priority, const char *name, const char *message, ...);
625 
626 void
627 xo_vsyslog (int priority, const char *name, const char *message, va_list args);
628 
629 typedef void (*xo_syslog_open_t)(void);
630 typedef void (*xo_syslog_send_t)(const char *full_msg,
631 				 const char *v0_hdr, const char *text_only);
632 typedef void (*xo_syslog_close_t)(void);
633 
634 void
635 xo_set_syslog_handler (xo_syslog_open_t open_func, xo_syslog_send_t send_func,
636 		       xo_syslog_close_t close_func);
637 
638 void
639 xo_set_syslog_enterprise_id (unsigned short eid);
640 
641 typedef void (*xo_simplify_field_func_t)(const char *, unsigned, int);
642 
643 char *
644 xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers,
645 		    xo_simplify_field_func_t field_cb);
646 
647 int
648 xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
649 		  const char *fmt, const char *efmt,
650 		  va_list vap);
651 
652 int
653 xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
654 		 const char *fmt, const char *efmt, ...);
655 
656 int
657 xo_emit_field (const char *rolmod, const char *contents,
658 	       const char *fmt, const char *efmt, ...);
659 
660 void
661 xo_retain_clear_all (void);
662 
663 void
664 xo_retain_clear (const char *fmt);
665 
666 #endif /* INCLUDE_XO_H */
667