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