Deleted Added
full compact
libxo.c (298067) libxo.c (298083)
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

--- 5 unchanged lines hidden (view full) ---

14 * HTML output that encodes the text output annotated with additional
15 * information. Specialized encoders can be built that allow custom
16 * encoding including binary ones like CBOR, thrift, protobufs, etc.
17 *
18 * Full documentation is available in ./doc/libxo.txt or online at:
19 * http://juniper.github.io/libxo/libxo-manual.html
20 *
21 * For first time readers, the core bits of code to start looking at are:
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

--- 5 unchanged lines hidden (view full) ---

14 * HTML output that encodes the text output annotated with additional
15 * information. Specialized encoders can be built that allow custom
16 * encoding including binary ones like CBOR, thrift, protobufs, etc.
17 *
18 * Full documentation is available in ./doc/libxo.txt or online at:
19 * http://juniper.github.io/libxo/libxo-manual.html
20 *
21 * For first time readers, the core bits of code to start looking at are:
22 * - xo_do_emit() -- the central function of the library
22 * - xo_do_emit() -- parse and emit a set of fields
23 * - xo_do_emit_fields -- the central function of the library
23 * - xo_do_format_field() -- handles formatting a single field
24 * - xo_transiton() -- the state machine that keeps things sane
25 * and of course the "xo_handle_t" data structure, which carries all
26 * configuration and state.
27 */
28
29#include <stdio.h>
30#include <stdlib.h>

--- 84 unchanged lines hidden (view full) ---

115#elif HAVE_THREAD_LOCAL == THREAD_LOCAL_declspec
116#define THREAD_LOCAL(_x) __declspec(_x)
117#else
118#error unknown thread-local setting
119#endif /* HAVE_THREADS_H */
120
121const char xo_version[] = LIBXO_VERSION;
122const char xo_version_extra[] = LIBXO_VERSION_EXTRA;
24 * - xo_do_format_field() -- handles formatting a single field
25 * - xo_transiton() -- the state machine that keeps things sane
26 * and of course the "xo_handle_t" data structure, which carries all
27 * configuration and state.
28 */
29
30#include <stdio.h>
31#include <stdlib.h>

--- 84 unchanged lines hidden (view full) ---

116#elif HAVE_THREAD_LOCAL == THREAD_LOCAL_declspec
117#define THREAD_LOCAL(_x) __declspec(_x)
118#else
119#error unknown thread-local setting
120#endif /* HAVE_THREADS_H */
121
122const char xo_version[] = LIBXO_VERSION;
123const char xo_version_extra[] = LIBXO_VERSION_EXTRA;
124static const char xo_default_format[] = "%s";
123
124#ifndef UNUSED
125#define UNUSED __attribute__ ((__unused__))
126#endif /* UNUSED */
127
128#define XO_INDENT_BY 2 /* Amount to indent when pretty printing */
129#define XO_DEPTH 128 /* Default stack depth */
130#define XO_MAX_ANCHOR_WIDTH (8*1024) /* Anything wider is just sillyb */

--- 202 unchanged lines hidden (view full) ---

333#define XFF_HUMANIZE (1<<15) /* Humanize the value (for display styles) */
334
335#define XFF_HN_SPACE (1<<16) /* Humanize: put space before suffix */
336#define XFF_HN_DECIMAL (1<<17) /* Humanize: add one decimal place if <10 */
337#define XFF_HN_1000 (1<<18) /* Humanize: use 1000, not 1024 */
338#define XFF_GT_FIELD (1<<19) /* Call gettext() on a field */
339
340#define XFF_GT_PLURAL (1<<20) /* Call dngettext to find plural form */
125
126#ifndef UNUSED
127#define UNUSED __attribute__ ((__unused__))
128#endif /* UNUSED */
129
130#define XO_INDENT_BY 2 /* Amount to indent when pretty printing */
131#define XO_DEPTH 128 /* Default stack depth */
132#define XO_MAX_ANCHOR_WIDTH (8*1024) /* Anything wider is just sillyb */

--- 202 unchanged lines hidden (view full) ---

335#define XFF_HUMANIZE (1<<15) /* Humanize the value (for display styles) */
336
337#define XFF_HN_SPACE (1<<16) /* Humanize: put space before suffix */
338#define XFF_HN_DECIMAL (1<<17) /* Humanize: add one decimal place if <10 */
339#define XFF_HN_1000 (1<<18) /* Humanize: use 1000, not 1024 */
340#define XFF_GT_FIELD (1<<19) /* Call gettext() on a field */
341
342#define XFF_GT_PLURAL (1<<20) /* Call dngettext to find plural form */
343#define XFF_ARGUMENT (1<<21) /* Content provided via argument */
341
342/* Flags to turn off when we don't want i18n processing */
343#define XFF_GT_FLAGS (XFF_GT_FIELD | XFF_GT_PLURAL)
344
345/*
346 * Normal printf has width and precision, which for strings operate as
347 * min and max number of columns. But this depends on the idea that
348 * one byte means one column, which UTF-8 and multi-byte characters

--- 692 unchanged lines hidden (view full) ---

1041static int xo_utf8_bits[7] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
1042
1043static int
1044xo_is_utf8 (char ch)
1045{
1046 return (ch & 0x80);
1047}
1048
344
345/* Flags to turn off when we don't want i18n processing */
346#define XFF_GT_FLAGS (XFF_GT_FIELD | XFF_GT_PLURAL)
347
348/*
349 * Normal printf has width and precision, which for strings operate as
350 * min and max number of columns. But this depends on the idea that
351 * one byte means one column, which UTF-8 and multi-byte characters

--- 692 unchanged lines hidden (view full) ---

1044static int xo_utf8_bits[7] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
1045
1046static int
1047xo_is_utf8 (char ch)
1048{
1049 return (ch & 0x80);
1050}
1051
1049static int
1052static inline int
1050xo_utf8_to_wc_len (const char *buf)
1051{
1052 unsigned b = (unsigned char) *buf;
1053 int len;
1054
1055 if ((b & 0x80) == 0x0)
1056 len = 1;
1057 else if ((b & 0xe0) == 0xc0)

--- 42 unchanged lines hidden (view full) ---

1100 return len;
1101}
1102
1103/*
1104 * Build a wide character from the input buffer; the number of
1105 * bits we pull off the first character is dependent on the length,
1106 * but we put 6 bits off all other bytes.
1107 */
1053xo_utf8_to_wc_len (const char *buf)
1054{
1055 unsigned b = (unsigned char) *buf;
1056 int len;
1057
1058 if ((b & 0x80) == 0x0)
1059 len = 1;
1060 else if ((b & 0xe0) == 0xc0)

--- 42 unchanged lines hidden (view full) ---

1103 return len;
1104}
1105
1106/*
1107 * Build a wide character from the input buffer; the number of
1108 * bits we pull off the first character is dependent on the length,
1109 * but we put 6 bits off all other bytes.
1110 */
1108static wchar_t
1111static inline wchar_t
1109xo_utf8_char (const char *buf, int len)
1110{
1112xo_utf8_char (const char *buf, int len)
1113{
1114 /* Most common case: singleton byte */
1115 if (len == 1)
1116 return (unsigned char) buf[0];
1117
1111 int i;
1112 wchar_t wc;
1113 const unsigned char *cp = (const unsigned char *) buf;
1114
1115 wc = *cp & xo_utf8_bits[len];
1116 for (i = 1; i < len; i++) {
1117 wc <<= 6;
1118 wc |= cp[i] & 0x3f;

--- 157 unchanged lines hidden (view full) ---

1276 * Append the given string to the given buffer
1277 */
1278static void
1279xo_data_escape (xo_handle_t *xop, const char *str, int len)
1280{
1281 xo_buf_escape(xop, &xop->xo_data, str, len, 0);
1282}
1283
1118 int i;
1119 wchar_t wc;
1120 const unsigned char *cp = (const unsigned char *) buf;
1121
1122 wc = *cp & xo_utf8_bits[len];
1123 for (i = 1; i < len; i++) {
1124 wc <<= 6;
1125 wc |= cp[i] & 0x3f;

--- 157 unchanged lines hidden (view full) ---

1283 * Append the given string to the given buffer
1284 */
1285static void
1286xo_data_escape (xo_handle_t *xop, const char *str, int len)
1287{
1288 xo_buf_escape(xop, &xop->xo_data, str, len, 0);
1289}
1290
1291#ifdef LIBXO_NO_RETAIN
1284/*
1292/*
1293 * Empty implementations of the retain logic
1294 */
1295
1296void
1297xo_retain_clear_all (void)
1298{
1299 return;
1300}
1301
1302void
1303xo_retain_clear (const char *fmt UNUSED)
1304{
1305 return;
1306}
1307static void
1308xo_retain_add (const char *fmt UNUSED, xo_field_info_t *fields UNUSED,
1309 unsigned num_fields UNUSED)
1310{
1311 return;
1312}
1313
1314static int
1315xo_retain_find (const char *fmt UNUSED, xo_field_info_t **valp UNUSED,
1316 unsigned *nump UNUSED)
1317{
1318 return -1;
1319}
1320
1321#else /* !LIBXO_NO_RETAIN */
1322/*
1323 * Retain: We retain parsed field definitions to enhance performance,
1324 * especially inside loops. We depend on the caller treating the format
1325 * strings as immutable, so that we can retain pointers into them. We
1326 * hold the pointers in a hash table, so allow quick access. Retained
1327 * information is retained until xo_retain_clear is called.
1328 */
1329
1330/*
1331 * xo_retain_entry_t holds information about one retained set of
1332 * parsed fields.
1333 */
1334typedef struct xo_retain_entry_s {
1335 struct xo_retain_entry_s *xre_next; /* Pointer to next (older) entry */
1336 unsigned long xre_hits; /* Number of times we've hit */
1337 const char *xre_format; /* Pointer to format string */
1338 unsigned xre_num_fields; /* Number of fields saved */
1339 xo_field_info_t *xre_fields; /* Pointer to fields */
1340} xo_retain_entry_t;
1341
1342/*
1343 * xo_retain_t holds a complete set of parsed fields as a hash table.
1344 */
1345#ifndef XO_RETAIN_SIZE
1346#define XO_RETAIN_SIZE 6
1347#endif /* XO_RETAIN_SIZE */
1348#define RETAIN_HASH_SIZE (1<<XO_RETAIN_SIZE)
1349
1350typedef struct xo_retain_s {
1351 xo_retain_entry_t *xr_bucket[RETAIN_HASH_SIZE];
1352} xo_retain_t;
1353
1354static THREAD_LOCAL(xo_retain_t) xo_retain;
1355static THREAD_LOCAL(unsigned) xo_retain_count;
1356
1357/*
1358 * Simple hash function based on Thomas Wang's paper. The original is
1359 * gone, but an archive is available on the Way Back Machine:
1360 *
1361 * http://web.archive.org/web/20071223173210/\
1362 * http://www.concentric.net/~Ttwang/tech/inthash.htm
1363 *
1364 * For our purposes, we can assume the low four bits are uninteresting
1365 * since any string less that 16 bytes wouldn't be worthy of
1366 * retaining. We toss the high bits also, since these bits are likely
1367 * to be common among constant format strings. We then run Wang's
1368 * algorithm, and cap the result at RETAIN_HASH_SIZE.
1369 */
1370static unsigned
1371xo_retain_hash (const char *fmt)
1372{
1373 volatile uintptr_t iptr = (uintptr_t) (const void *) fmt;
1374
1375 /* Discard low four bits and high bits; they aren't interesting */
1376 uint32_t val = (uint32_t) ((iptr >> 4) & (((1 << 24) - 1)));
1377
1378 val = (val ^ 61) ^ (val >> 16);
1379 val = val + (val << 3);
1380 val = val ^ (val >> 4);
1381 val = val * 0x3a8f05c5; /* My large prime number */
1382 val = val ^ (val >> 15);
1383 val &= RETAIN_HASH_SIZE - 1;
1384
1385 return val;
1386}
1387
1388/*
1389 * Walk all buckets, clearing all retained entries
1390 */
1391void
1392xo_retain_clear_all (void)
1393{
1394 int i;
1395 xo_retain_entry_t *xrep, *next;
1396
1397 for (i = 0; i < RETAIN_HASH_SIZE; i++) {
1398 for (xrep = xo_retain.xr_bucket[i]; xrep; xrep = next) {
1399 next = xrep->xre_next;
1400 xo_free(xrep);
1401 }
1402 xo_retain.xr_bucket[i] = NULL;
1403 }
1404 xo_retain_count = 0;
1405}
1406
1407/*
1408 * Walk all buckets, clearing all retained entries
1409 */
1410void
1411xo_retain_clear (const char *fmt)
1412{
1413 xo_retain_entry_t **xrepp;
1414 unsigned hash = xo_retain_hash(fmt);
1415
1416 for (xrepp = &xo_retain.xr_bucket[hash]; *xrepp;
1417 xrepp = &(*xrepp)->xre_next) {
1418 if ((*xrepp)->xre_format == fmt) {
1419 *xrepp = (*xrepp)->xre_next;
1420 xo_retain_count -= 1;
1421 return;
1422 }
1423 }
1424}
1425
1426/*
1427 * Search the hash for an entry matching 'fmt'; return it's fields.
1428 */
1429static int
1430xo_retain_find (const char *fmt, xo_field_info_t **valp, unsigned *nump)
1431{
1432 if (xo_retain_count == 0)
1433 return -1;
1434
1435 unsigned hash = xo_retain_hash(fmt);
1436 xo_retain_entry_t *xrep;
1437
1438 for (xrep = xo_retain.xr_bucket[hash]; xrep != NULL;
1439 xrep = xrep->xre_next) {
1440 if (xrep->xre_format == fmt) {
1441 *valp = xrep->xre_fields;
1442 *nump = xrep->xre_num_fields;
1443 xrep->xre_hits += 1;
1444 return 0;
1445 }
1446 }
1447
1448 return -1;
1449}
1450
1451static void
1452xo_retain_add (const char *fmt, xo_field_info_t *fields, unsigned num_fields)
1453{
1454 unsigned hash = xo_retain_hash(fmt);
1455 xo_retain_entry_t *xrep;
1456 unsigned sz = sizeof(*xrep) + (num_fields + 1) * sizeof(*fields);
1457 xo_field_info_t *xfip;
1458
1459 xrep = xo_realloc(NULL, sz);
1460 if (xrep == NULL)
1461 return;
1462
1463 xfip = (xo_field_info_t *) &xrep[1];
1464 memcpy(xfip, fields, num_fields * sizeof(*fields));
1465
1466 bzero(xrep, sizeof(*xrep));
1467
1468 xrep->xre_format = fmt;
1469 xrep->xre_fields = xfip;
1470 xrep->xre_num_fields = num_fields;
1471
1472 /* Record the field info in the retain bucket */
1473 xrep->xre_next = xo_retain.xr_bucket[hash];
1474 xo_retain.xr_bucket[hash] = xrep;
1475 xo_retain_count += 1;
1476}
1477
1478#endif /* !LIBXO_NO_RETAIN */
1479
1480/*
1285 * Generate a warning. Normally, this is a text message written to
1286 * standard error. If the XOF_WARN_XML flag is set, then we generate
1287 * XMLified content on standard output.
1288 */
1289static void
1290xo_warn_hcv (xo_handle_t *xop, int code, int check_warn,
1291 const char *fmt, va_list vap)
1292{

--- 276 unchanged lines hidden (view full) ---

1569 }
1570 }
1571 if (need_nl)
1572 xo_printf(xop, "\n");
1573
1574 break;
1575 }
1576
1481 * Generate a warning. Normally, this is a text message written to
1482 * standard error. If the XOF_WARN_XML flag is set, then we generate
1483 * XMLified content on standard output.
1484 */
1485static void
1486xo_warn_hcv (xo_handle_t *xop, int code, int check_warn,
1487 const char *fmt, va_list vap)
1488{

--- 276 unchanged lines hidden (view full) ---

1765 }
1766 }
1767 if (need_nl)
1768 xo_printf(xop, "\n");
1769
1770 break;
1771 }
1772
1773 switch (xo_style(xop)) {
1774 case XO_STYLE_HTML:
1775 if (XOIF_ISSET(xop, XOIF_DIV_OPEN)) {
1776 static char div_close[] = "</div>";
1777 XOIF_CLEAR(xop, XOIF_DIV_OPEN);
1778 xo_data_append(xop, div_close, sizeof(div_close) - 1);
1779
1780 if (XOF_ISSET(xop, XOF_PRETTY))
1781 xo_data_append(xop, "\n", 1);
1782 }
1783 break;
1784 }
1785
1577 (void) xo_flush_h(xop);
1578}
1579
1580void
1581xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...)
1582{
1583 va_list vap;
1584

--- 90 unchanged lines hidden (view full) ---

1675 xop->xo_close = xo_close_file;
1676 xop->xo_flush = xo_flush_file;
1677 }
1678
1679 return xop;
1680}
1681
1682/**
1786 (void) xo_flush_h(xop);
1787}
1788
1789void
1790xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...)
1791{
1792 va_list vap;
1793

--- 90 unchanged lines hidden (view full) ---

1884 xop->xo_close = xo_close_file;
1885 xop->xo_flush = xo_flush_file;
1886 }
1887
1888 return xop;
1889}
1890
1891/**
1892 * Set the default handler to output to a file.
1893 * @xop libxo handle
1894 * @fp FILE pointer to use
1895 */
1896int
1897xo_set_file_h (xo_handle_t *xop, FILE *fp)
1898{
1899 xop = xo_default(xop);
1900
1901 if (fp == NULL) {
1902 xo_failure(xop, "xo_set_file: NULL fp");
1903 return -1;
1904 }
1905
1906 xop->xo_opaque = fp;
1907 xop->xo_write = xo_write_to_file;
1908 xop->xo_close = xo_close_file;
1909 xop->xo_flush = xo_flush_file;
1910
1911 return 0;
1912}
1913
1914/**
1915 * Set the default handler to output to a file.
1916 * @fp FILE pointer to use
1917 */
1918int
1919xo_set_file (FILE *fp)
1920{
1921 return xo_set_file_h(NULL, fp);
1922}
1923
1924/**
1683 * Release any resources held by the handle.
1684 * @xop XO handle to alter (or NULL for default handle)
1685 */
1686void
1687xo_destroy (xo_handle_t *xop_arg)
1688{
1689 xo_handle_t *xop = xo_default(xop_arg);
1690

--- 128 unchanged lines hidden (view full) ---

1819 { XOF_FLUSH, "flush" },
1820 { XOF_IGNORE_CLOSE, "ignore-close" },
1821 { XOF_INFO, "info" },
1822 { XOF_KEYS, "keys" },
1823 { XOF_LOG_GETTEXT, "log-gettext" },
1824 { XOF_LOG_SYSLOG, "log-syslog" },
1825 { XOF_NO_HUMANIZE, "no-humanize" },
1826 { XOF_NO_LOCALE, "no-locale" },
1925 * Release any resources held by the handle.
1926 * @xop XO handle to alter (or NULL for default handle)
1927 */
1928void
1929xo_destroy (xo_handle_t *xop_arg)
1930{
1931 xo_handle_t *xop = xo_default(xop_arg);
1932

--- 128 unchanged lines hidden (view full) ---

2061 { XOF_FLUSH, "flush" },
2062 { XOF_IGNORE_CLOSE, "ignore-close" },
2063 { XOF_INFO, "info" },
2064 { XOF_KEYS, "keys" },
2065 { XOF_LOG_GETTEXT, "log-gettext" },
2066 { XOF_LOG_SYSLOG, "log-syslog" },
2067 { XOF_NO_HUMANIZE, "no-humanize" },
2068 { XOF_NO_LOCALE, "no-locale" },
2069 { XOF_RETAIN_NONE, "no-retain" },
1827 { XOF_NO_TOP, "no-top" },
1828 { XOF_NOT_FIRST, "not-first" },
1829 { XOF_PRETTY, "pretty" },
2070 { XOF_NO_TOP, "no-top" },
2071 { XOF_NOT_FIRST, "not-first" },
2072 { XOF_PRETTY, "pretty" },
2073 { XOF_RETAIN_ALL, "retain" },
1830 { XOF_UNDERSCORES, "underscores" },
1831 { XOF_UNITS, "units" },
1832 { XOF_WARN, "warn" },
1833 { XOF_WARN_XML, "warn-xml" },
1834 { XOF_XPATH, "xpath" },
1835 { 0, NULL }
1836};
1837

--- 1770 unchanged lines hidden (view full) ---

3608
3609 case XO_STYLE_HTML:
3610 xo_buf_append_div(xop, "text", 0, NULL, 0, str, len, NULL, 0);
3611 break;
3612 }
3613}
3614
3615static void
2074 { XOF_UNDERSCORES, "underscores" },
2075 { XOF_UNITS, "units" },
2076 { XOF_WARN, "warn" },
2077 { XOF_WARN_XML, "warn-xml" },
2078 { XOF_XPATH, "xpath" },
2079 { 0, NULL }
2080};
2081

--- 1770 unchanged lines hidden (view full) ---

3852
3853 case XO_STYLE_HTML:
3854 xo_buf_append_div(xop, "text", 0, NULL, 0, str, len, NULL, 0);
3855 break;
3856 }
3857}
3858
3859static void
3616xo_format_title (xo_handle_t *xop, xo_field_info_t *xfip)
3860xo_format_title (xo_handle_t *xop, xo_field_info_t *xfip,
3861 const char *str, unsigned len)
3617{
3862{
3618 const char *str = xfip->xfi_content;
3619 unsigned len = xfip->xfi_clen;
3620 const char *fmt = xfip->xfi_format;
3621 unsigned flen = xfip->xfi_flen;
3622 xo_xff_flags_t flags = xfip->xfi_flags;
3623
3624 static char div_open[] = "<div class=\"title";
3625 static char div_middle[] = "\">";
3626 static char div_close[] = "</div>";
3627

--- 450 unchanged lines hidden (view full) ---

4078 xo_buf_data(&xop->xo_data, name_offset),
4079 xo_buf_data(&xop->xo_data, value_offset));
4080 xo_buf_reset(&xop->xo_data);
4081 break;
4082 }
4083}
4084
4085static void
3863 const char *fmt = xfip->xfi_format;
3864 unsigned flen = xfip->xfi_flen;
3865 xo_xff_flags_t flags = xfip->xfi_flags;
3866
3867 static char div_open[] = "<div class=\"title";
3868 static char div_middle[] = "\">";
3869 static char div_close[] = "</div>";
3870

--- 450 unchanged lines hidden (view full) ---

4321 xo_buf_data(&xop->xo_data, name_offset),
4322 xo_buf_data(&xop->xo_data, value_offset));
4323 xo_buf_reset(&xop->xo_data);
4324 break;
4325 }
4326}
4327
4328static void
4086xo_set_gettext_domain (xo_handle_t *xop, xo_field_info_t *xfip)
4329xo_set_gettext_domain (xo_handle_t *xop, xo_field_info_t *xfip,
4330 const char *str, unsigned len)
4087{
4331{
4088 const char *str = xfip->xfi_content;
4089 unsigned len = xfip->xfi_clen;
4090 const char *fmt = xfip->xfi_format;
4091 unsigned flen = xfip->xfi_flen;
4092
4093 /* Start by discarding previous domain */
4094 if (xop->xo_gt_domain) {
4095 xo_free(xop->xo_gt_domain);
4096 xop->xo_gt_domain = NULL;
4097 }

--- 232 unchanged lines hidden (view full) ---

4330#ifdef LIBXO_TEXT_ONLY
4331 return 0;
4332#else /* LIBXO_TEXT_ONLY */
4333 return XOF_ISSET(xop, XOF_COLOR);
4334#endif /* LIBXO_TEXT_ONLY */
4335}
4336
4337static void
4332 const char *fmt = xfip->xfi_format;
4333 unsigned flen = xfip->xfi_flen;
4334
4335 /* Start by discarding previous domain */
4336 if (xop->xo_gt_domain) {
4337 xo_free(xop->xo_gt_domain);
4338 xop->xo_gt_domain = NULL;
4339 }

--- 232 unchanged lines hidden (view full) ---

4572#ifdef LIBXO_TEXT_ONLY
4573 return 0;
4574#else /* LIBXO_TEXT_ONLY */
4575 return XOF_ISSET(xop, XOF_COLOR);
4576#endif /* LIBXO_TEXT_ONLY */
4577}
4578
4579static void
4338xo_colors_handle_text (xo_handle_t *xop UNUSED, xo_colors_t *newp)
4580xo_colors_handle_text (xo_handle_t *xop, xo_colors_t *newp)
4339{
4340 char buf[BUFSIZ];
4341 char *cp = buf, *ep = buf + sizeof(buf);
4342 unsigned i, bit;
4343 xo_colors_t *oldp = &xop->xo_colors;
4581{
4582 char buf[BUFSIZ];
4583 char *cp = buf, *ep = buf + sizeof(buf);
4584 unsigned i, bit;
4585 xo_colors_t *oldp = &xop->xo_colors;
4344 const char *code;
4586 const char *code = NULL;
4345
4346 /*
4347 * Start the buffer with an escape. We don't want to add the '['
4348 * now, since we let xo_effect_text_add unconditionally add the ';'.
4349 * We'll replace the first ';' with a '[' when we're done.
4350 */
4351 *cp++ = 0x1b; /* Escape */
4352

--- 102 unchanged lines hidden (view full) ---

4455
4456 if (bg) {
4457 xo_buf_append_str(xbp, " color-bg-");
4458 xo_buf_append_str(xbp, bg);
4459 }
4460}
4461
4462static void
4587
4588 /*
4589 * Start the buffer with an escape. We don't want to add the '['
4590 * now, since we let xo_effect_text_add unconditionally add the ';'.
4591 * We'll replace the first ';' with a '[' when we're done.
4592 */
4593 *cp++ = 0x1b; /* Escape */
4594

--- 102 unchanged lines hidden (view full) ---

4697
4698 if (bg) {
4699 xo_buf_append_str(xbp, " color-bg-");
4700 xo_buf_append_str(xbp, bg);
4701 }
4702}
4703
4704static void
4463xo_format_colors (xo_handle_t *xop, xo_field_info_t *xfip)
4705xo_format_colors (xo_handle_t *xop, xo_field_info_t *xfip,
4706 const char *str, unsigned len)
4464{
4707{
4465 const char *str = xfip->xfi_content;
4466 unsigned len = xfip->xfi_clen;
4467 const char *fmt = xfip->xfi_format;
4468 unsigned flen = xfip->xfi_flen;
4469
4470 xo_buffer_t xb;
4471
4472 /* If the string is static and we've in an encoding style, bail */
4473 if (len != 0 && xo_style_is_encoding(xop))
4474 return;

--- 54 unchanged lines hidden (view full) ---

4529 break;
4530 }
4531 }
4532
4533 xo_buf_cleanup(&xb);
4534}
4535
4536static void
4708 const char *fmt = xfip->xfi_format;
4709 unsigned flen = xfip->xfi_flen;
4710
4711 xo_buffer_t xb;
4712
4713 /* If the string is static and we've in an encoding style, bail */
4714 if (len != 0 && xo_style_is_encoding(xop))
4715 return;

--- 54 unchanged lines hidden (view full) ---

4770 break;
4771 }
4772 }
4773
4774 xo_buf_cleanup(&xb);
4775}
4776
4777static void
4537xo_format_units (xo_handle_t *xop, xo_field_info_t *xfip)
4778xo_format_units (xo_handle_t *xop, xo_field_info_t *xfip,
4779 const char *str, unsigned len)
4538{
4780{
4539 const char *str = xfip->xfi_content;
4540 unsigned len = xfip->xfi_clen;
4541 const char *fmt = xfip->xfi_format;
4542 unsigned flen = xfip->xfi_flen;
4543 xo_xff_flags_t flags = xfip->xfi_flags;
4544
4545 static char units_start_xml[] = " units=\"";
4546 static char units_start_html[] = " data-units=\"";
4547
4548 if (!XOIF_ISSET(xop, XOIF_UNITS_PENDING)) {

--- 35 unchanged lines hidden (view full) ---

4584 char *buf = alloca(delta);
4585
4586 memcpy(buf, xbp->xb_bufp + stop, delta);
4587 memmove(xbp->xb_bufp + start + delta, xbp->xb_bufp + start, stop - start);
4588 memmove(xbp->xb_bufp + start, buf, delta);
4589}
4590
4591static int
4781 const char *fmt = xfip->xfi_format;
4782 unsigned flen = xfip->xfi_flen;
4783 xo_xff_flags_t flags = xfip->xfi_flags;
4784
4785 static char units_start_xml[] = " units=\"";
4786 static char units_start_html[] = " data-units=\"";
4787
4788 if (!XOIF_ISSET(xop, XOIF_UNITS_PENDING)) {

--- 35 unchanged lines hidden (view full) ---

4824 char *buf = alloca(delta);
4825
4826 memcpy(buf, xbp->xb_bufp + stop, delta);
4827 memmove(xbp->xb_bufp + start + delta, xbp->xb_bufp + start, stop - start);
4828 memmove(xbp->xb_bufp + start, buf, delta);
4829}
4830
4831static int
4592xo_find_width (xo_handle_t *xop, xo_field_info_t *xfip)
4832xo_find_width (xo_handle_t *xop, xo_field_info_t *xfip,
4833 const char *str, unsigned len)
4593{
4834{
4594 const char *str = xfip->xfi_content;
4595 unsigned len = xfip->xfi_clen;
4596 const char *fmt = xfip->xfi_format;
4597 unsigned flen = xfip->xfi_flen;
4598
4599 long width = 0;
4600 char *bp;
4601 char *cp;
4602
4603 if (len) {

--- 30 unchanged lines hidden (view full) ---

4634 * An anchor is a marker used to delay field width implications.
4635 * Imagine the format string "{[:10}{min:%d}/{cur:%d}/{max:%d}{:]}".
4636 * We are looking for output like " 1/4/5"
4637 *
4638 * To make this work, we record the anchor and then return to
4639 * format it when the end anchor tag is seen.
4640 */
4641static void
4835 const char *fmt = xfip->xfi_format;
4836 unsigned flen = xfip->xfi_flen;
4837
4838 long width = 0;
4839 char *bp;
4840 char *cp;
4841
4842 if (len) {

--- 30 unchanged lines hidden (view full) ---

4873 * An anchor is a marker used to delay field width implications.
4874 * Imagine the format string "{[:10}{min:%d}/{cur:%d}/{max:%d}{:]}".
4875 * We are looking for output like " 1/4/5"
4876 *
4877 * To make this work, we record the anchor and then return to
4878 * format it when the end anchor tag is seen.
4879 */
4880static void
4642xo_anchor_start (xo_handle_t *xop, xo_field_info_t *xfip)
4881xo_anchor_start (xo_handle_t *xop, xo_field_info_t *xfip,
4882 const char *str, unsigned len)
4643{
4644 if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
4645 return;
4646
4647 if (XOIF_ISSET(xop, XOIF_ANCHOR))
4648 xo_failure(xop, "the anchor already recording is discarded");
4649
4650 XOIF_SET(xop, XOIF_ANCHOR);
4651 xo_buffer_t *xbp = &xop->xo_data;
4652 xop->xo_anchor_offset = xbp->xb_curp - xbp->xb_bufp;
4653 xop->xo_anchor_columns = 0;
4654
4655 /*
4656 * Now we find the width, if possible. If it's not there,
4657 * we'll get it on the end anchor.
4658 */
4883{
4884 if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
4885 return;
4886
4887 if (XOIF_ISSET(xop, XOIF_ANCHOR))
4888 xo_failure(xop, "the anchor already recording is discarded");
4889
4890 XOIF_SET(xop, XOIF_ANCHOR);
4891 xo_buffer_t *xbp = &xop->xo_data;
4892 xop->xo_anchor_offset = xbp->xb_curp - xbp->xb_bufp;
4893 xop->xo_anchor_columns = 0;
4894
4895 /*
4896 * Now we find the width, if possible. If it's not there,
4897 * we'll get it on the end anchor.
4898 */
4659 xop->xo_anchor_min_width = xo_find_width(xop, xfip);
4899 xop->xo_anchor_min_width = xo_find_width(xop, xfip, str, len);
4660}
4661
4662static void
4900}
4901
4902static void
4663xo_anchor_stop (xo_handle_t *xop, xo_field_info_t *xfip)
4903xo_anchor_stop (xo_handle_t *xop, xo_field_info_t *xfip,
4904 const char *str, unsigned len)
4664{
4665 if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
4666 return;
4667
4668 if (!XOIF_ISSET(xop, XOIF_ANCHOR)) {
4669 xo_failure(xop, "no start anchor");
4670 return;
4671 }
4672
4673 XOIF_CLEAR(xop, XOIF_UNITS_PENDING);
4674
4905{
4906 if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
4907 return;
4908
4909 if (!XOIF_ISSET(xop, XOIF_ANCHOR)) {
4910 xo_failure(xop, "no start anchor");
4911 return;
4912 }
4913
4914 XOIF_CLEAR(xop, XOIF_UNITS_PENDING);
4915
4675 int width = xo_find_width(xop, xfip);
4916 int width = xo_find_width(xop, xfip, str, len);
4676 if (width == 0)
4677 width = xop->xo_anchor_min_width;
4678
4679 if (width == 0) /* No width given; nothing to do */
4680 goto done;
4681
4682 xo_buffer_t *xbp = &xop->xo_data;
4683 int start = xop->xo_anchor_offset;

--- 98 unchanged lines hidden (view full) ---

4782 { 0, NULL }
4783};
4784
4785#define XO_ROLE_EBRACE '{' /* Escaped braces */
4786#define XO_ROLE_TEXT '+'
4787#define XO_ROLE_NEWLINE '\n'
4788
4789static xo_mapping_t xo_modifier_names[] = {
4917 if (width == 0)
4918 width = xop->xo_anchor_min_width;
4919
4920 if (width == 0) /* No width given; nothing to do */
4921 goto done;
4922
4923 xo_buffer_t *xbp = &xop->xo_data;
4924 int start = xop->xo_anchor_offset;

--- 98 unchanged lines hidden (view full) ---

5023 { 0, NULL }
5024};
5025
5026#define XO_ROLE_EBRACE '{' /* Escaped braces */
5027#define XO_ROLE_TEXT '+'
5028#define XO_ROLE_NEWLINE '\n'
5029
5030static xo_mapping_t xo_modifier_names[] = {
5031 { XFF_ARGUMENT, "argument" },
4790 { XFF_COLON, "colon" },
4791 { XFF_COMMA, "comma" },
4792 { XFF_DISPLAY_ONLY, "display" },
4793 { XFF_ENCODE_ONLY, "encoding" },
4794 { XFF_GT_FIELD, "gettext" },
4795 { XFF_HUMANIZE, "humanize" },
4796 { XFF_HUMANIZE, "hn" },
4797 { XFF_HN_SPACE, "hn-space" },

--- 55 unchanged lines hidden (view full) ---

4853 * 'P': padding; whitespace
4854 * 'T': Title, where 'content' is a column title
4855 * 'U': Units, where 'content' is the unit label
4856 * 'V': value, where 'content' is the name of the field (the default)
4857 * 'W': warning message
4858 * '[': start a section of anchored text
4859 * ']': end a section of anchored text
4860 * The following modifiers are also supported:
5032 { XFF_COLON, "colon" },
5033 { XFF_COMMA, "comma" },
5034 { XFF_DISPLAY_ONLY, "display" },
5035 { XFF_ENCODE_ONLY, "encoding" },
5036 { XFF_GT_FIELD, "gettext" },
5037 { XFF_HUMANIZE, "humanize" },
5038 { XFF_HUMANIZE, "hn" },
5039 { XFF_HN_SPACE, "hn-space" },

--- 55 unchanged lines hidden (view full) ---

5095 * 'P': padding; whitespace
5096 * 'T': Title, where 'content' is a column title
5097 * 'U': Units, where 'content' is the unit label
5098 * 'V': value, where 'content' is the name of the field (the default)
5099 * 'W': warning message
5100 * '[': start a section of anchored text
5101 * ']': end a section of anchored text
5102 * The following modifiers are also supported:
5103 * 'a': content is provided via argument (const char *), not descriptor
4861 * 'c': flag: emit a colon after the label
4862 * 'd': field is only emitted for display styles (text and html)
4863 * 'e': field is only emitted for encoding styles (xml and json)
4864 * 'g': gettext() the field
4865 * 'h': humanize a numeric value (only for display styles)
4866 * 'k': this field is a key, suitable for XPath predicates
4867 * 'l': a leaf-list, a simple list of values
4868 * 'n': no quotes around this field

--- 10 unchanged lines hidden (view full) ---

4879xo_parse_roles (xo_handle_t *xop, const char *fmt,
4880 const char *basep, xo_field_info_t *xfip)
4881{
4882 const char *sp;
4883 unsigned ftype = 0;
4884 xo_xff_flags_t flags = 0;
4885 uint8_t fnum = 0;
4886
5104 * 'c': flag: emit a colon after the label
5105 * 'd': field is only emitted for display styles (text and html)
5106 * 'e': field is only emitted for encoding styles (xml and json)
5107 * 'g': gettext() the field
5108 * 'h': humanize a numeric value (only for display styles)
5109 * 'k': this field is a key, suitable for XPath predicates
5110 * 'l': a leaf-list, a simple list of values
5111 * 'n': no quotes around this field

--- 10 unchanged lines hidden (view full) ---

5122xo_parse_roles (xo_handle_t *xop, const char *fmt,
5123 const char *basep, xo_field_info_t *xfip)
5124{
5125 const char *sp;
5126 unsigned ftype = 0;
5127 xo_xff_flags_t flags = 0;
5128 uint8_t fnum = 0;
5129
4887 for (sp = basep; sp; sp++) {
5130 for (sp = basep; sp && *sp; sp++) {
4888 if (*sp == ':' || *sp == '/' || *sp == '}')
4889 break;
4890
4891 if (*sp == '\\') {
4892 if (sp[1] == '\0') {
4893 xo_failure(xop, "backslash at the end of string");
4894 return NULL;
4895 }

--- 60 unchanged lines hidden (view full) ---

4956 case '5':
4957 case '6':
4958 case '7':
4959 case '8':
4960 case '9':
4961 fnum = (fnum * 10) + (*sp - '0');
4962 break;
4963
5131 if (*sp == ':' || *sp == '/' || *sp == '}')
5132 break;
5133
5134 if (*sp == '\\') {
5135 if (sp[1] == '\0') {
5136 xo_failure(xop, "backslash at the end of string");
5137 return NULL;
5138 }

--- 60 unchanged lines hidden (view full) ---

5199 case '5':
5200 case '6':
5201 case '7':
5202 case '8':
5203 case '9':
5204 fnum = (fnum * 10) + (*sp - '0');
5205 break;
5206
5207 case 'a':
5208 flags |= XFF_ARGUMENT;
5209 break;
5210
4964 case 'c':
4965 flags |= XFF_COLON;
4966 break;
4967
4968 case 'd':
4969 flags |= XFF_DISPLAY_ONLY;
4970 break;
4971

--- 156 unchanged lines hidden (view full) ---

5128
5129 return 0;
5130}
5131
5132static int
5133xo_parse_fields (xo_handle_t *xop, xo_field_info_t *fields,
5134 unsigned num_fields, const char *fmt)
5135{
5211 case 'c':
5212 flags |= XFF_COLON;
5213 break;
5214
5215 case 'd':
5216 flags |= XFF_DISPLAY_ONLY;
5217 break;
5218

--- 156 unchanged lines hidden (view full) ---

5375
5376 return 0;
5377}
5378
5379static int
5380xo_parse_fields (xo_handle_t *xop, xo_field_info_t *fields,
5381 unsigned num_fields, const char *fmt)
5382{
5136 static const char default_format[] = "%s";
5137 const char *cp, *sp, *ep, *basep;
5138 unsigned field = 0;
5139 xo_field_info_t *xfip = fields;
5140 unsigned seen_fnum = 0;
5141
5142 for (cp = fmt; *cp && field < num_fields; field++, xfip++) {
5143 xfip->xfi_start = cp;
5144

--- 117 unchanged lines hidden (view full) ---

5262 xo_failure(xop, "missing closing '}': %s", xo_printable(fmt));
5263 return -1;
5264 }
5265
5266 xfip->xfi_len = sp - xfip->xfi_start;
5267 xfip->xfi_next = ++sp;
5268
5269 /* If we have content, then we have a default format */
5383 const char *cp, *sp, *ep, *basep;
5384 unsigned field = 0;
5385 xo_field_info_t *xfip = fields;
5386 unsigned seen_fnum = 0;
5387
5388 for (cp = fmt; *cp && field < num_fields; field++, xfip++) {
5389 xfip->xfi_start = cp;
5390

--- 117 unchanged lines hidden (view full) ---

5508 xo_failure(xop, "missing closing '}': %s", xo_printable(fmt));
5509 return -1;
5510 }
5511
5512 xfip->xfi_len = sp - xfip->xfi_start;
5513 xfip->xfi_next = ++sp;
5514
5515 /* If we have content, then we have a default format */
5270 if (xfip->xfi_clen || format) {
5516 if (xfip->xfi_clen || format || (xfip->xfi_flags & XFF_ARGUMENT)) {
5271 if (format) {
5272 xfip->xfi_format = format;
5273 xfip->xfi_flen = flen;
5274 } else if (xo_role_wants_default_format(xfip->xfi_ftype)) {
5517 if (format) {
5518 xfip->xfi_format = format;
5519 xfip->xfi_flen = flen;
5520 } else if (xo_role_wants_default_format(xfip->xfi_ftype)) {
5275 xfip->xfi_format = default_format;
5521 xfip->xfi_format = xo_default_format;
5276 xfip->xfi_flen = 2;
5277 }
5278 }
5279
5280 cp = sp;
5281 }
5282
5283 int rc = 0;

--- 279 unchanged lines hidden (view full) ---

5563 * format string:
5564 * "cluse-a {:fd} retoorned {:test}. Bork {:error} Bork. Bork.\n"
5565 * If we have to reorder fields within the message, then things get
5566 * complicated. See xo_gettext_rewrite_fields.
5567 *
5568 * Summary: i18n aighn't cheap.
5569 */
5570static const char *
5522 xfip->xfi_flen = 2;
5523 }
5524 }
5525
5526 cp = sp;
5527 }
5528
5529 int rc = 0;

--- 279 unchanged lines hidden (view full) ---

5809 * format string:
5810 * "cluse-a {:fd} retoorned {:test}. Bork {:error} Bork. Bork.\n"
5811 * If we have to reorder fields within the message, then things get
5812 * complicated. See xo_gettext_rewrite_fields.
5813 *
5814 * Summary: i18n aighn't cheap.
5815 */
5816static const char *
5571xo_gettext_build_format (xo_handle_t *xop UNUSED,
5572 xo_field_info_t *fields UNUSED,
5573 int this_field UNUSED,
5817xo_gettext_build_format (xo_handle_t *xop,
5818 xo_field_info_t *fields, int this_field,
5574 const char *fmt, char **new_fmtp)
5575{
5576 if (xo_style_is_encoding(xop))
5577 goto bail;
5578
5579 xo_buffer_t xb;
5580 xo_buf_init(&xb);
5581

--- 99 unchanged lines hidden (view full) ---

5681 unsigned *fstart UNUSED, unsigned min_fstart UNUSED,
5682 unsigned *fend UNUSED, unsigned max_fend UNUSED)
5683{
5684 return;
5685}
5686#endif /* HAVE_GETTEXT */
5687
5688/*
5819 const char *fmt, char **new_fmtp)
5820{
5821 if (xo_style_is_encoding(xop))
5822 goto bail;
5823
5824 xo_buffer_t xb;
5825 xo_buf_init(&xb);
5826

--- 99 unchanged lines hidden (view full) ---

5926 unsigned *fstart UNUSED, unsigned min_fstart UNUSED,
5927 unsigned *fend UNUSED, unsigned max_fend UNUSED)
5928{
5929 return;
5930}
5931#endif /* HAVE_GETTEXT */
5932
5933/*
5689 * The central function for emitting libxo output.
5934 * Emit a set of fields. This is really the core of libxo.
5690 */
5691static int
5935 */
5936static int
5692xo_do_emit (xo_handle_t *xop, const char *fmt)
5937xo_do_emit_fields (xo_handle_t *xop, xo_field_info_t *fields,
5938 unsigned max_fields, const char *fmt)
5693{
5694 int gettext_inuse = 0;
5695 int gettext_changed = 0;
5696 int gettext_reordered = 0;
5939{
5940 int gettext_inuse = 0;
5941 int gettext_changed = 0;
5942 int gettext_reordered = 0;
5943 unsigned ftype;
5944 xo_xff_flags_t flags;
5697 xo_field_info_t *new_fields = NULL;
5945 xo_field_info_t *new_fields = NULL;
5698
5946 xo_field_info_t *xfip;
5947 unsigned field;
5699 int rc = 0;
5948 int rc = 0;
5949
5700 int flush = XOF_ISSET(xop, XOF_FLUSH);
5701 int flush_line = XOF_ISSET(xop, XOF_FLUSH_LINE);
5702 char *new_fmt = NULL;
5703
5704 if (XOIF_ISSET(xop, XOIF_REORDER) || xo_style(xop) == XO_STYLE_ENCODER)
5705 flush_line = 0;
5706
5950 int flush = XOF_ISSET(xop, XOF_FLUSH);
5951 int flush_line = XOF_ISSET(xop, XOF_FLUSH_LINE);
5952 char *new_fmt = NULL;
5953
5954 if (XOIF_ISSET(xop, XOIF_REORDER) || xo_style(xop) == XO_STYLE_ENCODER)
5955 flush_line = 0;
5956
5707 xop->xo_columns = 0; /* Always reset it */
5708 xop->xo_errno = errno; /* Save for "%m" */
5709
5710 unsigned max_fields = xo_count_fields(xop, fmt), field;
5711 xo_field_info_t fields[max_fields], *xfip;
5712
5713 bzero(fields, max_fields * sizeof(fields[0]));
5714
5715 if (xo_parse_fields(xop, fields, max_fields, fmt))
5716 return -1; /* Warning already displayed */
5717
5718 unsigned ftype;
5719 xo_xff_flags_t flags;
5720
5721 /*
5722 * Some overhead for gettext; if the fields in the msgstr returned
5723 * by gettext are reordered, then we need to record start and end
5724 * for each field. We'll go ahead and render the fields in the
5725 * normal order, but later we can then reconstruct the reordered
5726 * fields using these fstart/fend values.
5727 */
5728 unsigned flimit = max_fields * 2; /* Pessimistic limit */

--- 11 unchanged lines hidden (view full) ---

5740
5741 /* Record field start offset */
5742 if (gettext_reordered) {
5743 fstart[field] = xo_buf_offset(&xop->xo_data);
5744 if (min_fstart > field)
5745 min_fstart = field;
5746 }
5747
5957 /*
5958 * Some overhead for gettext; if the fields in the msgstr returned
5959 * by gettext are reordered, then we need to record start and end
5960 * for each field. We'll go ahead and render the fields in the
5961 * normal order, but later we can then reconstruct the reordered
5962 * fields using these fstart/fend values.
5963 */
5964 unsigned flimit = max_fields * 2; /* Pessimistic limit */

--- 11 unchanged lines hidden (view full) ---

5976
5977 /* Record field start offset */
5978 if (gettext_reordered) {
5979 fstart[field] = xo_buf_offset(&xop->xo_data);
5980 if (min_fstart > field)
5981 min_fstart = field;
5982 }
5983
5984 const char *content = xfip->xfi_content;
5985 int clen = xfip->xfi_clen;
5986
5987 if (flags & XFF_ARGUMENT) {
5988 /*
5989 * Argument flag means the content isn't given in the descriptor,
5990 * but as a UTF-8 string ('const char *') argument in xo_vap.
5991 */
5992 content = va_arg(xop->xo_vap, char *);
5993 clen = content ? strlen(content) : 0;
5994 }
5995
5748 if (ftype == XO_ROLE_NEWLINE) {
5749 xo_line_close(xop);
5750 if (flush_line && xo_flush_h(xop) < 0)
5751 return -1;
5752 goto bottom;
5753
5754 } else if (ftype == XO_ROLE_EBRACE) {
5755 xo_format_text(xop, xfip->xfi_start, xfip->xfi_len);

--- 12 unchanged lines hidden (view full) ---

5768 if (flags & XFF_WS) {
5769 xo_format_content(xop, "padding", NULL, " ", 1,
5770 NULL, 0, flags);
5771 flags &= ~XFF_WS; /* Block later handling of this */
5772 }
5773 }
5774
5775 if (ftype == 'V')
5996 if (ftype == XO_ROLE_NEWLINE) {
5997 xo_line_close(xop);
5998 if (flush_line && xo_flush_h(xop) < 0)
5999 return -1;
6000 goto bottom;
6001
6002 } else if (ftype == XO_ROLE_EBRACE) {
6003 xo_format_text(xop, xfip->xfi_start, xfip->xfi_len);

--- 12 unchanged lines hidden (view full) ---

6016 if (flags & XFF_WS) {
6017 xo_format_content(xop, "padding", NULL, " ", 1,
6018 NULL, 0, flags);
6019 flags &= ~XFF_WS; /* Block later handling of this */
6020 }
6021 }
6022
6023 if (ftype == 'V')
5776 xo_format_value(xop, xfip->xfi_content, xfip->xfi_clen,
6024 xo_format_value(xop, content, clen,
5777 xfip->xfi_format, xfip->xfi_flen,
5778 xfip->xfi_encoding, xfip->xfi_elen, flags);
5779 else if (ftype == '[')
6025 xfip->xfi_format, xfip->xfi_flen,
6026 xfip->xfi_encoding, xfip->xfi_elen, flags);
6027 else if (ftype == '[')
5780 xo_anchor_start(xop, xfip);
6028 xo_anchor_start(xop, xfip, content, clen);
5781 else if (ftype == ']')
6029 else if (ftype == ']')
5782 xo_anchor_stop(xop, xfip);
6030 xo_anchor_stop(xop, xfip, content, clen);
5783 else if (ftype == 'C')
6031 else if (ftype == 'C')
5784 xo_format_colors(xop, xfip);
6032 xo_format_colors(xop, xfip, content, clen);
5785
5786 else if (ftype == 'G') {
5787 /*
5788 * A {G:domain} field; disect the domain name and translate
5789 * the remaining portion of the input string. If the user
5790 * didn't put the {G:} at the start of the format string, then
5791 * assumably they just want us to translate the rest of it.
5792 * Since gettext returns strings in a static buffer, we make
5793 * a copy in new_fmt.
5794 */
6033
6034 else if (ftype == 'G') {
6035 /*
6036 * A {G:domain} field; disect the domain name and translate
6037 * the remaining portion of the input string. If the user
6038 * didn't put the {G:} at the start of the format string, then
6039 * assumably they just want us to translate the rest of it.
6040 * Since gettext returns strings in a static buffer, we make
6041 * a copy in new_fmt.
6042 */
5795 xo_set_gettext_domain(xop, xfip);
6043 xo_set_gettext_domain(xop, xfip, content, clen);
5796
5797 if (!gettext_inuse) { /* Only translate once */
5798 gettext_inuse = 1;
5799 if (new_fmt) {
5800 xo_free(new_fmt);
5801 new_fmt = NULL;
5802 }
5803

--- 34 unchanged lines hidden (view full) ---

5838 xfip = new_fields;
5839 max_fields = new_max_fields;
5840 }
5841 }
5842 }
5843 }
5844 continue;
5845
6044
6045 if (!gettext_inuse) { /* Only translate once */
6046 gettext_inuse = 1;
6047 if (new_fmt) {
6048 xo_free(new_fmt);
6049 new_fmt = NULL;
6050 }
6051

--- 34 unchanged lines hidden (view full) ---

6086 xfip = new_fields;
6087 max_fields = new_max_fields;
6088 }
6089 }
6090 }
6091 }
6092 continue;
6093
5846 } else if (xfip->xfi_clen || xfip->xfi_format) {
6094 } else if (clen || xfip->xfi_format) {
5847
5848 const char *class_name = xo_class_name(ftype);
5849 if (class_name)
5850 xo_format_content(xop, class_name, xo_tag_name(ftype),
6095
6096 const char *class_name = xo_class_name(ftype);
6097 if (class_name)
6098 xo_format_content(xop, class_name, xo_tag_name(ftype),
5851 xfip->xfi_content, xfip->xfi_clen,
6099 content, clen,
5852 xfip->xfi_format, xfip->xfi_flen, flags);
5853 else if (ftype == 'T')
6100 xfip->xfi_format, xfip->xfi_flen, flags);
6101 else if (ftype == 'T')
5854 xo_format_title(xop, xfip);
6102 xo_format_title(xop, xfip, content, clen);
5855 else if (ftype == 'U')
6103 else if (ftype == 'U')
5856 xo_format_units(xop, xfip);
6104 xo_format_units(xop, xfip, content, clen);
5857 else
5858 xo_failure(xop, "unknown field type: '%c'", ftype);
5859 }
5860
5861 if (flags & XFF_COLON)
5862 xo_format_content(xop, "decoration", NULL, ":", 1, NULL, 0, 0);
5863
5864 if (flags & XFF_WS)

--- 14 unchanged lines hidden (view full) ---

5879 }
5880
5881 XOIF_CLEAR(xop, XOIF_REORDER);
5882
5883 /* If we don't have an anchor, write the text out */
5884 if (flush && !XOIF_ISSET(xop, XOIF_ANCHOR)) {
5885 if (xo_write(xop) < 0)
5886 rc = -1; /* Report failure */
6105 else
6106 xo_failure(xop, "unknown field type: '%c'", ftype);
6107 }
6108
6109 if (flags & XFF_COLON)
6110 xo_format_content(xop, "decoration", NULL, ":", 1, NULL, 0, 0);
6111
6112 if (flags & XFF_WS)

--- 14 unchanged lines hidden (view full) ---

6127 }
6128
6129 XOIF_CLEAR(xop, XOIF_REORDER);
6130
6131 /* If we don't have an anchor, write the text out */
6132 if (flush && !XOIF_ISSET(xop, XOIF_ANCHOR)) {
6133 if (xo_write(xop) < 0)
6134 rc = -1; /* Report failure */
5887 else if (xop->xo_flush && xop->xo_flush(xop->xo_opaque) < 0)
6135 else if (xo_flush_h(xop) < 0)
5888 rc = -1;
5889 }
5890
5891 if (new_fmt)
5892 xo_free(new_fmt);
5893
5894 /*
5895 * We've carried the gettext domainname inside our handle just for

--- 4 unchanged lines hidden (view full) ---

5900 xo_free(xop->xo_gt_domain);
5901 xop->xo_gt_domain = NULL;
5902 }
5903
5904 return (rc < 0) ? rc : (int) xop->xo_columns;
5905}
5906
5907/*
6136 rc = -1;
6137 }
6138
6139 if (new_fmt)
6140 xo_free(new_fmt);
6141
6142 /*
6143 * We've carried the gettext domainname inside our handle just for

--- 4 unchanged lines hidden (view full) ---

6148 xo_free(xop->xo_gt_domain);
6149 xop->xo_gt_domain = NULL;
6150 }
6151
6152 return (rc < 0) ? rc : (int) xop->xo_columns;
6153}
6154
6155/*
6156 * Parse and emit a set of fields
6157 */
6158static int
6159xo_do_emit (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt)
6160{
6161 xop->xo_columns = 0; /* Always reset it */
6162 xop->xo_errno = errno; /* Save for "%m" */
6163
6164 if (fmt == NULL)
6165 return 0;
6166
6167 unsigned max_fields;
6168 xo_field_info_t *fields = NULL;
6169
6170 /* Adjust XOEF_RETAIN based on global flags */
6171 if (XOF_ISSET(xop, XOF_RETAIN_ALL))
6172 flags |= XOEF_RETAIN;
6173 if (XOF_ISSET(xop, XOF_RETAIN_NONE))
6174 flags &= ~XOEF_RETAIN;
6175
6176 /*
6177 * Check for 'retain' flag, telling us to retain the field
6178 * information. If we've already saved it, then we can avoid
6179 * re-parsing the format string.
6180 */
6181 if (!(flags & XOEF_RETAIN)
6182 || xo_retain_find(fmt, &fields, &max_fields) != 0
6183 || fields == NULL) {
6184
6185 /* Nothing retained; parse the format string */
6186 max_fields = xo_count_fields(xop, fmt);
6187 fields = alloca(max_fields * sizeof(fields[0]));
6188 bzero(fields, max_fields * sizeof(fields[0]));
6189
6190 if (xo_parse_fields(xop, fields, max_fields, fmt))
6191 return -1; /* Warning already displayed */
6192
6193 if (flags & XOEF_RETAIN) {
6194 /* Retain the info */
6195 xo_retain_add(fmt, fields, max_fields);
6196 }
6197 }
6198
6199 return xo_do_emit_fields(xop, fields, max_fields, fmt);
6200}
6201
6202/*
5908 * Rebuild a format string in a gettext-friendly format. This function
5909 * is exposed to tools can perform this function. See xo(1).
5910 */
5911char *
5912xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers,
5913 xo_simplify_field_func_t field_cb)
5914{
5915 xop = xo_default(xop);

--- 23 unchanged lines hidden (view full) ---

5939
5940int
5941xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap)
5942{
5943 int rc;
5944
5945 xop = xo_default(xop);
5946 va_copy(xop->xo_vap, vap);
6203 * Rebuild a format string in a gettext-friendly format. This function
6204 * is exposed to tools can perform this function. See xo(1).
6205 */
6206char *
6207xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers,
6208 xo_simplify_field_func_t field_cb)
6209{
6210 xop = xo_default(xop);

--- 23 unchanged lines hidden (view full) ---

6234
6235int
6236xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap)
6237{
6238 int rc;
6239
6240 xop = xo_default(xop);
6241 va_copy(xop->xo_vap, vap);
5947 rc = xo_do_emit(xop, fmt);
6242 rc = xo_do_emit(xop, 0, fmt);
5948 va_end(xop->xo_vap);
5949 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
5950
5951 return rc;
5952}
5953
5954int
5955xo_emit_h (xo_handle_t *xop, const char *fmt, ...)
5956{
5957 int rc;
5958
5959 xop = xo_default(xop);
5960 va_start(xop->xo_vap, fmt);
6243 va_end(xop->xo_vap);
6244 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
6245
6246 return rc;
6247}
6248
6249int
6250xo_emit_h (xo_handle_t *xop, const char *fmt, ...)
6251{
6252 int rc;
6253
6254 xop = xo_default(xop);
6255 va_start(xop->xo_vap, fmt);
5961 rc = xo_do_emit(xop, fmt);
6256 rc = xo_do_emit(xop, 0, fmt);
5962 va_end(xop->xo_vap);
5963 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
5964
5965 return rc;
5966}
5967
5968int
5969xo_emit (const char *fmt, ...)
5970{
5971 xo_handle_t *xop = xo_default(NULL);
5972 int rc;
5973
5974 va_start(xop->xo_vap, fmt);
6257 va_end(xop->xo_vap);
6258 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
6259
6260 return rc;
6261}
6262
6263int
6264xo_emit (const char *fmt, ...)
6265{
6266 xo_handle_t *xop = xo_default(NULL);
6267 int rc;
6268
6269 va_start(xop->xo_vap, fmt);
5975 rc = xo_do_emit(xop, fmt);
6270 rc = xo_do_emit(xop, 0, fmt);
5976 va_end(xop->xo_vap);
5977 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
5978
5979 return rc;
5980}
5981
5982int
6271 va_end(xop->xo_vap);
6272 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
6273
6274 return rc;
6275}
6276
6277int
6278xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
6279 const char *fmt, va_list vap)
6280{
6281 int rc;
6282
6283 xop = xo_default(xop);
6284 va_copy(xop->xo_vap, vap);
6285 rc = xo_do_emit(xop, flags, fmt);
6286 va_end(xop->xo_vap);
6287 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
6288
6289 return rc;
6290}
6291
6292int
6293xo_emit_hf (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt, ...)
6294{
6295 int rc;
6296
6297 xop = xo_default(xop);
6298 va_start(xop->xo_vap, fmt);
6299 rc = xo_do_emit(xop, flags, fmt);
6300 va_end(xop->xo_vap);
6301 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
6302
6303 return rc;
6304}
6305
6306int
6307xo_emit_f (xo_emit_flags_t flags, const char *fmt, ...)
6308{
6309 xo_handle_t *xop = xo_default(NULL);
6310 int rc;
6311
6312 va_start(xop->xo_vap, fmt);
6313 rc = xo_do_emit(xop, flags, fmt);
6314 va_end(xop->xo_vap);
6315 bzero(&xop->xo_vap, sizeof(xop->xo_vap));
6316
6317 return rc;
6318}
6319
6320/*
6321 * Emit a single field by providing the info information typically provided
6322 * inside the field description (role, modifiers, and formats). This is
6323 * a convenience function to avoid callers using snprintf to build field
6324 * descriptions.
6325 */
6326int
6327xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
6328 const char *fmt, const char *efmt,
6329 va_list vap)
6330{
6331 int rc;
6332
6333 xop = xo_default(xop);
6334
6335 if (rolmod == NULL)
6336 rolmod = "V";
6337
6338 xo_field_info_t xfi;
6339
6340 bzero(&xfi, sizeof(xfi));
6341
6342 const char *cp;
6343 cp = xo_parse_roles(xop, rolmod, rolmod, &xfi);
6344 if (cp == NULL)
6345 return -1;
6346
6347 xfi.xfi_start = fmt;
6348 xfi.xfi_content = contents;
6349 xfi.xfi_format = fmt;
6350 xfi.xfi_encoding = efmt;
6351 xfi.xfi_clen = contents ? strlen(contents) : 0;
6352 xfi.xfi_flen = fmt ? strlen(fmt) : 0;
6353 xfi.xfi_elen = efmt ? strlen(efmt) : 0;
6354
6355 /* If we have content, then we have a default format */
6356 if (contents && fmt == NULL
6357 && xo_role_wants_default_format(xfi.xfi_ftype)) {
6358 xfi.xfi_format = xo_default_format;
6359 xfi.xfi_flen = 2;
6360 }
6361
6362
6363
6364 va_copy(xop->xo_vap, vap);
6365
6366 rc = xo_do_emit_fields(xop, &xfi, 1, fmt ?: contents ?: "field");
6367
6368 va_end(xop->xo_vap);
6369
6370 return rc;
6371}
6372
6373int
6374xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
6375 const char *fmt, const char *efmt, ...)
6376{
6377 int rc;
6378 va_list vap;
6379
6380 va_start(vap, efmt);
6381 rc = xo_emit_field_hv(xop, rolmod, contents, fmt, efmt, vap);
6382 va_end(vap);
6383
6384 return rc;
6385}
6386
6387int
6388xo_emit_field (const char *rolmod, const char *contents,
6389 const char *fmt, const char *efmt, ...)
6390{
6391 int rc;
6392 va_list vap;
6393
6394 va_start(vap, efmt);
6395 rc = xo_emit_field_hv(NULL, rolmod, contents, fmt, efmt, vap);
6396 va_end(vap);
6397
6398 return rc;
6399}
6400
6401int
5983xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap)
5984{
5985 const int extra = 5; /* space, equals, quote, quote, and nul */
5986 xop = xo_default(xop);
5987
5988 int rc = 0;
5989 int nlen = strlen(name);
5990 xo_buffer_t *xbp = &xop->xo_attrs;

--- 396 unchanged lines hidden (view full) ---

6387
6388static int
6389xo_open_list_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
6390{
6391 return xo_transition(xop, flags, name, XSS_OPEN_LIST);
6392}
6393
6394int
6402xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap)
6403{
6404 const int extra = 5; /* space, equals, quote, quote, and nul */
6405 xop = xo_default(xop);
6406
6407 int rc = 0;
6408 int nlen = strlen(name);
6409 xo_buffer_t *xbp = &xop->xo_attrs;

--- 396 unchanged lines hidden (view full) ---

6806
6807static int
6808xo_open_list_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
6809{
6810 return xo_transition(xop, flags, name, XSS_OPEN_LIST);
6811}
6812
6813int
6395xo_open_list_h (xo_handle_t *xop, const char *name UNUSED)
6814xo_open_list_h (xo_handle_t *xop, const char *name)
6396{
6397 return xo_open_list_hf(xop, 0, name);
6398}
6399
6400int
6401xo_open_list (const char *name)
6402{
6403 return xo_open_list_hf(NULL, 0, name);
6404}
6405
6406int
6815{
6816 return xo_open_list_hf(xop, 0, name);
6817}
6818
6819int
6820xo_open_list (const char *name)
6821{
6822 return xo_open_list_hf(NULL, 0, name);
6823}
6824
6825int
6407xo_open_list_hd (xo_handle_t *xop, const char *name UNUSED)
6826xo_open_list_hd (xo_handle_t *xop, const char *name)
6408{
6409 return xo_open_list_hf(xop, XOF_DTRT, name);
6410}
6411
6412int
6413xo_open_list_d (const char *name)
6414{
6415 return xo_open_list_hf(NULL, XOF_DTRT, name);

--- 692 unchanged lines hidden (view full) ---

7108 */
7109 break;
7110
7111 default:
7112 xo_failure(xop, "unknown transition: (%u -> %u)",
7113 xsp->xs_state, new_state);
7114 }
7115
6827{
6828 return xo_open_list_hf(xop, XOF_DTRT, name);
6829}
6830
6831int
6832xo_open_list_d (const char *name)
6833{
6834 return xo_open_list_hf(NULL, XOF_DTRT, name);

--- 692 unchanged lines hidden (view full) ---

7527 */
7528 break;
7529
7530 default:
7531 xo_failure(xop, "unknown transition: (%u -> %u)",
7532 xsp->xs_state, new_state);
7533 }
7534
7535 /* Handle the flush flag */
7536 if (rc >= 0 && XOF_ISSET(xop, XOF_FLUSH))
7537 if (xo_flush_h(xop))
7538 rc = -1;
7539
7116 return rc;
7117
7118 marker_prevents_close:
7119 xo_failure(xop, "marker '%s' prevents transition from %s to %s",
7120 xop->xo_stack[xop->xo_depth].xs_name,
7121 xo_state_name(old_state), xo_state_name(new_state));
7122 return -1;
7123}

--- 50 unchanged lines hidden (view full) ---

7174{
7175 xo_realloc = realloc_func;
7176 xo_free = free_func;
7177}
7178
7179int
7180xo_flush_h (xo_handle_t *xop)
7181{
7540 return rc;
7541
7542 marker_prevents_close:
7543 xo_failure(xop, "marker '%s' prevents transition from %s to %s",
7544 xop->xo_stack[xop->xo_depth].xs_name,
7545 xo_state_name(old_state), xo_state_name(new_state));
7546 return -1;
7547}

--- 50 unchanged lines hidden (view full) ---

7598{
7599 xo_realloc = realloc_func;
7600 xo_free = free_func;
7601}
7602
7603int
7604xo_flush_h (xo_handle_t *xop)
7605{
7182 static char div_close[] = "</div>";
7183 int rc;
7184
7185 xop = xo_default(xop);
7186
7187 switch (xo_style(xop)) {
7606 int rc;
7607
7608 xop = xo_default(xop);
7609
7610 switch (xo_style(xop)) {
7188 case XO_STYLE_HTML:
7189 if (XOIF_ISSET(xop, XOIF_DIV_OPEN)) {
7190 XOIF_CLEAR(xop, XOIF_DIV_OPEN);
7191 xo_data_append(xop, div_close, sizeof(div_close) - 1);
7192
7193 if (XOF_ISSET(xop, XOF_PRETTY))
7194 xo_data_append(xop, "\n", 1);
7195 }
7196 break;
7197
7198 case XO_STYLE_ENCODER:
7199 xo_encoder_handle(xop, XO_OP_FLUSH, NULL, NULL);
7200 }
7201
7202 rc = xo_write(xop);
7203 if (rc >= 0 && xop->xo_flush)
7204 if (xop->xo_flush(xop->xo_opaque) < 0)
7205 return -1;

--- 224 unchanged lines hidden (view full) ---

7430 */
7431void
7432xo_set_program (const char *name)
7433{
7434 xo_program = name;
7435}
7436
7437void
7611 case XO_STYLE_ENCODER:
7612 xo_encoder_handle(xop, XO_OP_FLUSH, NULL, NULL);
7613 }
7614
7615 rc = xo_write(xop);
7616 if (rc >= 0 && xop->xo_flush)
7617 if (xop->xo_flush(xop->xo_opaque) < 0)
7618 return -1;

--- 224 unchanged lines hidden (view full) ---

7843 */
7844void
7845xo_set_program (const char *name)
7846{
7847 xo_program = name;
7848}
7849
7850void
7438xo_set_version_h (xo_handle_t *xop, const char *version UNUSED)
7851xo_set_version_h (xo_handle_t *xop, const char *version)
7439{
7440 xop = xo_default(xop);
7441
7442 if (version == NULL || strchr(version, '"') != NULL)
7443 return;
7444
7445 if (!xo_style_is_encoding(xop))
7446 return;

--- 213 unchanged lines hidden ---
7852{
7853 xop = xo_default(xop);
7854
7855 if (version == NULL || strchr(version, '"') != NULL)
7856 return;
7857
7858 if (!xo_style_is_encoding(xop))
7859 return;

--- 213 unchanged lines hidden ---