You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5243 lines
130 KiB

diff -up util-linux-2.23.2/configure.ac.kzak util-linux-2.23.2/configure.ac
--- util-linux-2.23.2/configure.ac.kzak 2013-07-30 10:39:26.188738061 +0200
+++ util-linux-2.23.2/configure.ac 2014-09-25 14:41:48.980843829 +0200
@@ -46,6 +46,13 @@ LIBMOUNT_LT_MINOR=1
LIBMOUNT_LT_MICRO=0
LIBMOUNT_VERSION_INFO=`expr $LIBMOUNT_LT_MAJOR + $LIBMOUNT_LT_MINOR`:$LIBMOUNT_LT_MICRO:$LIBMOUNT_LT_MINOR
+dnl libsmartcols version
+LIBSMARTCOLS_VERSION="$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR.$PACKAGE_VERSION_RELEASE"
+LIBSMARTCOLS_LT_MAJOR=1
+LIBSMARTCOLS_LT_MINOR=1
+LIBSMARTCOLS_LT_MICRO=0
+LIBSMARTCOLS_VERSION_INFO=`expr $LIBSMARTCOLS_LT_MAJOR + $LIBSMARTCOLS_LT_MINOR`:$LIBSMARTCOLS_LT_MICRO:$LIBSMARTCOLS_LT_MINOR
+
# Check whether exec_prefix=/usr:
case $exec_prefix:$prefix in
NONE:NONE | NONE:/usr | /usr:*)
@@ -765,6 +772,18 @@ AC_DEFINE_UNQUOTED(LIBMOUNT_VERSION, "$L
dnl
+dnl libsmartcols
+dnl
+UL_BUILD_INIT([libsmartcols], [yes])
+AM_CONDITIONAL([BUILD_LIBSMARTCOLS], [test "x$build_libsmartcols" = xyes])
+AM_CONDITIONAL([BUILD_LIBSMARTCOLS_TESTS], [test "x$build_libsmartcols" = xyes -a "x$enable_static" = xyes])
+
+AC_SUBST([LIBSMARTCOLS_VERSION])
+AC_SUBST([LIBSMARTCOLS_VERSION_INFO])
+AC_DEFINE_UNQUOTED([LIBSMARTCOLS_VERSION], ["$LIBSMARTCOLS_VERSION"], [libsmartcols version string])
+
+
+dnl
dnl libfdisk is enabled all time if possible
dnl
UL_BUILD_INIT([libfdisk], [check])
@@ -1500,6 +1519,9 @@ libblkid/src/blkid.h
libmount/docs/Makefile
libmount/docs/version.xml
libmount/src/libmount.h
+libsmartcols/docs/Makefile
+libsmartcols/docs/version.xml
+libsmartcols/src/libsmartcols.h
po/Makefile.in
])
diff -up util-linux-2.23.2/include/carefulputc.h.kzak util-linux-2.23.2/include/carefulputc.h
--- util-linux-2.23.2/include/carefulputc.h.kzak 2012-11-29 16:18:33.956147961 +0100
+++ util-linux-2.23.2/include/carefulputc.h 2014-09-25 14:41:48.980843829 +0200
@@ -26,4 +26,39 @@ static inline int carefulputc(int c, FIL
return (ret < 0) ? EOF : 0;
}
+static inline void fputs_quoted(const char *data, FILE *out)
+{
+ const char *p;
+
+ fputc('"', out);
+ for (p = data; p && *p; p++) {
+ if ((unsigned char) *p == 0x22 || /* " */
+ (unsigned char) *p == 0x5c || /* \ */
+ !isprint((unsigned char) *p) ||
+ iscntrl((unsigned char) *p)) {
+
+ fprintf(out, "\\x%02x", (unsigned char) *p);
+ } else
+ fputc(*p, out);
+ }
+ fputc('"', out);
+}
+
+static inline void fputs_nonblank(const char *data, FILE *out)
+{
+ const char *p;
+
+ for (p = data; p && *p; p++) {
+ if (isblank((unsigned char) *p) ||
+ (unsigned char) *p == 0x5c || /* \ */
+ !isprint((unsigned char) *p) ||
+ iscntrl((unsigned char) *p)) {
+
+ fprintf(out, "\\x%02x", (unsigned char) *p);
+
+ } else
+ fputc(*p, out);
+ }
+}
+
#endif /* _CAREFUULPUTC_H */
diff -up util-linux-2.23.2/include/debug.h.kzak util-linux-2.23.2/include/debug.h
--- util-linux-2.23.2/include/debug.h.kzak 2014-09-25 14:41:48.981843839 +0200
+++ util-linux-2.23.2/include/debug.h 2014-09-25 14:41:48.981843839 +0200
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_DEBUG_H
+#define UTIL_LINUX_DEBUG_H
+
+#include <stdarg.h>
+#include <string.h>
+
+struct dbg_mask { char *mname; int val; };
+#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0 }}
+
+#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask
+#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
+#define UL_DEBUG_DEFINE_MASKANEMS(m) static const struct dbg_mask m ## _masknames[]
+
+/* p - flag prefix, m - flag postfix */
+#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m
+
+/* l - library name, p - flag prefix, m - flag postfix, x - function */
+#define __UL_DBG(l, p, m, x) \
+ do { \
+ if ((p ## m) & l ## _debug_mask) { \
+ fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
+ x; \
+ } \
+ } while (0)
+
+#define __UL_DBG_CALL(l, p, m, x) \
+ do { \
+ if ((p ## m) & l ## _debug_mask) { \
+ x; \
+ } \
+ } while (0)
+
+#define __UL_DBG_FLUSH(l, p) \
+ do { \
+ if (l ## _debug_mask && \
+ l ## _debug_mask != p ## INIT) { \
+ fflush(stderr); \
+ } \
+ } while (0)
+
+
+#define __UL_INIT_DEBUG(lib, pref, mask, env) \
+ do { \
+ if (lib ## _debug_mask & pref ## INIT) \
+ ; \
+ else if (!mask) { \
+ char *str = getenv(# env); \
+ if (str) \
+ lib ## _debug_mask = parse_envmask(lib ## _masknames, str); \
+ } else \
+ lib ## _debug_mask = mask; \
+ lib ## _debug_mask |= pref ## INIT; \
+ if (lib ## _debug_mask != pref ## INIT) { \
+ __UL_DBG(lib, pref, INIT, ul_debug("library debug mask: 0x%04x", \
+ lib ## _debug_mask)); \
+ } \
+ } while (0)
+
+
+static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
+ul_debug(const char *mesg, ...)
+{
+ va_list ap;
+ va_start(ap, mesg);
+ vfprintf(stderr, mesg, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
+ul_debugobj(void *handler, const char *mesg, ...)
+{
+ va_list ap;
+
+ if (handler)
+ fprintf(stderr, "[%p]: ", handler);
+ va_start(ap, mesg);
+ vfprintf(stderr, mesg, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+static inline int parse_envmask(const struct dbg_mask const flagnames[],
+ const char *mask)
+{
+ int res;
+ char *ptr;
+
+ /* let's check for a numeric mask first */
+ res = strtoul(mask, &ptr, 0);
+
+ /* perhaps it's a comma-separated string? */
+ if (*ptr != '\0' && flagnames) {
+ char *msbuf, *ms, *name;
+ res = 0;
+
+ ms = msbuf = strdup(mask);
+ if (!ms)
+ return res;
+
+ while ((name = strtok_r(ms, ",", &ptr))) {
+ size_t i = 0;
+ ms = ptr;
+
+ while (flagnames[i].mname) {
+ if (!strcmp(name, flagnames[i].mname)) {
+ res |= flagnames[i].val;
+ break;
+ }
+ ++i;
+ }
+ /* nothing else we can do by OR-ing the mask */
+ if (res == 0xffff)
+ break;
+ }
+ free(msbuf);
+ }
+ return res;
+}
+#endif /* UTIL_LINUX_DEBUG_H */
diff -up util-linux-2.23.2/include/list.h.kzak util-linux-2.23.2/include/list.h
--- util-linux-2.23.2/include/list.h.kzak 2013-06-13 09:46:10.396650417 +0200
+++ util-linux-2.23.2/include/list.h 2014-09-25 14:41:48.981843839 +0200
@@ -212,14 +212,16 @@ _INLINE_ void list_splice(struct list_he
* sentinel head node, "prev" links not maintained.
*/
_INLINE_ struct list_head *merge(int (*cmp)(struct list_head *a,
- struct list_head *b),
+ struct list_head *b,
+ void *data),
+ void *data,
struct list_head *a, struct list_head *b)
{
struct list_head head, *tail = &head;
while (a && b) {
/* if equal, take 'a' -- important for sort stability */
- if ((*cmp)(a, b) <= 0) {
+ if ((*cmp)(a, b, data) <= 0) {
tail->next = a;
a = a->next;
} else {
@@ -240,7 +242,9 @@ _INLINE_ struct list_head *merge(int (*c
* throughout.
*/
_INLINE_ void merge_and_restore_back_links(int (*cmp)(struct list_head *a,
- struct list_head *b),
+ struct list_head *b,
+ void *data),
+ void *data,
struct list_head *head,
struct list_head *a, struct list_head *b)
{
@@ -248,7 +252,7 @@ _INLINE_ void merge_and_restore_back_lin
while (a && b) {
/* if equal, take 'a' -- important for sort stability */
- if ((*cmp)(a, b) <= 0) {
+ if ((*cmp)(a, b, data) <= 0) {
tail->next = a;
a->prev = tail;
a = a->next;
@@ -268,7 +272,7 @@ _INLINE_ void merge_and_restore_back_lin
* element comparison is needed, so the client's cmp()
* routine can invoke cond_resched() periodically.
*/
- (*cmp)(tail->next, tail->next);
+ (*cmp)(tail->next, tail->next, data);
tail->next->prev = tail;
tail = tail->next;
@@ -294,7 +298,9 @@ _INLINE_ void merge_and_restore_back_lin
*/
_INLINE_ void list_sort(struct list_head *head,
int (*cmp)(struct list_head *a,
- struct list_head *b))
+ struct list_head *b,
+ void *data),
+ void *data)
{
struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
-- last slot is a sentinel */
@@ -316,7 +322,7 @@ _INLINE_ void list_sort(struct list_head
cur->next = NULL;
for (lev = 0; part[lev]; lev++) {
- cur = merge(cmp, part[lev], cur);
+ cur = merge(cmp, data, part[lev], cur);
part[lev] = NULL;
}
if (lev > max_lev) {
@@ -330,11 +336,12 @@ _INLINE_ void list_sort(struct list_head
for (lev = 0; lev < max_lev; lev++)
if (part[lev])
- list = merge(cmp, part[lev], list);
+ list = merge(cmp, data, part[lev], list);
- merge_and_restore_back_links(cmp, head, part[max_lev], list);
+ merge_and_restore_back_links(cmp, data, head, part[max_lev], list);
}
+
#undef _INLINE_
#endif /* UTIL_LINUX_LIST_H */
diff -up util-linux-2.23.2/include/mbsalign.h.kzak util-linux-2.23.2/include/mbsalign.h
--- util-linux-2.23.2/include/mbsalign.h.kzak 2013-06-13 09:46:10.397650425 +0200
+++ util-linux-2.23.2/include/mbsalign.h 2014-09-25 14:41:48.981843839 +0200
@@ -1,5 +1,6 @@
/* Align/Truncate a string in a given screen width
Copyright (C) 2009-2010 Free Software Foundation, Inc.
+ Copyright (C) 2010-2013 Karel Zak <kzak@redhat.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -13,8 +14,9 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <stddef.h>
+#ifndef UTIL_LINUX_MBSALIGN_H
+# define UTIL_LINUX_MBSALIGN_H
+# include <stddef.h>
typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t;
@@ -43,3 +45,12 @@ extern size_t mbs_truncate(char *str, si
extern size_t mbsalign (const char *src, char *dest,
size_t dest_size, size_t *width,
mbs_align_t align, int flags);
+
+extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz);
+extern size_t mbs_safe_width(const char *s);
+
+extern char *mbs_safe_encode(const char *s, size_t *width);
+extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf);
+extern size_t mbs_safe_encode_size(size_t bytes);
+
+#endif /* UTIL_LINUX_MBSALIGN_H */
diff -up util-linux-2.23.2/lib/mbsalign.c.kzak util-linux-2.23.2/lib/mbsalign.c
--- util-linux-2.23.2/lib/mbsalign.c.kzak 2013-07-30 10:39:26.203738210 +0200
+++ util-linux-2.23.2/lib/mbsalign.c 2014-09-25 14:41:48.982843848 +0200
@@ -23,17 +23,193 @@
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
+#include <ctype.h>
#include "c.h"
#include "mbsalign.h"
#include "widechar.h"
-
#ifdef HAVE_WIDECHAR
/* Replace non printable chars.
Note \t and \n etc. are non printable.
Return 1 if replacement made, 0 otherwise. */
+/*
+ * Counts number of cells in multibyte string. For all control and
+ * non-printable chars is the result width enlarged to store \x?? hex
+ * sequence. See mbs_safe_encode().
+ *
+ * Returns: number of cells, @sz returns number of bytes.
+ */
+size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz)
+{
+ mbstate_t st;
+ const char *p = buf, *last = buf;
+ size_t width = 0, bytes = 0;
+
+ memset(&st, 0, sizeof(st));
+
+ if (p && *p && bufsz)
+ last = p + (bufsz - 1);
+
+ while (p && *p && p <= last) {
+ if (iscntrl((unsigned char) *p)) {
+ width += 4, bytes += 4; /* *p encoded to \x?? */
+ p++;
+ }
+#ifdef HAVE_WIDECHAR
+ else {
+ wchar_t wc;
+ size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+
+ if (len == 0)
+ break;
+
+ if (len == (size_t) -1 || len == (size_t) -2) {
+ len = 1;
+ if (isprint((unsigned char) *p))
+ width += 1, bytes += 1;
+ else
+ width += 4, bytes += 4;
+
+ } else if (!iswprint(wc)) {
+ width += len * 4; /* hex encode whole sequence */
+ bytes += len * 4;
+ } else {
+ width += wcwidth(wc); /* number of cells */
+ bytes += len; /* number of bytes */
+ }
+ p += len;
+ }
+#else
+ else if (!isprint((unsigned char) *p)) {
+ width += 4, bytes += 4; /* *p encoded to \x?? */
+ p++;
+ } else {
+ width++, bytes++;
+ p++;
+ }
+#endif
+ }
+
+ if (sz)
+ *sz = bytes;
+ return width;
+}
+
+size_t mbs_safe_width(const char *s)
+{
+ if (!s || !*s)
+ return 0;
+ return mbs_safe_nwidth(s, strlen(s), NULL);
+}
+
+/*
+ * Copy @s to @buf and replace control and non-printable chars with
+ * \x?? hex sequence. The @width returns number of cells.
+ *
+ * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s)))
+ * bytes.
+ */
+char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf)
+{
+ mbstate_t st;
+ const char *p = s;
+ char *r;
+ size_t sz = s ? strlen(s) : 0;
+
+ if (!sz || !buf)
+ return NULL;
+
+ memset(&st, 0, sizeof(st));
+
+ r = buf;
+ *width = 0;
+
+ while (p && *p) {
+ if (iscntrl((unsigned char) *p)) {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ r += 4;
+ *width += 4;
+ p++;
+ }
+#ifdef HAVE_WIDECHAR
+ else {
+ wchar_t wc;
+ size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+
+ if (len == 0)
+ break; /* end of string */
+
+ if (len == (size_t) -1 || len == (size_t) -2) {
+ len = 1;
+ /*
+ * Not valid multibyte sequence -- maybe it's
+ * printable char according to the current locales.
+ */
+ if (!isprint((unsigned char) *p)) {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ r += 4;
+ *width += 4;
+ } else {
+ width++;
+ *r++ = *p;
+ }
+ } else if (!iswprint(wc)) {
+ size_t i;
+ for (i = 0; i < len; i++) {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ r += 4;
+ *width += 4;
+ }
+ } else {
+ memcpy(r, p, len);
+ r += len;
+ *width += wcwidth(wc);
+ }
+ p += len;
+ }
+#else
+ else if (!isprint((unsigned char) *p)) {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ p++;
+ r += 4;
+ *width += 4;
+ } else {
+ *r++ = *p++;
+ *width++;
+ }
+#endif
+ }
+
+ *r = '\0';
+
+ return buf;
+}
+
+size_t mbs_safe_encode_size(size_t bytes)
+{
+ return (bytes * 4) + 1;
+}
+
+/*
+ * Returns allocated string where all control and non-printable chars are
+ * replaced with \x?? hex sequence.
+ */
+char *mbs_safe_encode(const char *s, size_t *width)
+{
+ size_t sz = s ? strlen(s) : 0;
+ char *buf;
+
+ if (!sz)
+ return NULL;
+ buf = malloc(mbs_safe_encode_size(sz));
+ if (!buf)
+ return NULL;
+
+ return mbs_safe_encode_to_buffer(s, width, buf);
+}
+
static bool
wc_ensure_printable (wchar_t *wchars)
{
@@ -254,8 +430,8 @@ mbsalign_unibyte:
if (dest_size != 0)
{
char *dest_end = dest + dest_size - 1;
- size_t start_spaces = n_spaces / 2 + n_spaces % 2;
- size_t end_spaces = n_spaces / 2;
+ size_t start_spaces;
+ size_t end_spaces;
switch (align)
{
diff -up util-linux-2.23.2/libsmartcols/COPYING.kzak util-linux-2.23.2/libsmartcols/COPYING
--- util-linux-2.23.2/libsmartcols/COPYING.kzak 2014-09-25 14:41:48.983843858 +0200
+++ util-linux-2.23.2/libsmartcols/COPYING 2014-09-25 14:41:48.983843858 +0200
@@ -0,0 +1,8 @@
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later
+version.
+
+The complete text of the license is available in the
+../Documentation/licenses/COPYING.LGPLv2.1 file.
diff -up util-linux-2.23.2/libsmartcols/docs/.gitignore.kzak util-linux-2.23.2/libsmartcols/docs/.gitignore
--- util-linux-2.23.2/libsmartcols/docs/.gitignore.kzak 2014-09-25 14:41:48.983843858 +0200
+++ util-linux-2.23.2/libsmartcols/docs/.gitignore 2014-09-25 14:41:48.983843858 +0200
@@ -0,0 +1,18 @@
+*-decl-list.txt
+*-decl.txt
+*-overrides.txt
+*-undeclared.txt
+*-undocumented.txt
+*-unused.txt
+*.args
+*.bak
+*.hierarchy
+*.interfaces
+*.prerequisites
+*.signals
+*.stamp
+*.types
+html/*
+tmpl/*
+version.xml
+xml/*
diff -up util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml.kzak util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml
--- util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml.kzak 2014-09-25 14:41:48.984843867 +0200
+++ util-linux-2.23.2/libsmartcols/docs/libsmartcols-docs.xml 2014-09-25 14:41:48.984843867 +0200
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+ <!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+ <bookinfo>
+ <title>libsmartcols Reference Manual</title>
+ <releaseinfo>for libsmartcols version &version;</releaseinfo>
+ <copyright>
+ <year>2014</year>
+ <holder>Karel Zak &lt;kzak@redhat.com&gt;</holder>
+ </copyright>
+ </bookinfo>
+
+ <part id="gtk">
+ <title>libsmartcols Overview</title>
+ <partintro>
+ <para>
+The libsmartcols library is used for smart adaptive formatting of tabular data.
+ </para>
+ <para>
+The library is part of the util-linux package since version 2.25 and is
+available from ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
+ </para>
+ </partintro>
+ </part>
+
+ <part>
+ <title>Data manipulation</title>
+ <xi:include href="xml/table.xml"/>
+ <xi:include href="xml/column.xml"/>
+ <xi:include href="xml/line.xml"/>
+ <xi:include href="xml/cell.xml"/>
+ <xi:include href="xml/symbols.xml"/>
+ </part>
+ <part>
+ <title>Printing</title>
+ <xi:include href="xml/table_print.xml"/>
+ </part>
+ <part>
+ <title>Misc</title>
+ <xi:include href="xml/iter.xml"/>
+ <xi:include href="xml/version-utils.xml"/>
+ <xi:include href="xml/init.xml"/>
+ </part>
+ <index id="api-index-full">
+ <title>API Index</title>
+ <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+ </index>
+</book>
diff -up util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt.kzak util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt
--- util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt.kzak 2014-09-25 14:41:48.984843867 +0200
+++ util-linux-2.23.2/libsmartcols/docs/libsmartcols-sections.txt 2014-09-25 14:41:48.984843867 +0200
@@ -0,0 +1,146 @@
+<SECTION>
+<FILE>cell</FILE>
+libscols_cell
+scols_cell_copy_content
+scols_cell_get_color
+scols_cell_get_data
+scols_cell_get_userdata
+scols_cell_refer_data
+scols_cell_set_color
+scols_cell_set_data
+scols_cell_set_userdata
+scols_cmpstr_cells
+scols_reset_cell
+</SECTION>
+
+<SECTION>
+<FILE>column</FILE>
+libscols_column
+scols_column_get_color
+scols_column_get_flags
+scols_column_get_header
+scols_column_get_whint
+scols_column_is_noextremes
+scols_column_is_right
+scols_column_is_strict_width
+scols_column_is_tree
+scols_column_is_trunc
+scols_column_set_cmpfunc
+scols_column_set_color
+scols_column_set_flags
+scols_column_set_whint
+scols_copy_column
+scols_new_column
+scols_ref_column
+scols_unref_column
+</SECTION>
+
+<SECTION>
+<FILE>iter</FILE>
+libscols_iter
+scols_free_iter
+scols_iter_get_direction
+scols_new_iter
+scols_reset_iter
+</SECTION>
+
+<SECTION>
+<FILE>line</FILE>
+libscols_line
+scols_copy_line
+scols_line_add_child
+scols_line_alloc_cells
+scols_line_free_cells
+scols_line_get_cell
+scols_line_get_color
+scols_line_get_column_cell
+scols_line_get_ncells
+scols_line_get_parent
+scols_line_get_userdata
+scols_line_has_children
+scols_line_next_child
+scols_line_refer_data
+scols_line_remove_child
+scols_line_set_color
+scols_line_set_data
+scols_line_set_userdata
+scols_new_line
+scols_ref_line
+scols_unref_line
+</SECTION>
+
+<SECTION>
+<FILE>symbols</FILE>
+libscols_symbols
+scols_copy_symbols
+scols_new_symbols
+scols_ref_symbols
+scols_symbols_set_branch
+scols_symbols_set_right
+scols_symbols_set_vertical
+scols_unref_symbols
+</SECTION>
+
+<SECTION>
+<FILE>table</FILE>
+libscols_table
+scols_copy_table
+scols_new_table
+scols_ref_table
+scols_table_add_column
+scols_table_add_line
+scols_table_colors_wanted
+scols_table_enable_ascii
+scols_table_enable_colors
+scols_table_enable_export
+scols_table_enable_maxout
+scols_table_enable_noheadings
+scols_table_enable_raw
+scols_table_get_column
+scols_table_get_column_separator
+scols_table_get_line
+scols_table_get_line_separator
+scols_table_get_ncols
+scols_table_get_nlines
+scols_table_get_stream
+scols_table_is_ascii
+scols_table_is_empty
+scols_table_is_export
+scols_table_is_maxout
+scols_table_is_noheadings
+scols_table_is_raw
+scols_table_is_tree
+scols_table_new_column
+scols_table_new_line
+scols_table_next_column
+scols_table_next_line
+scols_table_reduce_termwidth
+scols_table_remove_column
+scols_table_remove_columns
+scols_table_remove_line
+scols_table_remove_lines
+scols_table_set_column_separator
+scols_table_set_line_separator
+scols_table_set_stream
+scols_table_set_symbols
+scols_sort_table
+scols_unref_table
+</SECTION>
+
+<SECTION>
+<FILE>table_print</FILE>
+scols_print_table
+scols_print_table_to_string
+</SECTION>
+
+<SECTION>
+<FILE>version-utils</FILE>
+scols_get_library_version
+scols_parse_version_string
+LIBSMARTCOLS_VERSION
+</SECTION>
+
+<SECTION>
+<FILE>init</FILE>
+scols_init_debug
+</SECTION>
diff -up util-linux-2.23.2/libsmartcols/docs/Makefile.am.kzak util-linux-2.23.2/libsmartcols/docs/Makefile.am
--- util-linux-2.23.2/libsmartcols/docs/Makefile.am.kzak 2014-09-25 14:41:48.984843867 +0200
+++ util-linux-2.23.2/libsmartcols/docs/Makefile.am 2014-09-25 14:41:48.984843867 +0200
@@ -0,0 +1,93 @@
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.10 at least.
+AUTOMAKE_OPTIONS = 1.10
+
+# This is a blank Makefile.am for using gtk-doc.
+# Copy this to your project's API docs directory and modify the variables to
+# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
+# of using the various options.
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=libsmartcols
+
+# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
+#DOC_MODULE_VERSION=2
+
+# The top-level SGML file. You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
+
+# The directory containing the source code. Relative to $(srcdir).
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting the functions and macros.
+# e.g. DOC_SOURCE_DIR=../../../gtk
+DOC_SOURCE_DIR=../src
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
+MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space mnt
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkhtml
+MKHTML_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+HFILE_GLOB=$(top_builddir)/libsmartcols/src/libsmartcols.h
+CFILE_GLOB=$(top_srcdir)/libsmartcols/src/*.c
+
+# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
+# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
+EXTRA_HFILES=
+
+# Header files to ignore when scanning. Use base file name, no paths
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
+IGNORE_HFILES=smartcolsP.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files = $(builddir)/version.xml
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+GTKDOC_CFLAGS=
+GTKDOC_LIBS=
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/config/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST += version.xml.in
+
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+DISTCLEANFILES += version.xml
diff -up util-linux-2.23.2/libsmartcols/docs/version.xml.in.kzak util-linux-2.23.2/libsmartcols/docs/version.xml.in
--- util-linux-2.23.2/libsmartcols/docs/version.xml.in.kzak 2014-09-25 14:41:48.985843877 +0200
+++ util-linux-2.23.2/libsmartcols/docs/version.xml.in 2014-09-25 14:41:48.984843867 +0200
@@ -0,0 +1 @@
+@VERSION@
diff -up util-linux-2.23.2/libsmartcols/Makemodule.am.kzak util-linux-2.23.2/libsmartcols/Makemodule.am
--- util-linux-2.23.2/libsmartcols/Makemodule.am.kzak 2014-09-25 14:41:48.983843858 +0200
+++ util-linux-2.23.2/libsmartcols/Makemodule.am 2014-09-25 14:41:48.983843858 +0200
@@ -0,0 +1,14 @@
+if BUILD_LIBSMARTCOLS
+
+include libsmartcols/src/Makemodule.am
+
+if ENABLE_GTK_DOC
+# Docs uses separate Makefiles
+SUBDIRS += libsmartcols/docs
+endif
+
+# noinst for RHEL7: pkgconfig_DATA += libsmartcols/smartcols.pc
+PATHFILES += libsmartcols/smartcols.pc
+EXTRA_DIST += libsmartcols/COPYING
+
+endif # BUILD_LIBSMARTCOLS
diff -up util-linux-2.23.2/libsmartcols/smartcols.pc.in.kzak util-linux-2.23.2/libsmartcols/smartcols.pc.in
--- util-linux-2.23.2/libsmartcols/smartcols.pc.in.kzak 2014-09-25 14:41:48.985843877 +0200
+++ util-linux-2.23.2/libsmartcols/smartcols.pc.in 2014-09-25 14:41:48.985843877 +0200
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@usrlib_execdir@
+includedir=@includedir@
+
+Name: smartcols
+Description: table or tree library
+Version: @LIBSMARTCOLS_VERSION@
+Cflags: -I${includedir}/libsmartcols
+Libs: -L${libdir} -lsmartcols
diff -up util-linux-2.23.2/libsmartcols/src/cell.c.kzak util-linux-2.23.2/libsmartcols/src/cell.c
--- util-linux-2.23.2/libsmartcols/src/cell.c.kzak 2014-09-25 14:41:48.986843886 +0200
+++ util-linux-2.23.2/libsmartcols/src/cell.c 2014-09-25 14:41:48.986843886 +0200
@@ -0,0 +1,242 @@
+/*
+ * cell.c - functions for table handling at the cell level
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: cell
+ * @title: Cell
+ * @short_description: cell API
+ *
+ * An API to access and modify per-cell data and information. Note that cell is
+ * always part of the line. If you destroy (un-reference) a line than it
+ * destroys all line cells too.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "smartcolsP.h"
+
+/*
+ * The cell has no ref-counting, free() and new() functions. All is
+ * handled by libscols_line.
+ */
+
+/**
+ * scols_reset_cell:
+ * @ce: pointer to a struct libscols_cell instance
+ *
+ * Frees the cell's internal data and resets its status.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_reset_cell(struct libscols_cell *ce)
+{
+ assert(ce);
+
+ if (!ce)
+ return -EINVAL;
+
+ /*DBG(CELL, ul_debugobj(ce, "reset"));*/
+ free(ce->data);
+ free(ce->color);
+ memset(ce, 0, sizeof(*ce));
+ return 0;
+}
+
+/**
+ * scols_cell_set_data:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @str: data (used for scols_printtable())
+ *
+ * Stores a copy of the @str in @ce.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_set_data(struct libscols_cell *ce, const char *str)
+{
+ char *p = NULL;
+
+ assert(ce);
+
+ if (!ce)
+ return -EINVAL;
+ if (str) {
+ p = strdup(str);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(ce->data);
+ ce->data = p;
+ return 0;
+}
+
+/**
+ * scols_cell_refer_data:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @str: data (used for scols_printtable())
+ *
+ * Adds a reference to @str to @ce. The pointer is deallocated by
+ * scols_reset_cell() or scols_unref_line(). This function is mostly designed
+ * for situations when the data for the cell are already composed in allocated
+ * memory (e.g. asprintf()) to avoid extra unnecessary strdup().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_refer_data(struct libscols_cell *ce, char *str)
+{
+ assert(ce);
+
+ if (!ce)
+ return -EINVAL;
+ free(ce->data);
+ ce->data = str;
+ return 0;
+}
+
+/**
+ * scols_cell_get_data:
+ * @ce: a pointer to a struct libscols_cell instance
+ *
+ * Returns: data in @ce or NULL.
+ */
+const char *scols_cell_get_data(const struct libscols_cell *ce)
+{
+ assert(ce);
+ return ce ? ce->data : NULL;
+}
+
+/**
+ * scols_cell_set_userdata:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @data: private user data
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_set_userdata(struct libscols_cell *ce, void *data)
+{
+ assert(ce);
+
+ if (!ce)
+ return -EINVAL;
+ ce->userdata = data;
+ return 0;
+}
+
+/**
+ * scols_cell_get_userdata
+ * @ce: a pointer to a struct libscols_cell instance
+ *
+ * Returns: user data
+ */
+void *scols_cell_get_userdata(struct libscols_cell *ce)
+{
+ return ce ? ce->userdata : NULL;
+}
+
+/**
+ * scols_cmpstr_cells:
+ * @a: pointer to cell
+ * @b: pointer to cell
+ * @data: unused pointer to private data (defined by API)
+ *
+ * Compares cells data by strcmp(). The function is designed for
+ * scols_column_set_cmpfunc() and scols_sort_table().
+ *
+ * Returns: follows strcmp() return values.
+ */
+int scols_cmpstr_cells(struct libscols_cell *a,
+ struct libscols_cell *b,
+ __attribute__((__unused__)) void *data)
+{
+ const char *adata, *bdata;
+
+ if (a == b)
+ return 0;
+
+ adata = scols_cell_get_data(a);
+ bdata = scols_cell_get_data(b);
+
+ if (adata == NULL && bdata == NULL)
+ return 0;
+ if (adata == NULL)
+ return -1;
+ if (bdata == NULL)
+ return 1;
+ return strcmp(adata, bdata);
+}
+
+/**
+ * scols_cell_set_color:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @color: ESC sequence
+ *
+ * Set the color of @ce to @color.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_set_color(struct libscols_cell *ce, const char *color)
+{
+ char *p = NULL;
+
+ assert(ce);
+
+ if (!ce)
+ return -EINVAL;
+ if (color) {
+ p = strdup(color);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(ce->color);
+ ce->color = p;
+ return 0;
+}
+
+/**
+ * scols_cell_get_color:
+ * @ce: a pointer to a struct libscols_cell instance
+ *
+ * Returns: the current color of @ce.
+ */
+const char *scols_cell_get_color(const struct libscols_cell *ce)
+{
+ assert(ce);
+ return ce ? ce->color : NULL;
+}
+
+/**
+ * scols_cell_copy_content:
+ * @dest: a pointer to a struct libscols_cell instance
+ * @src: a pointer to an immutable struct libscols_cell instance
+ *
+ * Copy the contents of @src into @dest.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_copy_content(struct libscols_cell *dest,
+ const struct libscols_cell *src)
+{
+ int rc;
+
+ assert(dest);
+ assert(src);
+
+ rc = scols_cell_set_data(dest, scols_cell_get_data(src));
+ if (!rc)
+ rc = scols_cell_set_color(dest, scols_cell_get_color(src));
+ if (!rc)
+ dest->userdata = src->userdata;
+
+ DBG(CELL, ul_debugobj((void *) src, "copy into %p", dest));
+ return rc;
+}
diff -up util-linux-2.23.2/libsmartcols/src/column.c.kzak util-linux-2.23.2/libsmartcols/src/column.c
--- util-linux-2.23.2/libsmartcols/src/column.c.kzak 2014-09-25 14:41:48.986843886 +0200
+++ util-linux-2.23.2/libsmartcols/src/column.c 2014-09-25 14:41:48.986843886 +0200
@@ -0,0 +1,337 @@
+/*
+ * column.c - functions for table handling at the column level
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: column
+ * @title: Column
+ * @short_description: column API
+ *
+ * An API to access and modify per-column data and information.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "smartcolsP.h"
+
+/**
+ * scols_new_column:
+ *
+ * Allocates space for a new column.
+ *
+ * Returns: a pointer to a new struct libscols_cell instance, NULL in case of an ENOMEM error.
+ */
+struct libscols_column *scols_new_column(void)
+{
+ struct libscols_column *cl;
+
+ cl = calloc(1, sizeof(*cl));
+ if (!cl)
+ return NULL;
+ DBG(COL, ul_debugobj(cl, "alloc"));
+ cl->refcount = 1;
+ INIT_LIST_HEAD(&cl->cl_columns);
+ return cl;
+}
+
+/**
+ * scols_ref_column:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Increases the refcount of @cl.
+ */
+void scols_ref_column(struct libscols_column *cl)
+{
+ if (cl)
+ cl->refcount++;
+}
+
+/**
+ * scols_unref_column:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Decreases the refcount of @cl. When the count falls to zero, the instance
+ * is automatically deallocated.
+ */
+void scols_unref_column(struct libscols_column *cl)
+{
+ if (cl && --cl->refcount <= 0) {
+ DBG(COL, ul_debugobj(cl, "dealloc"));
+ list_del(&cl->cl_columns);
+ scols_reset_cell(&cl->header);
+ free(cl->color);
+ free(cl);
+ }
+}
+
+/**
+ * scols_copy_column:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Creates a new column and copies @cl's data over to it.
+ *
+ * Returns: a pointer to a new struct libscols_column instance.
+ */
+struct libscols_column *scols_copy_column(const struct libscols_column *cl)
+{
+ struct libscols_column *ret;
+
+ assert (cl);
+ if (!cl)
+ return NULL;
+ ret = scols_new_column();
+ if (!ret)
+ return NULL;
+
+ DBG(COL, ul_debugobj((void *) cl, "copy to %p", ret));
+
+ if (scols_column_set_color(ret, cl->color))
+ goto err;
+ if (scols_cell_copy_content(&ret->header, &cl->header))
+ goto err;
+
+ ret->width = cl->width;
+ ret->width_min = cl->width_min;
+ ret->width_max = cl->width_max;
+ ret->width_avg = cl->width_avg;
+ ret->width_hint = cl->width_hint;
+ ret->flags = cl->flags;
+ ret->is_extreme = cl->is_extreme;
+
+ return ret;
+err:
+ scols_unref_column(ret);
+ return NULL;
+}
+
+/**
+ * scols_column_set_whint:
+ * @cl: a pointer to a struct libscols_column instance
+ * @whint: a width hint
+ *
+ * Sets the width hint of column @cl to @whint.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_whint(struct libscols_column *cl, double whint)
+{
+ assert(cl);
+
+ if (!cl)
+ return -EINVAL;
+
+ cl->width_hint = whint;
+ return 0;
+}
+
+/**
+ * scols_column_get_whint:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: The width hint of column @cl, a negative value in case of an error.
+ */
+double scols_column_get_whint(struct libscols_column *cl)
+{
+ assert(cl);
+ return cl ? cl->width_hint : -EINVAL;
+}
+
+/**
+ * scols_column_set_flags:
+ * @cl: a pointer to a struct libscols_column instance
+ * @flags: a flag mask
+ *
+ * Sets the flags of @cl to @flags.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_flags(struct libscols_column *cl, int flags)
+{
+ assert(cl);
+
+ if (!cl)
+ return -EINVAL;
+
+ cl->flags = flags;
+ return 0;
+}
+
+/**
+ * scols_column_get_flags:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: The flag mask of @cl, a negative value in case of an error.
+ */
+int scols_column_get_flags(struct libscols_column *cl)
+{
+ assert(cl);
+ return cl ? cl->flags : -EINVAL;
+}
+
+/**
+ * scols_column_get_header:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: A pointer to a struct libscols_cell instance, representing the
+ * header info of column @cl or NULL in case of an error.
+ */
+struct libscols_cell *scols_column_get_header(struct libscols_column *cl)
+{
+ assert(cl);
+ return cl ? &cl->header : NULL;
+}
+
+/**
+ * scols_column_set_color:
+ * @cl: a pointer to a struct libscols_column instance
+ * @color: ESC sequence
+ *
+ * The default color for data cells and column header.
+ *
+ * If you want to set header specific color then use scols_column_get_header()
+ * and scols_cell_set_color().
+ *
+ * If you want to set data cell specific color the use scols_line_get_cell() +
+ * scols_cell_set_color().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_color(struct libscols_column *cl, const char *color)
+{
+ char *p = NULL;
+
+ assert(cl);
+ if (!cl)
+ return -EINVAL;
+ if (color) {
+ p = strdup(color);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(cl->color);
+ cl->color = p;
+ return 0;
+}
+
+/**
+ * scols_column_get_color:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: The current color setting of the column @cl.
+ */
+const char *scols_column_get_color(struct libscols_column *cl)
+{
+ assert(cl);
+ return cl ? cl->color : NULL;
+}
+
+
+/**
+ * scols_column_set_cmpfunc:
+ * @cl: column
+ * @cmp: pointer to compare function
+ * @data: private data for cmp function
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_cmpfunc(struct libscols_column *cl,
+ int (*cmp)(struct libscols_cell *,
+ struct libscols_cell *,
+ void *),
+ void *data)
+{
+ assert(cl);
+ if (!cl)
+ return -EINVAL;
+
+ cl->cmpfunc = cmp;
+ cl->cmpfunc_data = data;
+ return 0;
+}
+
+/**
+ * scols_column_is_trunc:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag trunc.
+ *
+ * Returns: trunc flag value, negative value in case of an error.
+ */
+int scols_column_is_trunc(struct libscols_column *cl)
+{
+ assert(cl);
+ if (!cl)
+ return -EINVAL;
+ return cl->flags & SCOLS_FL_TRUNC;
+}
+/**
+ * scols_column_is_tree:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag tree.
+ *
+ * Returns: tree flag value, negative value in case of an error.
+ */
+int scols_column_is_tree(struct libscols_column *cl)
+{
+ assert(cl);
+ if (!cl)
+ return -EINVAL;
+ return cl->flags & SCOLS_FL_TREE;
+}
+/**
+ * scols_column_is_right:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag right.
+ *
+ * Returns: right flag value, negative value in case of an error.
+ */
+int scols_column_is_right(struct libscols_column *cl)
+{
+ assert(cl);
+ if (!cl)
+ return -EINVAL;
+ return cl->flags & SCOLS_FL_RIGHT;
+}
+/**
+ * scols_column_is_strict_width:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag strict_width.
+ *
+ * Returns: strict_width flag value, negative value in case of an error.
+ */
+int scols_column_is_strict_width(struct libscols_column *cl)
+{
+ assert(cl);
+ if (!cl)
+ return -EINVAL;
+ return cl->flags & SCOLS_FL_STRICTWIDTH;
+}
+/**
+ * scols_column_is_noextremes:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag no_extremes.
+ *
+ * Returns: no_extremes flag value, negative value in case of an error.
+ */
+int scols_column_is_noextremes(struct libscols_column *cl)
+{
+ assert(cl);
+ if (!cl)
+ return -EINVAL;
+ return cl->flags & SCOLS_FL_NOEXTREMES;
+}
diff -up util-linux-2.23.2/libsmartcols/src/.gitignore.kzak util-linux-2.23.2/libsmartcols/src/.gitignore
--- util-linux-2.23.2/libsmartcols/src/.gitignore.kzak 2014-09-25 14:41:48.985843877 +0200
+++ util-linux-2.23.2/libsmartcols/src/.gitignore 2014-09-25 14:41:48.985843877 +0200
@@ -0,0 +1 @@
+libsmartcols.h
diff -up util-linux-2.23.2/libsmartcols/src/init.c.kzak util-linux-2.23.2/libsmartcols/src/init.c
--- util-linux-2.23.2/libsmartcols/src/init.c.kzak 2014-09-25 14:41:48.987843896 +0200
+++ util-linux-2.23.2/libsmartcols/src/init.c 2014-09-25 14:41:48.987843896 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: init
+ * @title: Library initialization
+ * @short_description: initialize debugging
+ *
+ * The library debug stuff.
+ */
+
+#include <stdarg.h>
+
+#include "smartcolsP.h"
+
+UL_DEBUG_DEFINE_MASK(libsmartcols);
+
+static const struct dbg_mask libsmartcols_masknames [] = {
+ { "all", SCOLS_DEBUG_ALL },
+ { "cell", SCOLS_DEBUG_CELL },
+ { "line", SCOLS_DEBUG_LINE },
+ { "tab", SCOLS_DEBUG_TAB },
+ { "col", SCOLS_DEBUG_COL },
+ { "buff", SCOLS_DEBUG_BUFF },
+ { NULL, 0 }
+};
+/**
+ * scols_init_debug:
+ * @mask: debug mask (0xffff to enable full debugging)
+ *
+ * If the @mask is not specified, then this function reads
+ * the LIBSMARTCOLS_DEBUG environment variable to get the mask.
+ *
+ * Already initialized debugging stuff cannot be changed. Calling
+ * this function twice has no effect.
+ */
+void scols_init_debug(int mask)
+{
+ __UL_INIT_DEBUG(libsmartcols, SCOLS_DEBUG_, mask, LIBSMARTCOLS_DEBUG);
+
+ if (libsmartcols_debug_mask != SCOLS_DEBUG_INIT) {
+ const char *ver = NULL;
+
+ scols_get_library_version(&ver);
+
+ DBG(INIT, ul_debug("library version: %s", ver));
+ }
+}
diff -up util-linux-2.23.2/libsmartcols/src/iter.c.kzak util-linux-2.23.2/libsmartcols/src/iter.c
--- util-linux-2.23.2/libsmartcols/src/iter.c.kzak 2014-09-25 14:41:48.987843896 +0200
+++ util-linux-2.23.2/libsmartcols/src/iter.c 2014-09-25 14:41:48.987843896 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009-2014 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: iter
+ * @title: Iterator
+ * @short_description: unified iterator
+ *
+ * The iterator keeps the direction and the last position
+ * for access to the internal library tables/lists.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "smartcolsP.h"
+
+/**
+ * scols_new_iter:
+ * @direction: SCOLS_INTER_{FOR,BACK}WARD direction
+ *
+ * Returns: newly allocated generic libmount iterator.
+ */
+struct libscols_iter *scols_new_iter(int direction)
+{
+ struct libscols_iter *itr = calloc(1, sizeof(*itr));
+ if (!itr)
+ return NULL;
+ itr->direction = direction;
+ return itr;
+}
+
+/**
+ * scols_free_iter:
+ * @itr: iterator pointer
+ *
+ * Deallocates the iterator.
+ */
+void scols_free_iter(struct libscols_iter *itr)
+{
+ free(itr);
+}
+
+/**
+ * scols_reset_iter:
+ * @itr: iterator pointer
+ * @direction: SCOLS_INTER_{FOR,BACK}WARD or -1 to keep the direction unchanged
+ *
+ * Resets the iterator.
+ */
+void scols_reset_iter(struct libscols_iter *itr, int direction)
+{
+ if (direction == -1)
+ direction = itr->direction;
+
+ memset(itr, 0, sizeof(*itr));
+ itr->direction = direction;
+}
+
+/**
+ * scols_iter_get_direction:
+ * @itr: iterator pointer
+ *
+ * Returns: SCOLS_INTER_{FOR,BACK}WARD
+ */
+int scols_iter_get_direction(struct libscols_iter *itr)
+{
+ return itr->direction;
+}
diff -up util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in.kzak util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in
--- util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in.kzak 2014-09-25 14:41:48.988843905 +0200
+++ util-linux-2.23.2/libsmartcols/src/libsmartcols.h.in 2014-09-25 14:41:48.988843905 +0200
@@ -0,0 +1,229 @@
+/*
+ * Prints table or tree.
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef _LIBSMARTCOLS_H
+#define _LIBSMARTCOLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+/**
+ * LIBSMARTCOLS_VERSION:
+ *
+ * Library version string
+ */
+#define LIBSMARTCOLS_VERSION "@LIBSMARTCOLS_VERSION@"
+
+/**
+ * libscols_iter:
+ *
+ * Generic iterator
+ */
+struct libscols_iter;
+
+/**
+ * libscols_symbols:
+ *
+ * Symbol groups for printing tree hierarchies
+ */
+struct libscols_symbols;
+
+/**
+ * libscols_cell:
+ *
+ * A cell - the smallest library object
+ */
+struct libscols_cell;
+
+/**
+ * libscols_line:
+ *
+ * A line - an array of cells
+ */
+struct libscols_line;
+
+/**
+ * libscols_table:
+ *
+ * A table - The most abstract object, encapsulating lines, columns, symbols and cells
+ */
+struct libscols_table;
+
+/**
+ * libscols_column:
+ *
+ * A column - defines the number of columns and column names
+ */
+struct libscols_column;
+
+/* iter.c */
+enum {
+
+ SCOLS_ITER_FORWARD = 0,
+ SCOLS_ITER_BACKWARD
+};
+
+/*
+ * Column flags
+ */
+enum {
+ SCOLS_FL_TRUNC = (1 << 0), /* truncate fields data if necessary */
+ SCOLS_FL_TREE = (1 << 1), /* use tree "ascii art" */
+ SCOLS_FL_RIGHT = (1 << 2), /* align to the right */
+ SCOLS_FL_STRICTWIDTH = (1 << 3), /* don't reduce width if column is empty */
+ SCOLS_FL_NOEXTREMES = (1 << 4), /* ignore extreme fields when count column width*/
+};
+
+extern struct libscols_iter *scols_new_iter(int direction);
+extern void scols_free_iter(struct libscols_iter *itr);
+extern void scols_reset_iter(struct libscols_iter *itr, int direction);
+extern int scols_iter_get_direction(struct libscols_iter *itr);
+
+/* init.c */
+extern void scols_init_debug(int mask);
+
+/* version.c */
+extern int scols_parse_version_string(const char *ver_string);
+extern int scols_get_library_version(const char **ver_string);
+
+/* symbols.c */
+extern struct libscols_symbols *scols_new_symbols(void);
+extern void scols_ref_symbols(struct libscols_symbols *sy);
+extern void scols_unref_symbols(struct libscols_symbols *sy);
+extern struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sb);
+extern int scols_symbols_set_branch(struct libscols_symbols *sb, const char *str);
+extern int scols_symbols_set_vertical(struct libscols_symbols *sb, const char *str);
+extern int scols_symbols_set_right(struct libscols_symbols *sb, const char *str);
+
+/* cell.c */
+extern int scols_reset_cell(struct libscols_cell *ce);
+extern int scols_cell_copy_content(struct libscols_cell *dest,
+ const struct libscols_cell *src);
+extern int scols_cell_set_data(struct libscols_cell *ce, const char *str);
+extern int scols_cell_refer_data(struct libscols_cell *ce, char *str);
+extern const char *scols_cell_get_data(const struct libscols_cell *ce);
+extern int scols_cell_set_color(struct libscols_cell *ce, const char *color);
+extern const char *scols_cell_get_color(const struct libscols_cell *ce);
+
+extern void *scols_cell_get_userdata(struct libscols_cell *ce);
+extern int scols_cell_set_userdata(struct libscols_cell *ce, void *data);
+
+extern int scols_cmpstr_cells(struct libscols_cell *a,
+ struct libscols_cell *b, void *data);
+/* column.c */
+extern int scols_column_is_tree(struct libscols_column *cl);
+extern int scols_column_is_trunc(struct libscols_column *cl);
+extern int scols_column_is_right(struct libscols_column *cl);
+extern int scols_column_is_strict_width(struct libscols_column *cl);
+extern int scols_column_is_noextremes(struct libscols_column *cl);
+
+extern int scols_column_set_flags(struct libscols_column *cl, int flags);
+extern int scols_column_get_flags(struct libscols_column *cl);
+extern struct libscols_column *scols_new_column(void);
+extern void scols_ref_column(struct libscols_column *cl);
+extern void scols_unref_column(struct libscols_column *cl);
+extern struct libscols_column *scols_copy_column(const struct libscols_column *cl);
+extern int scols_column_set_whint(struct libscols_column *cl, double whint);
+extern double scols_column_get_whint(struct libscols_column *cl);
+extern struct libscols_cell *scols_column_get_header(struct libscols_column *cl);
+extern int scols_column_set_color(struct libscols_column *cl, const char *color);
+extern const char *scols_column_get_color(struct libscols_column *cl);
+
+extern int scols_column_set_cmpfunc(struct libscols_column *cl,
+ int (*cmp)(struct libscols_cell *a,
+ struct libscols_cell *b, void *),
+ void *data);
+
+/* line.c */
+extern struct libscols_line *scols_new_line(void);
+extern void scols_ref_line(struct libscols_line *ln);
+extern void scols_unref_line(struct libscols_line *ln);
+extern int scols_line_alloc_cells(struct libscols_line *ln, size_t n);
+extern void scols_line_free_cells(struct libscols_line *ln);
+extern int scols_line_set_userdata(struct libscols_line *ln, void *data);
+extern void *scols_line_get_userdata(struct libscols_line *ln);
+extern int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child);
+extern int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child);
+extern int scols_line_has_children(struct libscols_line *ln);
+extern int scols_line_next_child(struct libscols_line *ln,
+ struct libscols_iter *itr, struct libscols_line **chld);
+extern struct libscols_line *scols_line_get_parent(struct libscols_line *ln);
+extern int scols_line_set_color(struct libscols_line *ln, const char *color);
+extern const char *scols_line_get_color(struct libscols_line *ln);
+extern size_t scols_line_get_ncells(struct libscols_line *ln);
+extern struct libscols_cell *scols_line_get_cell(struct libscols_line *ln, size_t n);
+extern struct libscols_cell *scols_line_get_column_cell(
+ struct libscols_line *ln,
+ struct libscols_column *cl);
+extern int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data);
+extern int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data);
+extern struct libscols_line *scols_copy_line(struct libscols_line *ln);
+
+/* table */
+extern int scols_table_colors_wanted(struct libscols_table *tb);
+extern int scols_table_is_raw(struct libscols_table *tb);
+extern int scols_table_is_ascii(struct libscols_table *tb);
+extern int scols_table_is_noheadings(struct libscols_table *tb);
+extern int scols_table_is_empty(struct libscols_table *tb);
+extern int scols_table_is_export(struct libscols_table *tb);
+extern int scols_table_is_maxout(struct libscols_table *tb);
+extern int scols_table_is_tree(struct libscols_table *tb);
+
+extern int scols_table_enable_colors(struct libscols_table *tb, int enable);
+extern int scols_table_enable_raw(struct libscols_table *tb, int enable);
+extern int scols_table_enable_ascii(struct libscols_table *tb, int enable);
+extern int scols_table_enable_noheadings(struct libscols_table *tb, int enable);
+extern int scols_table_enable_export(struct libscols_table *tb, int enable);
+extern int scols_table_enable_maxout(struct libscols_table *tb, int enable);
+
+extern int scols_table_set_column_separator(struct libscols_table *tb, const char *sep);
+extern int scols_table_set_line_separator(struct libscols_table *tb, const char *sep);
+
+extern struct libscols_table *scols_new_table(void);
+extern void scols_ref_table(struct libscols_table *tb);
+extern void scols_unref_table(struct libscols_table *tb);
+extern int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl);
+extern int scols_table_remove_column(struct libscols_table *tb, struct libscols_column *cl);
+extern int scols_table_remove_columns(struct libscols_table *tb);
+extern struct libscols_column *scols_table_new_column(struct libscols_table *tb, const char *name, double whint, int flags);
+extern int scols_table_next_column(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_column **cl);
+extern char *scols_table_get_column_separator(struct libscols_table *tb);
+extern char *scols_table_get_line_separator(struct libscols_table *tb);
+extern int scols_table_get_ncols(struct libscols_table *tb);
+extern int scols_table_get_nlines(struct libscols_table *tb);
+extern struct libscols_column *scols_table_get_column(struct libscols_table *tb, size_t n);
+extern int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln);
+extern int scols_table_remove_line(struct libscols_table *tb, struct libscols_line *ln);
+extern void scols_table_remove_lines(struct libscols_table *tb);
+extern int scols_table_next_line(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_line **ln);
+extern struct libscols_line *scols_table_new_line(struct libscols_table *tb, struct libscols_line *parent);
+extern struct libscols_line *scols_table_get_line(struct libscols_table *tb, size_t n);
+extern struct libscols_table *scols_copy_table(struct libscols_table *tb);
+extern int scols_table_set_symbols(struct libscols_table *tb, struct libscols_symbols *sy);
+
+extern int scols_table_set_stream(struct libscols_table *tb, FILE *stream);
+extern FILE *scols_table_get_stream(struct libscols_table *tb);
+extern int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce);
+
+extern int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl);
+
+/* table_print.c */
+extern int scols_print_table(struct libscols_table *tb);
+extern int scols_print_table_to_string(struct libscols_table *tb, char **data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSMARTCOLS_H */
diff -up util-linux-2.23.2/libsmartcols/src/libsmartcols.sym.kzak util-linux-2.23.2/libsmartcols/src/libsmartcols.sym
--- util-linux-2.23.2/libsmartcols/src/libsmartcols.sym.kzak 2014-09-25 14:41:48.988843905 +0200
+++ util-linux-2.23.2/libsmartcols/src/libsmartcols.sym 2014-09-25 14:41:48.988843905 +0200
@@ -0,0 +1,112 @@
+/*
+ * symbols since util-linux 2.25
+ */
+SMARTCOLS_2.25 {
+global:
+ scols_cell_copy_content;
+ scols_cell_get_color;
+ scols_cell_get_data;
+ scols_cell_get_userdata;
+ scols_cell_refer_data;
+ scols_cell_set_color;
+ scols_cell_set_data;
+ scols_cell_set_userdata;
+ scols_cmpstr_cells;
+ scols_column_get_color;
+ scols_column_get_flags;
+ scols_column_get_header;
+ scols_column_get_whint;
+ scols_column_is_noextremes;
+ scols_column_is_right;
+ scols_column_is_strict_width;
+ scols_column_is_tree;
+ scols_column_is_trunc;
+ scols_column_set_cmpfunc;
+ scols_column_set_color;
+ scols_column_set_flags;
+ scols_column_set_whint;
+ scols_copy_column;
+ scols_copy_line;
+ scols_copy_symbols;
+ scols_copy_table;
+ scols_free_iter;
+ scols_get_library_version;
+ scols_init_debug;
+ scols_iter_get_direction;
+ scols_line_add_child;
+ scols_line_alloc_cells;
+ scols_line_free_cells;
+ scols_line_get_cell;
+ scols_line_get_color;
+ scols_line_get_column_cell;
+ scols_line_get_ncells;
+ scols_line_get_parent;
+ scols_line_get_userdata;
+ scols_line_has_children;
+ scols_line_next_child;
+ scols_line_refer_data;
+ scols_line_remove_child;
+ scols_line_set_color;
+ scols_line_set_data;
+ scols_line_set_userdata;
+ scols_new_column;
+ scols_new_iter;
+ scols_new_line;
+ scols_new_symbols;
+ scols_new_table;
+ scols_parse_version_string;
+ scols_print_table;
+ scols_print_table_to_string;
+ scols_ref_column;
+ scols_ref_line;
+ scols_ref_symbols;
+ scols_ref_table;
+ scols_reset_cell;
+ scols_reset_iter;
+ scols_sort_table;
+ scols_symbols_set_branch;
+ scols_symbols_set_right;
+ scols_symbols_set_vertical;
+ scols_table_add_column;
+ scols_table_add_line;
+ scols_table_colors_wanted;
+ scols_table_enable_ascii;
+ scols_table_enable_colors;
+ scols_table_enable_export;
+ scols_table_enable_maxout;
+ scols_table_enable_noheadings;
+ scols_table_enable_raw;
+ scols_table_get_column;
+ scols_table_get_column_separator;
+ scols_table_get_line;
+ scols_table_get_line_separator;
+ scols_table_get_ncols;
+ scols_table_get_nlines;
+ scols_table_get_stream;
+ scols_table_is_ascii;
+ scols_table_is_empty;
+ scols_table_is_export;
+ scols_table_is_maxout;
+ scols_table_is_noheadings;
+ scols_table_is_raw;
+ scols_table_is_tree;
+ scols_table_new_column;
+ scols_table_new_line;
+ scols_table_next_column;
+ scols_table_next_line;
+ scols_table_reduce_termwidth;
+ scols_table_remove_column;
+ scols_table_remove_columns;
+ scols_table_remove_line;
+ scols_table_remove_lines;
+ scols_table_set_column_separator;
+ scols_table_set_line_separator;
+ scols_table_set_stream;
+ scols_table_set_symbols;
+ scols_unref_column;
+ scols_unref_line;
+ scols_unref_symbols;
+ scols_unref_table;
+local:
+ *;
+};
diff -up util-linux-2.23.2/libsmartcols/src/line.c.kzak util-linux-2.23.2/libsmartcols/src/line.c
--- util-linux-2.23.2/libsmartcols/src/line.c.kzak 2014-09-25 14:41:48.989843915 +0200
+++ util-linux-2.23.2/libsmartcols/src/line.c 2014-09-25 14:41:48.989843915 +0200
@@ -0,0 +1,456 @@
+/*
+ * line.c - functions for table handling at the line level
+ *
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: line
+ * @title: Line
+ * @short_description: line API
+ *
+ * An API to access and modify per-line data and information.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "smartcolsP.h"
+
+/**
+ * scols_new_line:
+ *
+ * Note that the line is allocated without cells, the cells will be allocated
+ * later when you add the line to the table. If you want to use the line
+ * without table then you have to explicitly allocate the cells by
+ * scols_line_alloc_cells().
+ *
+ * Returns: a pointer to a new struct libscols_line instance.
+ */
+struct libscols_line *scols_new_line(void)
+{
+ struct libscols_line *ln;
+
+ ln = calloc(1, sizeof(*ln));
+ if (!ln)
+ return NULL;
+
+ DBG(LINE, ul_debugobj(ln, "alloc"));
+ ln->refcount = 1;
+ INIT_LIST_HEAD(&ln->ln_lines);
+ INIT_LIST_HEAD(&ln->ln_children);
+ INIT_LIST_HEAD(&ln->ln_branch);
+ return ln;
+}
+
+/**
+ * scols_ref_line:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Increases the refcount of @ln.
+ */
+void scols_ref_line(struct libscols_line *ln)
+{
+ if (ln)
+ ln->refcount++;
+}
+
+/**
+ * scols_unref_line:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Decreases the refcount of @ln. When the count falls to zero, the instance
+ * is automatically deallocated.
+ */
+void scols_unref_line(struct libscols_line *ln)
+{
+
+ if (ln && --ln->refcount <= 0) {
+ DBG(CELL, ul_debugobj(ln, "dealloc"));
+ list_del(&ln->ln_lines);
+ list_del(&ln->ln_children);
+ scols_line_free_cells(ln);
+ free(ln->color);
+ free(ln);
+ return;
+ }
+}
+
+/**
+ * scols_line_free_cells:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Frees the allocated cells referenced to by @ln.
+ */
+void scols_line_free_cells(struct libscols_line *ln)
+{
+ size_t i;
+
+ if (!ln || !ln->cells)
+ return;
+
+ DBG(LINE, ul_debugobj(ln, "free cells"));
+
+ for (i = 0; i < ln->ncells; i++)
+ scols_reset_cell(&ln->cells[i]);
+
+ free(ln->cells);
+ ln->ncells = 0;
+ ln->cells = NULL;
+}
+
+/**
+ * scols_line_alloc_cells:
+ * @ln: a pointer to a struct libscols_line instance
+ * @n: the number of elements
+ *
+ * Allocates space for @n cells. This function is optional,
+ * and libsmartcols automatically allocates necessary cells
+ * according to number of columns in the table when you add
+ * the line to the table. See scols_table_add_line().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_alloc_cells(struct libscols_line *ln, size_t n)
+{
+ struct libscols_cell *ce;
+
+ assert(ln);
+
+ if (!ln)
+ return -EINVAL;
+ if (ln->ncells == n)
+ return 0;
+
+ if (!n) {
+ scols_line_free_cells(ln);
+ return 0;
+ }
+
+ DBG(LINE, ul_debugobj(ln, "alloc %zu cells", n));
+
+ ce = realloc(ln->cells, n * sizeof(struct libscols_cell));
+ if (!ce)
+ return -errno;
+
+ if (n > ln->ncells)
+ memset(ce + ln->ncells, 0,
+ (n - ln->ncells) * sizeof(struct libscols_cell));
+
+ ln->cells = ce;
+ ln->ncells = n;
+ return 0;
+}
+
+/**
+ * scols_line_set_userdata:
+ * @ln: a pointer to a struct libscols_line instance
+ * @data: user data
+ *
+ * Binds @data to @ln.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_set_userdata(struct libscols_line *ln, void *data)
+{
+ assert(ln);
+ if (!ln)
+ return -EINVAL;
+ ln->userdata = data;
+ return 0;
+}
+
+/**
+ * scols_line_get_userdata:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+void *scols_line_get_userdata(struct libscols_line *ln)
+{
+ assert(ln);
+ return ln ? ln->userdata : NULL;
+}
+
+/**
+ * scols_line_remove_child:
+ * @ln: a pointer to a struct libscols_line instance
+ * @child: a pointer to a struct libscols_line instance
+ *
+ * Removes @child as a child of @ln.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child)
+{
+ assert(ln);
+ assert(child);
+
+ if (!ln || !child)
+ return -EINVAL;
+
+ DBG(LINE, ul_debugobj(ln, "remove child %p", child));
+
+ list_del_init(&child->ln_children);
+ child->parent = NULL;
+ scols_unref_line(child);
+
+ scols_unref_line(ln);
+ return 0;
+}
+
+/**
+ * scols_line_add_child:
+ * @ln: a pointer to a struct libscols_line instance
+ * @child: a pointer to a struct libscols_line instance
+ *
+ * Sets @child as a child of @ln.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child)
+{
+ assert(ln);
+ assert(child);
+
+ if (!ln || !child)
+ return -EINVAL;
+
+ /* unref old<->parent */
+ if (child->parent)
+ scols_line_remove_child(child->parent, child);
+
+ DBG(LINE, ul_debugobj(ln, "add child %p", child));
+
+ /* new reference from parent to child */
+ list_add_tail(&child->ln_children, &ln->ln_branch);
+ scols_ref_line(child);
+
+ /* new reference from child to parent */
+ child->parent = ln;
+ scols_ref_line(ln);
+
+ return 0;
+}
+
+/**
+ * scols_line_get_parent:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: a pointer to @ln's parent, NULL in case it has no parent or if there was an error.
+ */
+struct libscols_line *scols_line_get_parent(struct libscols_line *ln)
+{
+ assert(ln);
+ return ln ? ln->parent : NULL;
+}
+
+/**
+ * scols_line_has_children:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: 1 if @ln has any children, otherwise 0.
+ */
+int scols_line_has_children(struct libscols_line *ln)
+{
+ assert(ln);
+ return ln ? !list_empty(&ln->ln_branch) : 0;
+}
+
+/**
+ * scols_line_next_child:
+ * @ln: a pointer to a struct libscols_line instance
+ * @itr: a pointer to a struct libscols_iter instance
+ * @chld: a pointer to a pointer to a struct libscols_line instance
+ *
+ * Finds the next child and returns a pointer to it via @chld.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_next_child(struct libscols_line *ln,
+ struct libscols_iter *itr,
+ struct libscols_line **chld)
+{
+ int rc = 1;
+
+ if (!ln || !itr || !chld)
+ return -EINVAL;
+ *chld = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &ln->ln_branch);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *chld, struct libscols_line, ln_children);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * scols_line_set_color:
+ * @ln: a pointer to a struct libscols_line instance
+ * @color: ESC sequence
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_set_color(struct libscols_line *ln, const char *color)
+{
+ char *p = NULL;
+
+ assert(ln);
+ if (!ln)
+ return -EINVAL;
+ if (color) {
+ p = strdup(color);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(ln->color);
+ ln->color = p;
+ return 0;
+}
+
+/**
+ * scols_line_get_color:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: @ln's color string, NULL in case of an error.
+ */
+const char *scols_line_get_color(struct libscols_line *ln)
+{
+ assert(ln);
+ return ln ? ln->color : NULL;
+}
+
+/**
+ * scols_line_get_ncells:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: @ln's number of cells
+ */
+size_t scols_line_get_ncells(struct libscols_line *ln)
+{
+ assert(ln);
+ return ln ? ln->ncells : 0;
+}
+
+/**
+ * scols_line_get_cell:
+ * @ln: a pointer to a struct libscols_line instance
+ * @n: cell number to retrieve
+ *
+ * Returns: the @n-th cell in @ln, NULL in case of an error.
+ */
+struct libscols_cell *scols_line_get_cell(struct libscols_line *ln,
+ size_t n)
+{
+ assert(ln);
+
+ if (!ln || n >= ln->ncells)
+ return NULL;
+ return &ln->cells[n];
+}
+
+/**
+ * scols_line_get_column_cell:
+ * @ln: a pointer to a struct libscols_line instance
+ * @cl: pointer to cell
+ *
+ * Like scols_line_get_cell() by cell is referenced by column.
+ *
+ * Returns: the @n-th cell in @ln, NULL in case of an error.
+ */
+struct libscols_cell *scols_line_get_column_cell(
+ struct libscols_line *ln,
+ struct libscols_column *cl)
+{
+ assert(ln);
+ assert(cl);
+
+ return scols_line_get_cell(ln, cl->seqnum);
+}
+
+/**
+ * scols_line_set_data:
+ * @ln: a pointer to a struct libscols_cell instance
+ * @n: number of the cell, whose data is to be set
+ * @data: actual data to set
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data)
+{
+ struct libscols_cell *ce = scols_line_get_cell(ln, n);
+
+ if (!ce)
+ return -EINVAL;
+ return scols_cell_set_data(ce, data);
+}
+
+/**
+ * scols_line_refer_data:
+ * @ln: a pointer to a struct libscols_cell instance
+ * @n: number of the cell which will refer to @data
+ * @data: actual data to refer to
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data)
+{
+ struct libscols_cell *ce = scols_line_get_cell(ln, n);
+
+ if (!ce)
+ return -EINVAL;
+ return scols_cell_refer_data(ce, data);
+}
+
+/**
+ * scols_copy_line:
+ * @ln: a pointer to a struct libscols_cell instance
+ *
+ * Returns: A newly allocated copy of @ln, NULL in case of an error.
+ */
+struct libscols_line *scols_copy_line(struct libscols_line *ln)
+{
+ struct libscols_line *ret;
+ size_t i;
+
+ assert (ln);
+ if (!ln)
+ return NULL;
+
+ ret = scols_new_line();
+ if (!ret)
+ return NULL;
+ if (scols_line_set_color(ret, ln->color))
+ goto err;
+ if (scols_line_alloc_cells(ret, ln->ncells))
+ goto err;
+
+ ret->userdata = ln->userdata;
+ ret->ncells = ln->ncells;
+ ret->seqnum = ln->seqnum;
+
+ DBG(LINE, ul_debugobj(ln, "copy to %p", ret));
+
+ for (i = 0; i < ret->ncells; ++i) {
+ if (scols_cell_copy_content(&ret->cells[i], &ln->cells[i]))
+ goto err;
+ }
+
+ return ret;
+err:
+ scols_unref_line(ret);
+ return NULL;
+}
+
+
diff -up util-linux-2.23.2/libsmartcols/src/Makemodule.am.kzak util-linux-2.23.2/libsmartcols/src/Makemodule.am
--- util-linux-2.23.2/libsmartcols/src/Makemodule.am.kzak 2014-09-25 14:41:48.985843877 +0200
+++ util-linux-2.23.2/libsmartcols/src/Makemodule.am 2014-09-25 14:42:10.471048869 +0200
@@ -0,0 +1,75 @@
+
+
+## smartcols.h is generated, so it's stored in builddir! (no distribute in RHEL7)
+#smartcolsincdir = $(includedir)/libsmartcols
+#nodist_smartcolsinc_HEADERS = $(top_builddir)/libsmartcols/src/libsmartcols.h
+
+noinst_LTLIBRARIES += libsmartcols.la
+libsmartcols_la_SOURCES= \
+ include/list.h \
+ \
+ libsmartcols/src/smartcolsP.h \
+ libsmartcols/src/iter.c \
+ libsmartcols/src/symbols.c \
+ libsmartcols/src/cell.c \
+ libsmartcols/src/column.c \
+ libsmartcols/src/line.c \
+ libsmartcols/src/table.c \
+ libsmartcols/src/table_print.c \
+ libsmartcols/src/version.c \
+ libsmartcols/src/init.c \
+ $(nodist_smartcolsinc_HEADERS)
+
+nodist_libsmartcols_la_SOURCES = libsmartcols/src/smartcolsP.h
+
+libsmartcols_la_LIBADD = libcommon.la
+
+libsmartcols_la_CFLAGS = \
+ $(SOLIB_CFLAGS) \
+ -I$(ul_libsmartcols_incdir) \
+ -I$(top_srcdir)/libsmartcols/src
+
+libsmartcols_la_DEPENDENCIES = \
+ libcommon.la \
+ libsmartcols/src/libsmartcols.sym \
+ libsmartcols/src/libsmartcols.h.in
+
+libsmartcols_la_LDFLAGS = \
+ $(SOLIB_LDFLAGS) \
+ -Wl,--version-script=$(top_srcdir)/libsmartcols/src/libsmartcols.sym \
+ -version-info $(LIBSMARTCOLS_VERSION_INFO)
+
+EXTRA_DIST += \
+ libsmartcols/src/libsmartcols.sym \
+ libsmartcols/src/libsmartcols.h.in
+
+
+if BUILD_LIBSMARTCOLS_TESTS
+check_PROGRAMS += test_smartcols
+
+libsmartcols_tests_cflags = $(libsmartcols_la_CFLAGS)
+libsmartcols_tests_ldadd = libsmartcols.la libcommon.la
+
+test_smartcols_SOURCES = libsmartcols/src/test.c
+test_smartcols_CFLAGS = $(libsmartcols_tests_cflags)
+test_smartcols_LDADD = $(libsmartcols_tests_ldadd)
+endif # BUILD_LIBSMARTCOLS_TESTS
+
+
+# move lib from $(usrlib_execdir) to $(libdir) if needed
+install-exec-hook-libsmartcols:
+ if test "$(usrlib_execdir)" != "$(libdir)" -a -f "$(DESTDIR)$(usrlib_execdir)/libsmartcols.so"; then \
+ mkdir -p $(DESTDIR)$(libdir); \
+ mv $(DESTDIR)$(usrlib_execdir)/libsmartcols.so.* $(DESTDIR)$(libdir); \
+ so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libsmartcols.so); \
+ so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \
+ (cd $(DESTDIR)$(usrlib_execdir) && \
+ rm -f libsmartcols.so && \
+ $(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libsmartcols.so); \
+ fi
+
+uninstall-hook-libsmartcols:
+ rm -f $(DESTDIR)$(libdir)/libsmartcols.so*
+
+INSTALL_EXEC_HOOKS += install-exec-hook-libsmartcols
+UNINSTALL_HOOKS += uninstall-hook-libsmartcols
diff -up util-linux-2.23.2/libsmartcols/src/smartcolsP.h.kzak util-linux-2.23.2/libsmartcols/src/smartcolsP.h
--- util-linux-2.23.2/libsmartcols/src/smartcolsP.h.kzak 2014-09-25 14:41:48.989843915 +0200
+++ util-linux-2.23.2/libsmartcols/src/smartcolsP.h 2014-09-25 14:41:48.989843915 +0200
@@ -0,0 +1,173 @@
+/*
+ * smartcolsP.h - private library header file
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#ifndef _LIBSMARTCOLS_PRIVATE_H
+#define _LIBSMARTCOLS_PRIVATE_H
+
+#include "c.h"
+#include "list.h"
+#include "colors.h"
+#include "debug.h"
+
+#include "libsmartcols.h"
+
+/* features */
+#define CONFIG_LIBSMARTCOLS_ASSERT
+
+#ifdef CONFIG_LIBSMARTCOLS_ASSERT
+# include <assert.h>
+#else
+# define assert(x)
+#endif
+
+/*
+ * Debug
+ */
+#define SCOLS_DEBUG_INIT (1 << 1)
+#define SCOLS_DEBUG_CELL (1 << 2)
+#define SCOLS_DEBUG_LINE (1 << 3)
+#define SCOLS_DEBUG_TAB (1 << 4)
+#define SCOLS_DEBUG_COL (1 << 5)
+#define SCOLS_DEBUG_BUFF (1 << 6)
+#define SCOLS_DEBUG_ALL 0xFFFF
+
+UL_DEBUG_DECLARE_MASK(libsmartcols);
+#define DBG(m, x) __UL_DBG(libsmartcols, SCOLS_DEBUG_, m, x)
+#define ON_DBG(m, x) __UL_DBG_CALL(libsmartcols, SCOLS_DEBUG_, m, x)
+#define DBG_FLUSH __UL_DBG_FLUSH(libsmartcols, SCOLS_DEBUG_)
+
+/*
+ * Generic iterator
+ */
+struct libscols_iter {
+ struct list_head *p; /* current position */
+ struct list_head *head; /* start position */
+ int direction; /* SCOLS_ITER_{FOR,BACK}WARD */
+};
+
+/*
+ * Tree symbols
+ */
+struct libscols_symbols {
+ int refcount;
+ char *branch;
+ char *vert;
+ char *right;
+};
+
+/*
+ * Table cells
+ */
+struct libscols_cell {
+ char *data;
+ char *color;
+ void *userdata;
+};
+
+
+/*
+ * Table column
+ */
+struct libscols_column {
+ int refcount; /* reference counter */
+ size_t seqnum; /* column index */
+
+ size_t width; /* real column width */
+ size_t width_min; /* minimal width (usually header width) */
+ size_t width_max; /* maximal width */
+ size_t width_avg; /* average width, used to detect extreme fields */
+ double width_hint; /* hint (N < 1 is in percent of termwidth) */
+
+ int flags;
+ int is_extreme;
+ char *color; /* default column color */
+
+ int (*cmpfunc)(struct libscols_cell *,
+ struct libscols_cell *,
+ void *); /* cells comparison function */
+ void *cmpfunc_data;
+
+ struct libscols_cell header;
+ struct list_head cl_columns;
+};
+
+/*
+ * Table line
+ */
+struct libscols_line {
+ int refcount;
+ size_t seqnum;
+
+ void *userdata;
+ char *color; /* default line color */
+
+ struct libscols_cell *cells; /* array with data */
+ size_t ncells; /* number of cells */
+
+ struct list_head ln_lines; /* table lines */
+ struct list_head ln_branch; /* begin of branch (head of ln_children) */
+ struct list_head ln_children;
+
+ struct libscols_line *parent;
+};
+
+enum {
+ SCOLS_FMT_HUMAN = 0, /* default, human readable */
+ SCOLS_FMT_RAW, /* space separated */
+ SCOLS_FMT_EXPORT /* COLNAME="data" ... */
+};
+
+/*
+ * The table
+ */
+struct libscols_table {
+ int refcount;
+ size_t ncols; /* number of columns */
+ size_t ntreecols; /* number of columns with SCOLS_FL_TREE */
+ size_t nlines; /* number of lines */
+ size_t termwidth; /* terminal width */
+ size_t termreduce; /* extra blank space */
+ FILE *out; /* output stream */
+
+ char *colsep; /* column separator */
+ char *linesep; /* line separator */
+
+ struct list_head tb_columns;
+ struct list_head tb_lines;
+ struct libscols_symbols *symbols;
+
+ int format; /* SCOLS_FMT_* */
+
+ /* flags */
+ unsigned int ascii :1, /* don't use unicode */
+ colors_wanted :1, /* enable colors */
+ is_term :1, /* isatty() */
+ maxout :1, /* maximalize output */
+ no_headings :1; /* don't print header */
+};
+
+#define IS_ITER_FORWARD(_i) ((_i)->direction == SCOLS_ITER_FORWARD)
+#define IS_ITER_BACKWARD(_i) ((_i)->direction == SCOLS_ITER_BACKWARD)
+
+#define SCOLS_ITER_INIT(itr, list) \
+ do { \
+ (itr)->p = IS_ITER_FORWARD(itr) ? \
+ (list)->next : (list)->prev; \
+ (itr)->head = (list); \
+ } while(0)
+
+#define SCOLS_ITER_ITERATE(itr, res, restype, member) \
+ do { \
+ res = list_entry((itr)->p, restype, member); \
+ (itr)->p = IS_ITER_FORWARD(itr) ? \
+ (itr)->p->next : (itr)->p->prev; \
+ } while(0)
+
+#endif /* _LIBSMARTCOLS_PRIVATE_H */
diff -up util-linux-2.23.2/libsmartcols/src/symbols.c.kzak util-linux-2.23.2/libsmartcols/src/symbols.c
--- util-linux-2.23.2/libsmartcols/src/symbols.c.kzak 2014-09-25 14:41:48.989843915 +0200
+++ util-linux-2.23.2/libsmartcols/src/symbols.c 2014-09-25 14:41:48.989843915 +0200
@@ -0,0 +1,175 @@
+/*
+ * symbols.c - routines for symbol handling
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: symbols
+ * @title: Symbols
+ * @short_description: symbols API
+ *
+ * An API to access and modify data and information per symbol/symbol group.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "smartcolsP.h"
+
+/**
+ * scols_new_symbols:
+ *
+ * Returns: a pointer to a newly allocated struct libscols_symbols instance.
+ */
+struct libscols_symbols *scols_new_symbols(void)
+{
+ struct libscols_symbols *sy = calloc(1, sizeof(struct libscols_symbols));
+
+ if (!sy)
+ return NULL;
+ sy->refcount = 1;
+ return sy;
+}
+
+/**
+ * scols_ref_symbols:
+ * @sy: a pointer to a struct libscols_symbols instance
+ *
+ * Increases the refcount of @sy.
+ */
+void scols_ref_symbols(struct libscols_symbols *sy)
+{
+ if (sy)
+ sy->refcount++;
+}
+
+/**
+ * scols_unref_symbols:
+ * @sy: a pointer to a struct libscols_symbols instance
+ *
+ * Decreases the refcount of @sy.
+ */
+void scols_unref_symbols(struct libscols_symbols *sy)
+{
+ if (sy && --sy->refcount <= 0) {
+ free(sy->branch);
+ free(sy->vert);
+ free(sy->right);
+ free(sy);
+ }
+}
+
+/**
+ * scols_symbols_set_branch:
+ * @sb: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the branch part of a tree output
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_symbols_set_branch(struct libscols_symbols *sb, const char *str)
+{
+ char *p = NULL;
+
+ assert(sb);
+
+ if (!sb)
+ return -EINVAL;
+ if (str) {
+ p = strdup(str);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(sb->branch);
+ sb->branch = p;
+ return 0;
+}
+
+/**
+ * scols_symbols_set_vertical:
+ * @sb: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the vertical part of a tree output
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_symbols_set_vertical(struct libscols_symbols *sb, const char *str)
+{
+ char *p = NULL;
+
+ assert(sb);
+
+ if (!sb)
+ return -EINVAL;
+ if (str) {
+ p = strdup(str);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(sb->vert);
+ sb->vert = p;
+ return 0;
+}
+
+/**
+ * scols_symbols_set_right:
+ * @sb: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the right part of a tree output
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_symbols_set_right(struct libscols_symbols *sb, const char *str)
+{
+ char *p = NULL;
+
+ assert(sb);
+
+ if (!sb)
+ return -EINVAL;
+ if (str) {
+ p = strdup(str);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(sb->right);
+ sb->right = p;
+ return 0;
+}
+
+/**
+ * scols_copy_symbols:
+ * @sb: a pointer to a struct libscols_symbols instance
+ *
+ * Returns: a newly allocated copy of the @sb symbol group or NULL in caes of an error.
+ */
+struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sb)
+{
+ struct libscols_symbols *ret;
+ int rc;
+
+ assert(sb);
+ if (!sb)
+ return NULL;
+
+ ret = scols_new_symbols();
+ if (!ret)
+ return NULL;
+
+ rc = scols_symbols_set_branch(ret, sb->branch);
+ if (!rc)
+ rc = scols_symbols_set_vertical(ret, sb->vert);
+ if (!rc)
+ rc = scols_symbols_set_right(ret, sb->right);
+ if (!rc)
+ return ret;
+
+ scols_unref_symbols(ret);
+ return NULL;
+
+}
+
+
diff -up util-linux-2.23.2/libsmartcols/src/table.c.kzak util-linux-2.23.2/libsmartcols/src/table.c
--- util-linux-2.23.2/libsmartcols/src/table.c.kzak 2014-09-25 14:41:48.991843934 +0200
+++ util-linux-2.23.2/libsmartcols/src/table.c 2014-09-25 14:41:48.991843934 +0200
@@ -0,0 +1,1049 @@
+/*
+ * table.c - functions handling the data at the table level
+ *
+ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: table
+ * @title: Table
+ * @short_description: table data API
+ *
+ * Table data manipulation API.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <ctype.h>
+
+#include "nls.h"
+#include "widechar.h"
+#include "smartcolsP.h"
+
+#ifdef HAVE_WIDECHAR
+#define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */
+#define UTF_VR "\342\224\234" /* U+251C, Vertical and right */
+#define UTF_H "\342\224\200" /* U+2500, Horizontal */
+#define UTF_UR "\342\224\224" /* U+2514, Up and right */
+#endif /* !HAVE_WIDECHAR */
+
+#define is_last_column(_tb, _cl) \
+ list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
+
+
+/**
+ * scols_new_table:
+ *
+ * Returns: A newly allocated table.
+ */
+struct libscols_table *scols_new_table(void)
+{
+ struct libscols_table *tb;
+
+ tb = calloc(1, sizeof(struct libscols_table));
+ if (!tb)
+ return NULL;
+
+ tb->refcount = 1;
+ tb->out = stdout;
+
+ INIT_LIST_HEAD(&tb->tb_lines);
+ INIT_LIST_HEAD(&tb->tb_columns);
+
+ DBG(TAB, ul_debugobj(tb, "alloc"));
+ return tb;
+}
+
+/**
+ * scols_ref_table:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Increases the refcount of @tb.
+ */
+void scols_ref_table(struct libscols_table *tb)
+{
+ if (tb)
+ tb->refcount++;
+}
+
+/**
+ * scols_unref_table:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Decreases the refcount of @tb. When the count falls to zero, the instance
+ * is automatically deallocated.
+ */
+void scols_unref_table(struct libscols_table *tb)
+{
+ if (tb && (--tb->refcount <= 0)) {
+ DBG(TAB, ul_debugobj(tb, "dealloc"));
+ scols_table_remove_lines(tb);
+ scols_table_remove_columns(tb);
+ scols_unref_symbols(tb->symbols);
+ free(tb->linesep);
+ free(tb->colsep);
+ free(tb);
+ }
+}
+
+/**
+ * scols_table_add_column:
+ * @tb: a pointer to a struct libscols_table instance
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Adds @cl to @tb's column list.
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl)
+{
+ assert(tb);
+ assert(cl);
+
+ if (!tb || !cl || !list_empty(&tb->tb_lines))
+ return -EINVAL;
+
+ if (cl->flags & SCOLS_FL_TREE)
+ tb->ntreecols++;
+
+ DBG(TAB, ul_debugobj(tb, "add column %p", cl));
+ list_add_tail(&cl->cl_columns, &tb->tb_columns);
+ cl->seqnum = tb->ncols++;
+ scols_ref_column(cl);
+
+ /* TODO:
+ *
+ * Currently it's possible to add/remove columns only if the table is
+ * empty (see list_empty(tb->tb_lines) above). It would be nice to
+ * enlarge/reduce lines cells[] always when we add/remove a new column.
+ */
+ return 0;
+}
+
+/**
+ * scols_table_remove_column:
+ * @tb: a pointer to a struct libscols_table instance
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Removes @cl from @tb.
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_remove_column(struct libscols_table *tb,
+ struct libscols_column *cl)
+{
+ assert(tb);
+ assert(cl);
+
+ if (!tb || !cl || !list_empty(&tb->tb_lines))
+ return -EINVAL;
+
+ if (cl->flags & SCOLS_FL_TREE)
+ tb->ntreecols--;
+
+ DBG(TAB, ul_debugobj(tb, "remove column %p", cl));
+ list_del_init(&cl->cl_columns);
+ tb->ncols--;
+ scols_unref_column(cl);
+ return 0;
+}
+
+/**
+ * scols_table_remove_columns:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Removes all of @tb's columns.
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_remove_columns(struct libscols_table *tb)
+{
+ assert(tb);
+
+ if (!tb || !list_empty(&tb->tb_lines))
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "remove all columns"));
+ while (!list_empty(&tb->tb_columns)) {
+ struct libscols_column *cl = list_entry(tb->tb_columns.next,
+ struct libscols_column, cl_columns);
+ scols_table_remove_column(tb, cl);
+ }
+ return 0;
+}
+
+
+/**
+ * scols_table_new_column:
+ * @tb: table
+ * @name: column header
+ * @whint: column width hint (absolute width: N > 1; relative width: N < 1)
+ * @flags: flags integer
+ *
+ * This is shortcut for
+ *
+ * cl = scols_new_column();
+ * scols_column_set_....(cl, ...);
+ * scols_table_add_column(tb, cl);
+ *
+ * The column width is possible to define by three ways:
+ *
+ * @whint = 0..1 : relative width, percent of terminal width
+ *
+ * @whint = 1..N : absolute width, empty colum will be truncated to
+ * the column header width
+ *
+ * @whint = 1..N
+ *
+ * The column is necessary to address by
+ * sequential number. The first defined column has the colnum = 0. For example:
+ *
+ * scols_table_new_column(tab, "FOO", 0.5, 0); // colnum = 0
+ * scols_table_new_column(tab, "BAR", 0.5, 0); // colnum = 1
+ * .
+ * .
+ * scols_line_get_cell(line, 0); // FOO column
+ * scols_line_get_cell(line, 1); // BAR column
+ *
+ * Returns: newly allocated column
+ */
+struct libscols_column *scols_table_new_column(struct libscols_table *tb,
+ const char *name,
+ double whint,
+ int flags)
+{
+ struct libscols_column *cl;
+ struct libscols_cell *hr;
+
+ assert (tb);
+ if (!tb)
+ return NULL;
+
+ DBG(TAB, ul_debugobj(tb, "new column name=%s, whint=%g, flags=%d",
+ name, whint, flags));
+ cl = scols_new_column();
+ if (!cl)
+ return NULL;
+
+ /* set column name */
+ hr = scols_column_get_header(cl);
+ if (!hr)
+ goto err;
+ if (scols_cell_set_data(hr, name))
+ goto err;
+
+ scols_column_set_whint(cl, whint);
+ scols_column_set_flags(cl, flags);
+
+ if (scols_table_add_column(tb, cl)) /* this increments column ref-counter */
+ goto err;
+
+ scols_unref_column(cl);
+ return cl;
+err:
+ scols_unref_column(cl);
+ return NULL;
+}
+
+/**
+ * scols_table_next_column:
+ * @tb: a pointer to a struct libscols_table instance
+ * @itr: a pointer to a struct libscols_iter instance
+ * @cl: a pointer to a pointer to a struct libscols_column instance
+ *
+ * Returns the next column of @tb via @cl.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_next_column(struct libscols_table *tb,
+ struct libscols_iter *itr,
+ struct libscols_column **cl)
+{
+ int rc = 1;
+
+ if (!tb || !itr || !cl)
+ return -EINVAL;
+ *cl = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &tb->tb_columns);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *cl, struct libscols_column, cl_columns);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+
+/**
+ * scols_table_get_ncols:
+ * @tb: table
+ *
+ * Returns: the ncols table member, a negative number in case of an error.
+ */
+int scols_table_get_ncols(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb ? tb->ncols : -EINVAL;
+}
+
+/**
+ * scols_table_get_nlines:
+ * @tb: table
+ *
+ * Returns: the nlines table member, a negative number in case of an error.
+ */
+int scols_table_get_nlines(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb ? tb->nlines : -EINVAL;
+}
+
+/**
+ * scols_table_set_stream:
+ * @tb: table
+ * @stream: output stream
+ *
+ * Sets the output stream for table @tb.
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_set_stream(struct libscols_table *tb, FILE *stream)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "setting alternative stream"));
+ tb->out = stream;
+ return 0;
+}
+
+/**
+ * scols_table_get_stream:
+ * @tb: table
+ *
+ * Gets the output stream for table @tb.
+ *
+ * Returns: stream pointer, NULL in case of an error or an unset stream.
+ */
+FILE *scols_table_get_stream(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb ? tb->out: NULL;
+}
+
+/**
+ * scols_table_reduce_termwidth:
+ * @tb: table
+ * @reduce: width
+ *
+ * Reduce the output width to @reduce.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "reduce terminal width: %zu", reduce));
+ tb->termreduce = reduce;
+ return 0;
+}
+
+/**
+ * scols_table_get_column:
+ * @tb: table
+ * @n: number of column (0..N)
+ *
+ * Returns: pointer to column or NULL
+ */
+struct libscols_column *scols_table_get_column(struct libscols_table *tb,
+ size_t n)
+{
+ struct libscols_iter itr;
+ struct libscols_column *cl;
+
+ assert(tb);
+ if (!tb)
+ return NULL;
+ if (n >= tb->ncols)
+ return NULL;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (cl->seqnum == n)
+ return cl;
+ }
+ return NULL;
+}
+
+/**
+ * scols_table_add_line:
+ * @tb: table
+ * @ln: line
+ *
+ * Note that this function calls scols_line_alloc_cells() if number
+ * of the cells in the line is too small for @tb.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
+{
+
+ assert(tb);
+ assert(ln);
+
+ if (!tb || !ln)
+ return -EINVAL;
+
+ if (tb->ncols > ln->ncells) {
+ int rc = scols_line_alloc_cells(ln, tb->ncols);
+ if (rc)
+ return rc;
+ }
+
+ DBG(TAB, ul_debugobj(tb, "add line %p", ln));
+ list_add_tail(&ln->ln_lines, &tb->tb_lines);
+ ln->seqnum = tb->nlines++;
+ scols_ref_line(ln);
+ return 0;
+}
+
+/**
+ * scols_table_remove_line:
+ * @tb: table
+ * @ln: line
+ *
+ * Note that this function does not destroy the parent<->child relationship between lines.
+ * You have to call scols_line_remove_child()
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_remove_line(struct libscols_table *tb,
+ struct libscols_line *ln)
+{
+ assert(tb);
+ assert(ln);
+
+ if (!tb || !ln)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "remove line %p", ln));
+ list_del_init(&ln->ln_lines);
+ tb->nlines--;
+ scols_unref_line(ln);
+ return 0;
+}
+
+/**
+ * scols_table_remove_lines:
+ * @tb: table
+ *
+ * This empties the table and also destroys all the parent<->child relationships.
+ */
+void scols_table_remove_lines(struct libscols_table *tb)
+{
+ assert(tb);
+ if (!tb)
+ return;
+
+ DBG(TAB, ul_debugobj(tb, "remove all lines"));
+ while (!list_empty(&tb->tb_lines)) {
+ struct libscols_line *ln = list_entry(tb->tb_lines.next,
+ struct libscols_line, ln_lines);
+ if (ln->parent)
+ scols_line_remove_child(ln->parent, ln);
+ scols_table_remove_line(tb, ln);
+ }
+}
+
+/**
+ * scols_table_next_line:
+ * @tb: a pointer to a struct libscols_table instance
+ * @itr: a pointer to a struct libscols_iter instance
+ * @ln: a pointer to a pointer to a struct libscols_line instance
+ *
+ * Finds the next line and returns a pointer to it via @ln.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_next_line(struct libscols_table *tb,
+ struct libscols_iter *itr,
+ struct libscols_line **ln)
+{
+ int rc = 1;
+
+ if (!tb || !itr || !ln)
+ return -EINVAL;
+ *ln = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &tb->tb_lines);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *ln, struct libscols_line, ln_lines);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * scols_table_new_line:
+ * @tb: table
+ * @parent: parental line or NULL
+ *
+ * This is shortcut for
+ *
+ * ln = scols_new_line();
+ * scols_table_add_line(tb, ln);
+ * scols_line_add_child(parent, ln);
+ *
+ *
+ * Returns: newly allocate line
+ */
+struct libscols_line *scols_table_new_line(struct libscols_table *tb,
+ struct libscols_line *parent)
+{
+ struct libscols_line *ln;
+
+ assert(tb);
+ assert(tb->ncols);
+
+ if (!tb || !tb->ncols)
+ return NULL;
+
+ ln = scols_new_line();
+ if (!ln)
+ return NULL;
+
+ if (scols_table_add_line(tb, ln))
+ goto err;
+ if (parent)
+ scols_line_add_child(parent, ln);
+
+ scols_unref_line(ln); /* ref-counter incremented by scols_table_add_line() */
+ return ln;
+err:
+ scols_unref_line(ln);
+ return NULL;
+}
+
+/**
+ * scols_table_get_line:
+ * @tb: table
+ * @n: column number (0..N)
+ *
+ * This is a shortcut for
+ *
+ * ln = scols_new_line();
+ * scols_line_set_....(cl, ...);
+ * scols_table_add_line(tb, ln);
+ *
+ * Returns: a newly allocate line
+ */
+struct libscols_line *scols_table_get_line(struct libscols_table *tb,
+ size_t n)
+{
+ struct libscols_iter itr;
+ struct libscols_line *ln;
+
+ assert(tb);
+ if (!tb)
+ return NULL;
+ if (n >= tb->nlines)
+ return NULL;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ if (ln->seqnum == n)
+ return ln;
+ }
+ return NULL;
+}
+
+/**
+ * scols_copy_table:
+ * @tb: table
+ *
+ * Creates a new independent table copy, except struct libscols_symbols that
+ * are shared between the tables.
+ *
+ * Returns: a newly allocated copy of @tb
+ */
+struct libscols_table *scols_copy_table(struct libscols_table *tb)
+{
+ struct libscols_table *ret;
+ struct libscols_line *ln;
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+
+ assert(tb);
+ if (!tb)
+ return NULL;
+ ret = scols_new_table();
+ if (!ret)
+ return NULL;
+
+ DBG(TAB, ul_debugobj(tb, "copy into %p", ret));
+
+ if (tb->symbols)
+ scols_table_set_symbols(ret, tb->symbols);
+
+ /* columns */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ cl = scols_copy_column(cl);
+ if (!cl)
+ goto err;
+ if (scols_table_add_column(ret, cl))
+ goto err;
+ scols_unref_column(cl);
+ }
+
+ /* lines */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ struct libscols_line *newln = scols_copy_line(ln);
+ if (!newln)
+ goto err;
+ if (scols_table_add_line(ret, newln))
+ goto err;
+ if (ln->parent) {
+ struct libscols_line *p =
+ scols_table_get_line(ret, ln->parent->seqnum);
+ if (p)
+ scols_line_add_child(p, newln);
+ }
+ scols_unref_line(newln);
+ }
+
+ /* separators */
+ if (scols_table_set_column_separator(ret, tb->colsep) ||
+ scols_table_set_line_separator(ret, tb->linesep))
+ goto err;
+
+ return ret;
+err:
+ scols_unref_table(ret);
+ return NULL;
+}
+
+/**
+ * scols_table_set_symbols:
+ * @tb: table
+ * @sy: symbols or NULL
+ *
+ * Add a reference to @sy from the table. The symbols are used by library to
+ * draw tree output. If no symbols are specified then library checks the
+ * current environment to select ASCII or UTF8 symbols. This default behavior
+ * could be controlled by scols_table_enable_ascii().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_set_symbols(struct libscols_table *tb,
+ struct libscols_symbols *sy)
+{
+ assert(tb);
+
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "setting alternative symbols %p", sy));
+
+ if (tb->symbols) /* unref old */
+ scols_unref_symbols(tb->symbols);
+ if (sy) { /* ref user defined */
+ tb->symbols = sy;
+ scols_ref_symbols(sy);
+ } else { /* default symbols */
+ tb->symbols = scols_new_symbols();
+ if (!tb->symbols)
+ return -ENOMEM;
+#if defined(HAVE_WIDECHAR)
+ if (!scols_table_is_ascii(tb) &&
+ !strcmp(nl_langinfo(CODESET), "UTF-8")) {
+ scols_symbols_set_branch(tb->symbols, UTF_VR UTF_H);
+ scols_symbols_set_vertical(tb->symbols, UTF_V " ");
+ scols_symbols_set_right(tb->symbols, UTF_UR UTF_H);
+ } else
+#endif
+ {
+ scols_symbols_set_branch(tb->symbols, "|-");
+ scols_symbols_set_vertical(tb->symbols, "| ");
+ scols_symbols_set_right(tb->symbols, "`-");
+ }
+ }
+
+ return 0;
+}
+/**
+ * scols_table_enable_colors:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable colors.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_colors(struct libscols_table *tb, int enable)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "colors: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->colors_wanted = enable;
+ return 0;
+}
+/**
+ * scols_table_enable_raw:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable raw output format. The parsable output formats
+ * (export and raw) are mutually exclusive.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_raw(struct libscols_table *tb, int enable)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "raw: %s", enable ? "ENABLE" : "DISABLE"));
+ if (enable)
+ tb->format = SCOLS_FMT_RAW;
+ else if (tb->format == SCOLS_FMT_RAW)
+ tb->format = 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_export:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable export output format (COLUMNAME="value" ...).
+ * The parsable output formats (export and raw) are mutually exclusive.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_export(struct libscols_table *tb, int enable)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "export: %s", enable ? "ENABLE" : "DISABLE"));
+ if (enable)
+ tb->format = SCOLS_FMT_EXPORT;
+ else if (tb->format == SCOLS_FMT_EXPORT)
+ tb->format = 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_ascii:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * The ASCII-only output is relevant for tree-like outputs. The library
+ * checks if the current environment is UTF8 compatible by default. This
+ * function overrides this check and force the library to use ASCII chars
+ * for the tree.
+ *
+ * If a custom libcols_symbols are specified (see scols_table_set_symbols()
+ * then ASCII flag setting is ignored.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_ascii(struct libscols_table *tb, int enable)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "ascii: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->ascii = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_noheadings:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable header line.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ DBG(TAB, ul_debugobj(tb, "noheading: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->no_headings = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_maxout:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * The extra space after last column is ignored by default. The output
+ * maximization use the extra space for all columns.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_maxout(struct libscols_table *tb, int enable)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ DBG(TAB, ul_debugobj(tb, "maxout: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->maxout = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_colors_wanted:
+ * @tb: table
+ *
+ * Returns: 1 if colors are enabled.
+ */
+int scols_table_colors_wanted(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb && tb->colors_wanted;
+}
+
+/**
+ * scols_table_is_empty:
+ * @tb: table
+ *
+ * Returns: 1 if the table is empty.
+ */
+int scols_table_is_empty(struct libscols_table *tb)
+{
+ assert(tb);
+ return !tb || !tb->nlines;
+}
+
+/**
+ * scols_table_is_ascii:
+ * @tb: table
+ *
+ * Returns: 1 if ASCII tree is enabled.
+ */
+int scols_table_is_ascii(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb && tb->ascii;
+}
+
+/**
+ * scols_table_is_noheadings:
+ * @tb: table
+ *
+ * Returns: 1 if header output is disabled.
+ */
+int scols_table_is_noheadings(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb && tb->no_headings;
+}
+
+/**
+ * scols_table_is_export:
+ * @tb: table
+ *
+ * Returns: 1 if export output format is enabled.
+ */
+int scols_table_is_export(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb && tb->format == SCOLS_FMT_EXPORT;
+}
+
+/**
+ * scols_table_is_raw:
+ * @tb: table
+ *
+ * Returns: 1 if raw output format is enabled.
+ */
+int scols_table_is_raw(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb && tb->format == SCOLS_FMT_RAW;
+}
+
+
+/**
+ * scols_table_is_maxout
+ * @tb: table
+ *
+ * Returns: 1 if output maximization is enabled, negative value in case of an error.
+ */
+int scols_table_is_maxout(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb && tb->maxout;
+}
+
+/**
+ * scols_table_is_tree:
+ * @tb: table
+ *
+ * Returns: returns 1 tree-like output is expected.
+ */
+int scols_table_is_tree(struct libscols_table *tb)
+{
+ assert(tb);
+ return tb && tb->ntreecols > 0;
+}
+
+/**
+ * scols_table_set_column_separator:
+ * @tb: table
+ * @sep: separator
+ *
+ * Sets the column separator of @tb to @sep.
+ * Please note that @sep should always take up a single cell in the output.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_set_column_separator(struct libscols_table *tb, const char *sep)
+{
+ char *p = NULL;
+
+ assert (tb);
+
+ if (!tb)
+ return -EINVAL;
+
+ if (sep) {
+ p = strdup(sep);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ DBG(TAB, ul_debugobj(tb, "new columns separator: %s", sep));
+ free(tb->colsep);
+ tb->colsep = p;
+ return 0;
+}
+
+/**
+ * scols_table_set_line_separator:
+ * @tb: table
+ * @sep: separator
+ *
+ * Sets the line separator of @tb to @sep.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_set_line_separator(struct libscols_table *tb, const char *sep)
+{
+ char *p = NULL;
+
+ assert (tb);
+
+ if (!tb)
+ return -EINVAL;
+
+ if (sep) {
+ p = strdup(sep);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ DBG(TAB, ul_debugobj(tb, "new lines separator: %s", sep));
+ free(tb->linesep);
+ tb->linesep = p;
+ return 0;
+}
+
+/**
+ * scols_table_get_column_separator:
+ * @tb: table
+ *
+ * Returns: @tb column separator, NULL in case of an error
+ */
+char *scols_table_get_column_separator(struct libscols_table *tb)
+{
+ assert (tb);
+
+ if (!tb)
+ return NULL;
+ return tb->colsep;
+}
+
+/**
+ * scols_table_get_line_separator:
+ * @tb: table
+ *
+ * Returns: @tb line separator, NULL in case of an error
+ */
+char *scols_table_get_line_separator(struct libscols_table *tb)
+{
+ assert (tb);
+
+ if (!tb)
+ return NULL;
+ return tb->linesep;
+
+}
+
+static int cells_cmp_wrapper(struct list_head *a, struct list_head *b, void *data)
+{
+ struct libscols_column *cl = (struct libscols_column *) data;
+ struct libscols_line *ra, *rb;
+ struct libscols_cell *ca, *cb;
+
+ assert(a);
+ assert(b);
+ assert(cl);
+
+ ra = list_entry(a, struct libscols_line, ln_lines);
+ rb = list_entry(b, struct libscols_line, ln_lines);
+ ca = scols_line_get_cell(ra, cl->seqnum);
+ cb = scols_line_get_cell(rb, cl->seqnum);
+
+ return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
+}
+
+/**
+ * scols_sort_table:
+ * @tb: table
+ * @cl: order by this column
+ *
+ * Orders the table by the column. See also scols_column_set_cmpfunc().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl)
+{
+ assert(tb);
+ assert(cl);
+
+ if (!tb || !cl)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "sorting table"));
+ list_sort(&tb->tb_lines, cells_cmp_wrapper, cl);
+ return 0;
+}
diff -up util-linux-2.23.2/libsmartcols/src/table_print.c.kzak util-linux-2.23.2/libsmartcols/src/table_print.c
--- util-linux-2.23.2/libsmartcols/src/table_print.c.kzak 2014-09-25 14:41:48.992843944 +0200
+++ util-linux-2.23.2/libsmartcols/src/table_print.c 2014-09-25 14:41:48.992843944 +0200
@@ -0,0 +1,841 @@
+/*
+ * table.c - functions handling the data at the table level
+ *
+ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: table_print
+ * @title: Table print
+ * @short_description: table print API
+ *
+ * Table output API.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <ctype.h>
+
+#include "nls.h"
+#include "mbsalign.h"
+#include "widechar.h"
+#include "ttyutils.h"
+#include "carefulputc.h"
+#include "smartcolsP.h"
+
+/* This is private struct to work with output data */
+struct libscols_buffer {
+ char *begin; /* begin of the buffer */
+ char *cur; /* current end of the buffer */
+ char *encdata; /* encoded buffer mbs_safe_encode() */
+
+ size_t bufsz; /* size of the buffer */
+ size_t art_idx; /* begin of the tree ascii art or zero */
+};
+
+static struct libscols_buffer *new_buffer(size_t sz)
+{
+ struct libscols_buffer *buf = malloc(sz + sizeof(struct libscols_buffer));
+
+ if (!buf)
+ return NULL;
+
+ buf->cur = buf->begin = ((char *) buf) + sizeof(struct libscols_buffer);
+ buf->encdata = NULL;
+ buf->bufsz = sz;
+
+ DBG(BUFF, ul_debugobj(buf, "alloc (size=%zu)", sz));
+ return buf;
+}
+
+static void free_buffer(struct libscols_buffer *buf)
+{
+ if (!buf)
+ return;
+ DBG(BUFF, ul_debugobj(buf, "dealloc"));
+ free(buf->encdata);
+ free(buf);
+}
+
+static int buffer_reset_data(struct libscols_buffer *buf)
+{
+ if (!buf)
+ return -EINVAL;
+
+ /*DBG(BUFF, ul_debugobj(buf, "reset data"));*/
+ buf->begin[0] = '\0';
+ buf->cur = buf->begin;
+ buf->art_idx = 0;
+ return 0;
+}
+
+static int buffer_append_data(struct libscols_buffer *buf, const char *str)
+{
+ size_t maxsz, sz;
+
+ if (!buf)
+ return -EINVAL;
+ if (!str || !*str)
+ return 0;
+
+ sz = strlen(str);
+ maxsz = buf->bufsz - (buf->cur - buf->begin);
+
+ if (maxsz <= sz)
+ return -EINVAL;
+
+ memcpy(buf->cur, str, sz + 1);
+ buf->cur += sz;
+ return 0;
+}
+
+static int buffer_set_data(struct libscols_buffer *buf, const char *str)
+{
+ int rc = buffer_reset_data(buf);
+ return rc ? rc : buffer_append_data(buf, str);
+}
+
+/* save the current buffer possition to art_idx */
+static void buffer_set_art_index(struct libscols_buffer *buf)
+{
+ if (buf) {
+ buf->art_idx = buf->cur - buf->begin;
+ /*DBG(BUFF, ul_debugobj(buf, "art index: %zu", buf->art_idx));*/
+ }
+}
+
+static char *buffer_get_data(struct libscols_buffer *buf)
+{
+ return buf ? buf->begin : NULL;
+}
+
+/* encode data by mbs_safe_encode() to avoid control and non-printable chars */
+static char *buffer_get_safe_data(struct libscols_buffer *buf, size_t *cells)
+{
+ char *data = buffer_get_data(buf);
+ char *res = NULL;
+
+ if (!data)
+ goto nothing;
+
+ if (!buf->encdata) {
+ buf->encdata = malloc(mbs_safe_encode_size(buf->bufsz) + 1);
+ if (!buf->encdata)
+ goto nothing;
+ }
+
+ res = mbs_safe_encode_to_buffer(data, cells, buf->encdata);
+ if (!res || !*cells || *cells == (size_t) -1)
+ goto nothing;
+ return res;
+nothing:
+ *cells = 0;
+ return NULL;
+}
+
+/* returns size in bytes of the ascii art (according to art_idx) in safe encoding */
+static size_t buffer_get_safe_art_size(struct libscols_buffer *buf)
+{
+ char *data = buffer_get_data(buf);
+ size_t bytes = 0;
+
+ if (!data || !buf->art_idx)
+ return 0;
+
+ mbs_safe_nwidth(data, buf->art_idx, &bytes);
+ return bytes;
+}
+
+#define is_last_column(_tb, _cl) \
+ list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
+
+#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ")
+#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n")
+
+static int print_data(struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_line *ln, /* optional */
+ struct libscols_cell *ce, /* optional */
+ struct libscols_buffer *buf)
+{
+ size_t len = 0, i, width, bytes;
+ const char *color = NULL;
+ char *data;
+
+ assert(tb);
+ assert(cl);
+
+ DBG(TAB, ul_debugobj(tb,
+ " -> data, column=%p, line=%p, cell=%p, buff=%p",
+ cl, ln, ce, buf));
+
+ data = buffer_get_data(buf);
+ if (!data)
+ data = "";
+
+ /* raw mode */
+ if (scols_table_is_raw(tb)) {
+ fputs_nonblank(data, tb->out);
+ if (!is_last_column(tb, cl))
+ fputs(colsep(tb), tb->out);
+ return 0;
+ }
+
+ /* NAME=value mode */
+ if (scols_table_is_export(tb)) {
+ fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header));
+ fputs_quoted(data, tb->out);
+ if (!is_last_column(tb, cl))
+ fputs(colsep(tb), tb->out);
+ return 0;
+ }
+
+ if (tb->colors_wanted) {
+ if (ce && !color)
+ color = ce->color;
+ if (ln && !color)
+ color = ln->color;
+ if (!color)
+ color = cl->color;
+ }
+
+ /* encode, note that 'len' and 'width' are number of cells, not bytes */
+ data = buffer_get_safe_data(buf, &len);
+ if (!data)
+ data = "";
+ width = cl->width;
+ bytes = strlen(data);
+
+ if (is_last_column(tb, cl) && len < width && !scols_table_is_maxout(tb))
+ width = len;
+
+ /* truncate data */
+ if (len > width && scols_column_is_trunc(cl)) {
+ len = width;
+ bytes = mbs_truncate(data, &len); /* updates 'len' */
+
+ if (!data || bytes == (size_t) -1) {
+ bytes = len = 0;
+ data = NULL;
+ }
+ }
+
+ if (data) {
+ if (scols_column_is_right(cl)) {
+ size_t xw = cl->width;
+ if (color)
+ fputs(color, tb->out);
+ fprintf(tb->out, "%*s", (int) xw, data);
+ if (color)
+ fputs(UL_COLOR_RESET, tb->out);
+ if (len < xw)
+ len = xw;
+ } else if (color) {
+ char *p = data;
+ size_t art = buffer_get_safe_art_size(buf);
+
+ /* we don't want to colorize tree ascii art */
+ if (scols_column_is_tree(cl) && art && art < bytes) {
+ fwrite(p, 1, art, tb->out);
+ p += art;
+ }
+
+ fputs(color, tb->out);
+ fputs(p, tb->out);
+ fputs(UL_COLOR_RESET, tb->out);
+ } else
+ fputs(data, tb->out);
+ }
+ for (i = len; i < width; i++)
+ fputs(" ", tb->out); /* padding */
+
+ if (!is_last_column(tb, cl)) {
+ if (len > width && !scols_column_is_trunc(cl)) {
+ fputs(linesep(tb), tb->out);
+ for (i = 0; i <= (size_t) cl->seqnum; i++) {
+ struct libscols_column *x = scols_table_get_column(tb, i);
+ fprintf(tb->out, "%*s ", -((int)x->width), " ");
+ }
+ } else
+ fputs(colsep(tb), tb->out); /* columns separator */
+ }
+
+ return 0;
+}
+
+/* returns pointer to the end of used data */
+static int line_ascii_art_to_buffer(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_buffer *buf)
+{
+ const char *art;
+ int rc;
+
+ assert(ln);
+ assert(buf);
+
+ if (!ln->parent)
+ return 0;
+
+ rc = line_ascii_art_to_buffer(tb, ln->parent, buf);
+ if (rc)
+ return rc;
+
+ if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
+ art = " ";
+ else
+ art = tb->symbols->vert;
+
+ return buffer_append_data(buf, art);
+}
+
+static int cell_to_buffer(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_column *cl,
+ struct libscols_buffer *buf)
+{
+ const char *data;
+ struct libscols_cell *ce;
+ int rc = 0;
+
+ assert(tb);
+ assert(ln);
+ assert(cl);
+ assert(buf);
+ assert(cl->seqnum <= tb->ncols);
+
+ buffer_reset_data(buf);
+
+ ce = scols_line_get_cell(ln, cl->seqnum);
+ data = ce ? scols_cell_get_data(ce) : NULL;
+ if (!data)
+ return 0;
+
+ if (!scols_column_is_tree(cl))
+ return buffer_set_data(buf, data);
+
+ /*
+ * Tree stuff
+ */
+ if (ln->parent) {
+ rc = line_ascii_art_to_buffer(tb, ln->parent, buf);
+
+ if (!rc && list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch))
+ rc = buffer_append_data(buf, tb->symbols->right);
+ else if (!rc)
+ rc = buffer_append_data(buf, tb->symbols->branch);
+ if (!rc)
+ buffer_set_art_index(buf);
+ }
+
+ if (!rc)
+ rc = buffer_append_data(buf, data);
+ return rc;
+}
+
+/*
+ * Prints data, data maybe be printed in more formats (raw, NAME=xxx pairs) and
+ * control and non-printable chars maybe encoded in \x?? hex encoding.
+ */
+static int print_line(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_buffer *buf)
+{
+ int rc = 0;
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+
+ assert(ln);
+
+ DBG(TAB, ul_debugobj(tb, "printing line, line=%p, buff=%p", ln, buf));
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
+ rc = cell_to_buffer(tb, ln, cl, buf);
+ if (!rc)
+ rc = print_data(tb, cl, ln,
+ scols_line_get_cell(ln, cl->seqnum),
+ buf);
+ }
+
+ if (rc == 0)
+ fputs(linesep(tb), tb->out);
+ return 0;
+}
+
+static int print_header(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ int rc = 0;
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+
+ assert(tb);
+
+ if (scols_table_is_noheadings(tb) ||
+ scols_table_is_export(tb) ||
+ list_empty(&tb->tb_lines))
+ return 0;
+
+ DBG(TAB, ul_debugobj(tb, "printing header"));
+
+ /* set width according to the size of data
+ */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
+ rc = buffer_set_data(buf, scols_cell_get_data(&cl->header));
+ if (!rc)
+ rc = print_data(tb, cl, NULL, &cl->header, buf);
+ }
+
+ if (rc == 0)
+ fputs(linesep(tb), tb->out);
+ return rc;
+}
+
+static int print_table(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ int rc;
+ struct libscols_line *ln;
+ struct libscols_iter itr;
+
+ assert(tb);
+
+ rc = print_header(tb, buf);
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0)
+ rc = print_line(tb, ln, buf);
+
+ return rc;
+}
+
+static int print_tree_line(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_buffer *buf)
+{
+ int rc;
+ struct list_head *p;
+
+ rc = print_line(tb, ln, buf);
+ if (rc)
+ return rc;
+ if (list_empty(&ln->ln_branch))
+ return 0;
+
+ /* print all children */
+ list_for_each(p, &ln->ln_branch) {
+ struct libscols_line *chld =
+ list_entry(p, struct libscols_line, ln_children);
+ rc = print_tree_line(tb, chld, buf);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ int rc;
+ struct libscols_line *ln;
+ struct libscols_iter itr;
+
+ assert(tb);
+
+ DBG(TAB, ul_debugobj(tb, "printing tree"));
+
+ rc = print_header(tb, buf);
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) {
+ if (ln->parent)
+ continue;
+ rc = print_tree_line(tb, ln, buf);
+ }
+
+ return rc;
+}
+
+static void dbg_column(struct libscols_table *tb, struct libscols_column *cl)
+{
+ DBG(COL, ul_debugobj(cl, "%15s seq=%zu, width=%zd, "
+ "hint=%d, avg=%zu, max=%zu, min=%zu, "
+ "extreme=%s",
+
+ cl->header.data, cl->seqnum, cl->width,
+ cl->width_hint > 1 ? (int) cl->width_hint :
+ (int) (cl->width_hint * tb->termwidth),
+ cl->width_avg,
+ cl->width_max,
+ cl->width_min,
+ cl->is_extreme ? "yes" : "not"));
+}
+
+static void dbg_columns(struct libscols_table *tb)
+{
+ struct libscols_iter itr;
+ struct libscols_column *cl;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0)
+ dbg_column(tb, cl);
+}
+
+/*
+ * This function counts column width.
+ *
+ * For the SCOLS_FL_NOEXTREMES columns is possible to call this function two
+ * times. The first pass counts width and average width. If the column
+ * contains too large fields (width greater than 2 * average) then the column
+ * is marked as "extreme". In the second pass all extreme fields are ignored
+ * and column width is counted from non-extreme fields only.
+ */
+static int count_column_width(struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_buffer *buf)
+{
+ struct libscols_line *ln;
+ struct libscols_iter itr;
+ int count = 0, rc = 0;
+ size_t sum = 0;
+
+ assert(tb);
+ assert(cl);
+
+ cl->width = 0;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ size_t len;
+ char *data;
+
+ rc = cell_to_buffer(tb, ln, cl, buf);
+ if (rc)
+ return rc;
+
+ data = buffer_get_data(buf);
+ len = data ? mbs_safe_width(data) : 0;
+
+ if (len == (size_t) -1) /* ignore broken multibyte strings */
+ len = 0;
+ if (len > cl->width_max)
+ cl->width_max = len;
+
+ if (cl->is_extreme && len > cl->width_avg * 2)
+ continue;
+ else if (scols_column_is_noextremes(cl)) {
+ sum += len;
+ count++;
+ }
+ if (len > cl->width)
+ cl->width = len;
+ }
+
+ if (count && cl->width_avg == 0) {
+ cl->width_avg = sum / count;
+
+ if (cl->width_max > cl->width_avg * 2)
+ cl->is_extreme = 1;
+ }
+
+ /* check and set minimal column width */
+ if (scols_cell_get_data(&cl->header))
+ cl->width_min = mbs_safe_width(scols_cell_get_data(&cl->header));
+
+ /* enlarge to minimal width */
+ if (cl->width < cl->width_min && !scols_column_is_strict_width(cl))
+ cl->width = cl->width_min;
+
+ /* use relative size for large columns */
+ else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint
+ && cl->width_min < (size_t) cl->width_hint)
+
+ cl->width = (size_t) cl->width_hint;
+
+ ON_DBG(COL, dbg_column(tb, cl));
+ return rc;
+}
+
+
+/*
+ * This is core of the scols_* voodo...
+ */
+static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+ size_t width = 0; /* output width */
+ int trunc_only, rc = 0;
+ int extremes = 0;
+
+
+ DBG(TAB, ul_debugobj(tb, "recounting widths (termwidth=%zu)", tb->termwidth));
+
+ /* set basic columns width
+ */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ rc = count_column_width(tb, cl, buf);
+ if (rc)
+ return rc;
+
+ width += cl->width + (is_last_column(tb, cl) ? 0 : 1);
+ extremes += cl->is_extreme;
+ }
+
+ if (!tb->is_term)
+ return 0;
+
+ /* reduce columns with extreme fields
+ */
+ if (width > tb->termwidth && extremes) {
+ DBG(TAB, ul_debugobj(tb, " reduce width (extreme columns)"));
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ size_t org_width;
+
+ if (!cl->is_extreme)
+ continue;
+
+ org_width = cl->width;
+ rc = count_column_width(tb, cl, buf);
+ if (rc)
+ return rc;
+
+ if (org_width > cl->width)
+ width -= org_width - cl->width;
+ else
+ extremes--; /* hmm... nothing reduced */
+ }
+ }
+
+ if (width < tb->termwidth) {
+ if (extremes) {
+ DBG(TAB, ul_debugobj(tb, " enlarge width (extreme columns)"));
+
+ /* enlarge the first extreme column */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ size_t add;
+
+ if (!cl->is_extreme)
+ continue;
+
+ /* this column is tooo large, ignore?
+ if (cl->width_max - cl->width >
+ (tb->termwidth - width))
+ continue;
+ */
+
+ add = tb->termwidth - width;
+ if (add && cl->width + add > cl->width_max)
+ add = cl->width_max - cl->width;
+
+ cl->width += add;
+ width += add;
+
+ if (width == tb->termwidth)
+ break;
+ }
+ }
+
+ if (width < tb->termwidth && scols_table_is_maxout(tb)) {
+ DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)"));
+
+ /* try enlarge all columns */
+ while (width < tb->termwidth) {
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ cl->width++;
+ width++;
+ if (width == tb->termwidth)
+ break;
+ }
+ }
+ } else if (width < tb->termwidth) {
+ /* enlarge the last column */
+ struct libscols_column *cl = list_entry(
+ tb->tb_columns.prev, struct libscols_column, cl_columns);
+
+ DBG(TAB, ul_debugobj(tb, " enlarge width (last column)"));
+
+ if (!scols_column_is_right(cl) && tb->termwidth - width > 0) {
+ cl->width += tb->termwidth - width;
+ width = tb->termwidth;
+ }
+ }
+ }
+
+ /* bad, we have to reduce output width, this is done in two steps:
+ * 1/ reduce columns with a relative width and with truncate flag
+ * 2) reduce columns with a relative width without truncate flag
+ */
+ trunc_only = 1;
+ while (width > tb->termwidth) {
+ size_t org = width;
+
+ DBG(TAB, ul_debugobj(tb, " reduce width (current=%zu, "
+ "wanted=%zu, mode=%s)",
+ width, tb->termwidth,
+ trunc_only ? "trunc-only" : "all-relative"));
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (width <= tb->termwidth)
+ break;
+ if (cl->width_hint > 1 && !scols_column_is_trunc(cl))
+ continue; /* never truncate columns with absolute sizes */
+ if (scols_column_is_tree(cl))
+ continue; /* never truncate the tree */
+ if (trunc_only && !scols_column_is_trunc(cl))
+ continue;
+ if (cl->width == cl->width_min)
+ continue;
+
+ /* truncate column with relative sizes */
+ if (cl->width_hint < 1 && cl->width > 0 && width > 0 &&
+ cl->width > cl->width_hint * tb->termwidth) {
+ cl->width--;
+ width--;
+ }
+ /* truncate column with absolute size */
+ if (cl->width_hint > 1 && cl->width > 0 && width > 0 &&
+ !trunc_only) {
+ cl->width--;
+ width--;
+ }
+
+ }
+ if (org == width) {
+ if (trunc_only)
+ trunc_only = 0;
+ else
+ break;
+ }
+ }
+
+ DBG(TAB, ul_debugobj(tb, " result: %zu", width));
+ ON_DBG(TAB, dbg_columns(tb));
+
+ return rc;
+}
+
+static size_t strlen_line(struct libscols_line *ln)
+{
+ size_t i, sz = 0;
+
+ assert(ln);
+
+ for (i = 0; i < ln->ncells; i++) {
+ struct libscols_cell *ce = scols_line_get_cell(ln, i);
+ const char *data = ce ? scols_cell_get_data(ce) : NULL;
+
+ sz += data ? strlen(data) : 0;
+ }
+
+ return sz;
+}
+
+
+
+/**
+ * scols_print_table:
+ * @tb: table
+ *
+ * Prints the table to the output stream.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_print_table(struct libscols_table *tb)
+{
+ int rc = 0;
+ size_t bufsz;
+ struct libscols_line *ln;
+ struct libscols_iter itr;
+ struct libscols_buffer *buf;
+
+ assert(tb);
+ if (!tb)
+ return -1;
+
+ DBG(TAB, ul_debugobj(tb, "printing"));
+ if (!tb->symbols)
+ scols_table_set_symbols(tb, NULL); /* use default */
+
+ tb->is_term = isatty(STDOUT_FILENO) ? 1 : 0;
+ tb->termwidth = tb->is_term ? get_terminal_width() : 0;
+ if (tb->termwidth <= 0)
+ tb->termwidth = 80;
+ tb->termwidth -= tb->termreduce;
+
+ bufsz = tb->termwidth;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ size_t sz = strlen_line(ln);
+ if (sz > bufsz)
+ bufsz = sz;
+ }
+
+ buf = new_buffer(bufsz + 1); /* data + space for \0 */
+ if (!buf)
+ return -ENOMEM;
+
+ if (!(scols_table_is_raw(tb) || scols_table_is_export(tb))) {
+ rc = recount_widths(tb, buf);
+ if (rc != 0)
+ goto done;
+ }
+
+ if (scols_table_is_tree(tb))
+ rc = print_tree(tb, buf);
+ else
+ rc = print_table(tb, buf);
+
+done:
+ free_buffer(buf);
+ return rc;
+}
+
+/**
+ * scols_print_table_to_string:
+ * @tb: table
+ * @data: pointer to the beginning of a memory area to print to
+ *
+ * Prints the table to @data.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_print_table_to_string(struct libscols_table *tb, char **data)
+{
+#ifdef HAVE_OPEN_MEMSTREAM
+ FILE *stream;
+ size_t sz;
+ int rc;
+
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "printing to string"));
+
+ /* create a stream for output */
+ stream = open_memstream(data, &sz);
+ if (!stream)
+ return -ENOMEM;
+
+ scols_table_set_stream(tb, stream);
+ rc = scols_print_table(tb);
+ fclose(stream);
+
+ return rc;
+#else
+ return -ENOSYS;
+#endif
+}
+
diff -up util-linux-2.23.2/libsmartcols/src/test.c.kzak util-linux-2.23.2/libsmartcols/src/test.c
--- util-linux-2.23.2/libsmartcols/src/test.c.kzak 2014-09-25 14:41:48.993843953 +0200
+++ util-linux-2.23.2/libsmartcols/src/test.c 2014-09-25 14:41:48.993843953 +0200
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <getopt.h>
+
+#include "c.h"
+#include "nls.h"
+#include "strutils.h"
+
+#include "libsmartcols.h"
+
+static int add_children(struct libscols_table *tb,
+ struct libscols_line *ln, int fd);
+
+
+enum { COL_MODE, COL_SIZE, COL_NAME };
+
+/* add columns to the @tb */
+static void setup_columns(struct libscols_table *tb, int notree)
+{
+ if (!scols_table_new_column(tb, "MODE", 0.3, 0))
+ goto fail;
+ if (!scols_table_new_column(tb, "SIZE", 5, SCOLS_FL_RIGHT))
+ goto fail;
+ if (!scols_table_new_column(tb, "NAME", 0.5,
+ (notree ? 0 : SCOLS_FL_TREE) | SCOLS_FL_NOEXTREMES))
+ goto fail;
+
+ return;
+fail:
+ scols_unref_table(tb);
+ err(EXIT_FAILURE, "faild to create output columns");
+}
+
+/* add a new line to @tb, the content is based on @st */
+static int add_line_from_stat(struct libscols_table *tb,
+ struct libscols_line *parent,
+ int parent_fd,
+ struct stat *st,
+ const char *name)
+{
+ struct libscols_line *ln;
+ char modbuf[11], *p;
+ mode_t mode = st->st_mode;
+ int rc = 0;
+
+ ln = scols_table_new_line(tb, parent);
+ if (!ln)
+ err(EXIT_FAILURE, "failed to create output line");
+
+ /* MODE; local buffer, use scols_line_set_data() that calls strdup() */
+ strmode(mode, modbuf);
+ if (scols_line_set_data(ln, COL_MODE, modbuf))
+ goto fail;
+
+ /* SIZE; already allocated string, use scols_line_refer_data() */
+ p = size_to_human_string(0, st->st_size);
+ if (!p || scols_line_refer_data(ln, COL_SIZE, p))
+ goto fail;
+
+ /* NAME */
+ if (scols_line_set_data(ln, COL_NAME, name))
+ goto fail;
+
+ /* colors */
+ if (scols_table_colors_wanted(tb)) {
+ struct libscols_cell *ce = scols_line_get_cell(ln, COL_NAME);
+
+ if (S_ISDIR(mode))
+ scols_cell_set_color(ce, "blue");
+ else if (S_ISLNK(mode))
+ scols_cell_set_color(ce, "cyan");
+ else if (S_ISBLK(mode))
+ scols_cell_set_color(ce, "magenta");
+ else if ((mode & S_IXOTH) || (mode & S_IXGRP) || (mode & S_IXUSR))
+ scols_cell_set_color(ce, "green");
+ }
+
+ if (S_ISDIR(st->st_mode)) {
+ int fd;
+
+ if (parent_fd >= 0)
+ fd = openat(parent_fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
+ else
+ fd = open(name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
+ if (fd >= 0) {
+ rc = add_children(tb, ln, fd);
+ close(fd);
+ }
+ }
+ return rc;
+fail:
+ err(EXIT_FAILURE, "failed to create cell data");
+ return -1;
+}
+
+/* read all entrines from directory addressed by @fd */
+static int add_children(struct libscols_table *tb,
+ struct libscols_line *ln,
+ int fd)
+{
+ DIR *dir;
+ struct dirent *d;
+
+ dir = fdopendir(fd);
+ if (!dir)
+ return -errno;
+
+ while ((d = readdir(dir))) {
+ struct stat st;
+
+ if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
+ continue;
+ if (fstatat(fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0)
+ continue;
+ add_line_from_stat(tb, ln, fd, &st, d->d_name);
+ }
+ closedir(dir);
+ return 0;
+}
+
+static void add_lines(struct libscols_table *tb, const char *dirname)
+{
+ struct stat st;
+
+ if (lstat(dirname, &st))
+ err(EXIT_FAILURE, "%s", dirname);
+
+ add_line_from_stat(tb, NULL, -1, &st, dirname);
+}
+
+static void __attribute__((__noreturn__)) usage(FILE *out)
+{
+ fprintf(out, " %s [options] [<dir> ...]\n\n", program_invocation_short_name);
+ fputs(" -c, --csv display a csv-like output\n", out);
+ fputs(" -i, --ascii use ascii characters only\n", out);
+ fputs(" -l, --list use list format output\n", out);
+ fputs(" -n, --noheadings don't print headings\n", out);
+ fputs(" -p, --pairs use key=\"value\" output format\n", out);
+ fputs(" -r, --raw use raw output format\n", out);
+
+ exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+int main(int argc, char *argv[])
+{
+ struct libscols_table *tb;
+ int c, notree = 0;
+
+ static const struct option longopts[] = {
+ { "ascii", 0, 0, 'i' },
+ { "csv", 0, 0, 'c' },
+ { "list", 0, 0, 'l' },
+ { "noheadings", 0, 0, 'n' },
+ { "pairs", 0, 0, 'p' },
+ { "raw", 0, 0, 'r' },
+
+ { NULL, 0, 0, 0 },
+ };
+
+ setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */
+
+ scols_init_debug(0);
+
+ tb = scols_new_table();
+ if (!tb)
+ err(EXIT_FAILURE, "faild to create output table");
+
+ while((c = getopt_long(argc, argv, "cilnpr", longopts, NULL)) != -1) {
+ switch(c) {
+ case 'c':
+ scols_table_set_column_separator(tb, ",");
+ scols_table_enable_raw(tb, 1);
+ notree = 1;
+ break;
+ case 'i':
+ scols_table_enable_ascii(tb, 1);
+ break;
+ case 'l':
+ notree = 1;
+ break;
+ case 'n':
+ scols_table_enable_noheadings(tb, 1);
+ break;
+ case 'p':
+ scols_table_enable_export(tb, 1);
+ notree = 1;
+ break;
+ case 'r':
+ scols_table_enable_raw(tb, 1);
+ notree = 1;
+ break;
+ default:
+ usage(stderr);
+ }
+ }
+
+ scols_table_enable_colors(tb, 1);
+ setup_columns(tb, notree);
+
+ while (optind < argc)
+ add_lines(tb, argv[optind++]);
+
+ scols_print_table(tb);
+ scols_unref_table(tb);
+
+ return EXIT_SUCCESS;
+}
diff -up util-linux-2.23.2/libsmartcols/src/version.c.kzak util-linux-2.23.2/libsmartcols/src/version.c
--- util-linux-2.23.2/libsmartcols/src/version.c.kzak 2014-09-25 14:41:48.993843953 +0200
+++ util-linux-2.23.2/libsmartcols/src/version.c 2014-09-25 14:41:48.993843953 +0200
@@ -0,0 +1,62 @@
+/*
+ * version.c - Return the version of the library
+ *
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * See COPYING.libmount for the License of this software.
+ */
+
+/**
+ * SECTION: version-utils
+ * @title: Version functions
+ * @short_description: functions to get the library version.
+ *
+ * Note that library version is not the same thing as SONAME version. The
+ * libsmarcols uses symbols versioning and SONAME is not modified for releases.
+ *
+ * The library version and symbols version follow util-linux package versioning.
+ */
+
+#include <ctype.h>
+
+#include "smartcolsP.h"
+
+static const char *lib_version = LIBSMARTCOLS_VERSION;
+
+/**
+ * scols_parse_version_string:
+ * @ver_string: version string (e.g "2.18.0")
+ *
+ * Returns: release version code.
+ */
+int scols_parse_version_string(const char *ver_string)
+{
+ const char *cp;
+ int version = 0;
+
+ assert(ver_string);
+
+ for (cp = ver_string; *cp; cp++) {
+ if (*cp == '.')
+ continue;
+ if (!isdigit(*cp))
+ break;
+ version = (version * 10) + (*cp - '0');
+ }
+ return version;
+}
+
+/**
+ * scols_get_library_version:
+ * @ver_string: return pointer to the static library version string if not NULL
+ *
+ * Returns: release version number.
+ */
+int scols_get_library_version(const char **ver_string)
+{
+ if (ver_string)
+ *ver_string = lib_version;
+
+ return scols_parse_version_string(lib_version);
+}
+
diff -up util-linux-2.23.2/lib/tt.c.kzak util-linux-2.23.2/lib/tt.c
--- util-linux-2.23.2/lib/tt.c.kzak 2013-07-15 10:25:46.280049032 +0200
+++ util-linux-2.23.2/lib/tt.c 2014-09-25 14:41:48.982843848 +0200
@@ -52,140 +52,6 @@ static const struct tt_symbols utf8_tt_s
#define is_last_column(_tb, _cl) \
list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
-/*
- * Counts number of cells in multibyte string. For all control and
- * non-printable chars is the result width enlarged to store \x?? hex
- * sequence. See mbs_safe_encode().
- */
-static size_t mbs_safe_width(const char *s)
-{
- mbstate_t st;
- const char *p = s;
- size_t width = 0;
-
- memset(&st, 0, sizeof(st));
-
- while (p && *p) {
- if (iscntrl((unsigned char) *p)) {
- width += 4; /* *p encoded to \x?? */
- p++;
- }
-#ifdef HAVE_WIDECHAR
- else {
- wchar_t wc;
- size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
-
- if (len == 0)
- break;
-
- if (len == (size_t) -1 || len == (size_t) -2) {
- len = 1;
- width += (isprint((unsigned char) *p) ? 1 : 4);
-
- } if (!iswprint(wc))
- width += len * 4; /* hex encode whole sequence */
- else
- width += wcwidth(wc); /* number of cells */
- p += len;
- }
-#else
- else if (!isprint((unsigned char) *p)) {
- width += 4; /* *p encoded to \x?? */
- p++;
- } else {
- width++;
- p++;
- }
-#endif
- }
-
- return width;
-}
-
-/*
- * Returns allocated string where all control and non-printable chars are
- * replaced with \x?? hex sequence.
- */
-static char *mbs_safe_encode(const char *s, size_t *width)
-{
- mbstate_t st;
- const char *p = s;
- char *res, *r;
- size_t sz = s ? strlen(s) : 0;
-
-
- if (!sz)
- return NULL;
-
- memset(&st, 0, sizeof(st));
-
- res = malloc((sz * 4) + 1);
- if (!res)
- return NULL;
-
- r = res;
- *width = 0;
-
- while (p && *p) {
- if (iscntrl((unsigned char) *p)) {
- sprintf(r, "\\x%02x", (unsigned char) *p);
- r += 4;
- *width += 4;
- p++;
- }
-#ifdef HAVE_WIDECHAR
- else {
- wchar_t wc;
- size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
-
- if (len == 0)
- break; /* end of string */
-
- if (len == (size_t) -1 || len == (size_t) -2) {
- len = 1;
- /*
- * Not valid multibyte sequence -- maybe it's
- * printable char according to the current locales.
- */
- if (!isprint((unsigned char) *p)) {
- sprintf(r, "\\x%02x", (unsigned char) *p);
- r += 4;
- *width += 4;
- } else {
- width++;
- *r++ = *p;
- }
- } else if (!iswprint(wc)) {
- size_t i;
- for (i = 0; i < len; i++) {
- sprintf(r, "\\x%02x", (unsigned char) *p);
- r += 4;
- *width += 4;
- }
- } else {
- memcpy(r, p, len);
- r += len;
- *width += wcwidth(wc);
- }
- p += len;
- }
-#else
- else if (!isprint((unsigned char) *p)) {
- sprintf(r, "\\x%02x", (unsigned char) *p);
- p++;
- r += 4;
- *width += 4;
- } else {
- *r++ = *p++;
- *width++;
- }
-#endif
- }
-
- *r = '\0';
-
- return res;
-}
/*
* @flags: TT_FL_* flags (usually TT_FL_{ASCII,RAW})
diff -up util-linux-2.23.2/Makefile.am.kzak util-linux-2.23.2/Makefile.am
--- util-linux-2.23.2/Makefile.am.kzak 2013-06-13 09:46:10.334649886 +0200
+++ util-linux-2.23.2/Makefile.am 2014-09-25 14:41:48.979843819 +0200
@@ -22,6 +22,7 @@ dist_noinst_DATA = $(dist_man_MANS)
#
ul_libblkid_incdir = $(top_builddir)/libblkid/src
ul_libmount_incdir = $(top_builddir)/libmount/src
+ul_libsmartcols_incdir = $(top_builddir)/libsmartcols/src
ul_libuuid_incdir = $(top_srcdir)/libuuid/src
ul_libfdisk_incdir = $(top_srcdir)/libfdisk/src
@@ -77,6 +78,7 @@ include lib/Makemodule.am
include libuuid/Makemodule.am
include libblkid/Makemodule.am
include libmount/Makemodule.am
+include libsmartcols/Makemodule.am
include libfdisk/Makemodule.am
include schedutils/Makemodule.am