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.
6321 lines
173 KiB
6321 lines
173 KiB
6 years ago
|
From fc6853caa0f3e4f8f10404e58f2dbf9f0df88bd4 Mon Sep 17 00:00:00 2001
|
||
|
From: Karel Zak <kzak@redhat.com>
|
||
|
Date: Thu, 31 May 2018 11:44:35 +0200
|
||
|
Subject: [PATCH 153/173] libsmartcols: backport upstream version
|
||
|
v2.32-158-gc0bdff999
|
||
|
|
||
|
Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1561350
|
||
|
Signed-off-by: Karel Zak <kzak@redhat.com>
|
||
|
---
|
||
|
Makefile.am | 1 +
|
||
|
configure.ac | 3 -
|
||
|
libsmartcols/Makemodule.am | 3 +-
|
||
|
libsmartcols/docs/Makefile.am | 4 +-
|
||
|
libsmartcols/docs/libsmartcols-docs.xml | 28 +-
|
||
|
libsmartcols/docs/libsmartcols-sections.txt | 47 +-
|
||
|
libsmartcols/samples/Makemodule.am | 37 +
|
||
|
libsmartcols/samples/continuous.c | 138 +++
|
||
|
libsmartcols/samples/fromfile.c | 344 +++++++
|
||
|
libsmartcols/samples/maxout.c | 56 ++
|
||
|
libsmartcols/samples/title.c | 135 +++
|
||
|
libsmartcols/{src/test.c => samples/tree.c} | 77 +-
|
||
|
libsmartcols/samples/wrap.c | 111 +++
|
||
|
libsmartcols/src/Makemodule.am | 41 +-
|
||
|
libsmartcols/src/cell.c | 111 ++-
|
||
|
libsmartcols/src/column.c | 351 +++++--
|
||
|
libsmartcols/src/iter.c | 2 +-
|
||
|
libsmartcols/src/libsmartcols.h.in | 156 +++-
|
||
|
libsmartcols/src/libsmartcols.sym | 72 ++
|
||
|
libsmartcols/src/line.c | 173 ++--
|
||
|
libsmartcols/src/smartcolsP.h | 70 +-
|
||
|
libsmartcols/src/symbols.c | 114 ++-
|
||
|
libsmartcols/src/table.c | 851 +++++++++++++----
|
||
|
libsmartcols/src/table_print.c | 1342 ++++++++++++++++++++++-----
|
||
|
24 files changed, 3530 insertions(+), 737 deletions(-)
|
||
|
create mode 100644 libsmartcols/samples/Makemodule.am
|
||
|
create mode 100644 libsmartcols/samples/continuous.c
|
||
|
create mode 100644 libsmartcols/samples/fromfile.c
|
||
|
create mode 100644 libsmartcols/samples/maxout.c
|
||
|
create mode 100644 libsmartcols/samples/title.c
|
||
|
rename libsmartcols/{src/test.c => samples/tree.c} (68%)
|
||
|
create mode 100644 libsmartcols/samples/wrap.c
|
||
|
|
||
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index 67464e4b2..7d5fa10e9 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -118,6 +118,7 @@ edit_cmd = sed \
|
||
|
-e 's|@VERSION[@]|$(VERSION)|g' \
|
||
|
-e 's|@LIBUUID_VERSION[@]|$(LIBUUID_VERSION)|g' \
|
||
|
-e 's|@LIBMOUNT_VERSION[@]|$(LIBMOUNT_VERSION)|g' \
|
||
|
+ -e 's|@LIBSMARTCOLS_VERSION[@]|$(LIBSMARTCOLS_VERSION)|g' \
|
||
|
-e 's|@LIBBLKID_VERSION[@]|$(LIBBLKID_VERSION)|g'
|
||
|
|
||
|
CLEANFILES += $(PATHFILES)
|
||
|
diff --git a/configure.ac b/configure.ac
|
||
|
index 8cf317dc0..d561e01d0 100644
|
||
|
--- a/configure.ac
|
||
|
+++ b/configure.ac
|
||
|
@@ -133,9 +133,6 @@ AC_SUBST([BSD_WARN_CFLAGS])
|
||
|
dnl libtool-2
|
||
|
LT_INIT
|
||
|
|
||
|
-dnl check supported linker flags
|
||
|
-AX_CHECK_VSCRIPT
|
||
|
-
|
||
|
m4_ifndef([PKG_PROG_PKG_CONFIG],
|
||
|
[m4_fatal([Could not locate the pkg-config autoconf
|
||
|
macros. These are usually located in /usr/share/aclocal/pkg.m4.
|
||
|
diff --git a/libsmartcols/Makemodule.am b/libsmartcols/Makemodule.am
|
||
|
index 0089712f1..012848b2b 100644
|
||
|
--- a/libsmartcols/Makemodule.am
|
||
|
+++ b/libsmartcols/Makemodule.am
|
||
|
@@ -1,13 +1,14 @@
|
||
|
if BUILD_LIBSMARTCOLS
|
||
|
|
||
|
include libsmartcols/src/Makemodule.am
|
||
|
+include libsmartcols/samples/Makemodule.am
|
||
|
|
||
|
if ENABLE_GTK_DOC
|
||
|
# Docs uses separate Makefiles
|
||
|
SUBDIRS += libsmartcols/docs
|
||
|
endif
|
||
|
|
||
|
-# noinst for RHEL7: pkgconfig_DATA += libsmartcols/smartcols.pc
|
||
|
+pkgconfig_DATA += libsmartcols/smartcols.pc
|
||
|
PATHFILES += libsmartcols/smartcols.pc
|
||
|
EXTRA_DIST += libsmartcols/COPYING
|
||
|
|
||
|
diff --git a/libsmartcols/docs/Makefile.am b/libsmartcols/docs/Makefile.am
|
||
|
index c5aa2237c..e8a7600e9 100644
|
||
|
--- a/libsmartcols/docs/Makefile.am
|
||
|
+++ b/libsmartcols/docs/Makefile.am
|
||
|
@@ -32,7 +32,7 @@ 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
|
||
|
+MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space scols
|
||
|
|
||
|
# Extra options to supply to gtkdoc-mktmpl
|
||
|
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
|
||
|
@@ -67,7 +67,7 @@ HTML_IMAGES=
|
||
|
# 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
|
||
|
+# SGML files where gtk-doc abbreviations (#GtkWidget) are expanded
|
||
|
# These files must be listed here *and* in content_files
|
||
|
# e.g. expand_content_files=running.sgml
|
||
|
expand_content_files=
|
||
|
diff --git a/libsmartcols/docs/libsmartcols-docs.xml b/libsmartcols/docs/libsmartcols-docs.xml
|
||
|
index 4976ba701..02ee1ffe1 100644
|
||
|
--- a/libsmartcols/docs/libsmartcols-docs.xml
|
||
|
+++ b/libsmartcols/docs/libsmartcols-docs.xml
|
||
|
@@ -9,12 +9,12 @@
|
||
|
<title>libsmartcols Reference Manual</title>
|
||
|
<releaseinfo>for libsmartcols version &version;</releaseinfo>
|
||
|
<copyright>
|
||
|
- <year>2014</year>
|
||
|
+ <year>2014-2018</year>
|
||
|
<holder>Karel Zak <kzak@redhat.com></holder>
|
||
|
</copyright>
|
||
|
</bookinfo>
|
||
|
|
||
|
- <part id="gtk">
|
||
|
+ <part id="overview">
|
||
|
<title>libsmartcols Overview</title>
|
||
|
<partintro>
|
||
|
<para>
|
||
|
@@ -22,7 +22,7 @@ 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/.
|
||
|
+available from https://www.kernel.org/pub/linux/utils/util-linux/.
|
||
|
</para>
|
||
|
</partintro>
|
||
|
</part>
|
||
|
@@ -45,8 +45,28 @@ available from ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
|
||
|
<xi:include href="xml/version-utils.xml"/>
|
||
|
<xi:include href="xml/init.xml"/>
|
||
|
</part>
|
||
|
- <index id="api-index-full">
|
||
|
+ <index id="api-index">
|
||
|
<title>API Index</title>
|
||
|
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||
|
</index>
|
||
|
+ <index role="2.27">
|
||
|
+ <title>Index of new symbols in 2.27</title>
|
||
|
+ <xi:include href="xml/api-index-2.27.xml"><xi:fallback /></xi:include>
|
||
|
+ </index>
|
||
|
+ <index role="2.28">
|
||
|
+ <title>Index of new symbols in 2.28</title>
|
||
|
+ <xi:include href="xml/api-index-2.28.xml"><xi:fallback /></xi:include>
|
||
|
+ </index>
|
||
|
+ <index role="2.29">
|
||
|
+ <title>Index of new symbols in 2.29</title>
|
||
|
+ <xi:include href="xml/api-index-2.29.xml"><xi:fallback /></xi:include>
|
||
|
+ </index>
|
||
|
+ <index role="2.30">
|
||
|
+ <title>Index of new symbols in 2.30</title>
|
||
|
+ <xi:include href="xml/api-index-2.30.xml"><xi:fallback /></xi:include>
|
||
|
+ </index>
|
||
|
+ <index role="2.31">
|
||
|
+ <title>Index of new symbols in 2.31</title>
|
||
|
+ <xi:include href="xml/api-index-2.31.xml"><xi:fallback /></xi:include>
|
||
|
+ </index>
|
||
|
</book>
|
||
|
diff --git a/libsmartcols/docs/libsmartcols-sections.txt b/libsmartcols/docs/libsmartcols-sections.txt
|
||
|
index 2b8180c52..79786b544 100644
|
||
|
--- a/libsmartcols/docs/libsmartcols-sections.txt
|
||
|
+++ b/libsmartcols/docs/libsmartcols-sections.txt
|
||
|
@@ -2,12 +2,15 @@
|
||
|
<FILE>cell</FILE>
|
||
|
libscols_cell
|
||
|
scols_cell_copy_content
|
||
|
+scols_cell_get_alignment
|
||
|
scols_cell_get_color
|
||
|
scols_cell_get_data
|
||
|
+scols_cell_get_flags
|
||
|
scols_cell_get_userdata
|
||
|
scols_cell_refer_data
|
||
|
scols_cell_set_color
|
||
|
scols_cell_set_data
|
||
|
+scols_cell_set_flags
|
||
|
scols_cell_set_userdata
|
||
|
scols_cmpstr_cells
|
||
|
scols_reset_cell
|
||
|
@@ -19,20 +22,32 @@ libscols_column
|
||
|
scols_column_get_color
|
||
|
scols_column_get_flags
|
||
|
scols_column_get_header
|
||
|
+scols_column_get_json_type
|
||
|
+scols_column_get_safechars
|
||
|
+scols_column_get_table
|
||
|
scols_column_get_whint
|
||
|
+scols_column_get_width
|
||
|
+scols_column_is_customwrap
|
||
|
+scols_column_is_hidden
|
||
|
scols_column_is_noextremes
|
||
|
scols_column_is_right
|
||
|
scols_column_is_strict_width
|
||
|
scols_column_is_tree
|
||
|
scols_column_is_trunc
|
||
|
+scols_column_is_wrap
|
||
|
scols_column_set_cmpfunc
|
||
|
scols_column_set_color
|
||
|
scols_column_set_flags
|
||
|
+scols_column_set_json_type
|
||
|
+scols_column_set_safechars
|
||
|
scols_column_set_whint
|
||
|
+scols_column_set_wrapfunc
|
||
|
scols_copy_column
|
||
|
scols_new_column
|
||
|
scols_ref_column
|
||
|
scols_unref_column
|
||
|
+scols_wrapnl_chunksize
|
||
|
+scols_wrapnl_nextchunk
|
||
|
</SECTION>
|
||
|
|
||
|
<SECTION>
|
||
|
@@ -58,10 +73,13 @@ scols_line_get_ncells
|
||
|
scols_line_get_parent
|
||
|
scols_line_get_userdata
|
||
|
scols_line_has_children
|
||
|
+scols_line_is_ancestor
|
||
|
scols_line_next_child
|
||
|
+scols_line_refer_column_data
|
||
|
scols_line_refer_data
|
||
|
scols_line_remove_child
|
||
|
scols_line_set_color
|
||
|
+scols_line_set_column_data
|
||
|
scols_line_set_data
|
||
|
scols_line_set_userdata
|
||
|
scols_new_line
|
||
|
@@ -78,6 +96,8 @@ scols_ref_symbols
|
||
|
scols_symbols_set_branch
|
||
|
scols_symbols_set_right
|
||
|
scols_symbols_set_vertical
|
||
|
+scols_symbols_set_title_padding
|
||
|
+scols_symbols_set_cell_padding
|
||
|
scols_unref_symbols
|
||
|
</SECTION>
|
||
|
|
||
|
@@ -87,29 +107,48 @@ libscols_table
|
||
|
scols_copy_table
|
||
|
scols_new_table
|
||
|
scols_ref_table
|
||
|
+scols_sort_table
|
||
|
+scols_sort_table_by_tree
|
||
|
scols_table_add_column
|
||
|
scols_table_add_line
|
||
|
scols_table_colors_wanted
|
||
|
scols_table_enable_ascii
|
||
|
scols_table_enable_colors
|
||
|
+scols_table_enable_noencoding
|
||
|
scols_table_enable_export
|
||
|
+scols_table_enable_header_repeat
|
||
|
+scols_table_enable_json
|
||
|
scols_table_enable_maxout
|
||
|
scols_table_enable_noheadings
|
||
|
+scols_table_enable_nolinesep
|
||
|
+scols_table_enable_nowrap
|
||
|
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_name
|
||
|
scols_table_get_ncols
|
||
|
scols_table_get_nlines
|
||
|
scols_table_get_stream
|
||
|
+scols_table_get_symbols
|
||
|
+scols_table_get_termforce
|
||
|
+scols_table_get_termheight
|
||
|
+scols_table_get_termwidth
|
||
|
+scols_table_get_title
|
||
|
scols_table_is_ascii
|
||
|
scols_table_is_empty
|
||
|
scols_table_is_export
|
||
|
+scols_table_is_header_repeat
|
||
|
+scols_table_is_json
|
||
|
scols_table_is_maxout
|
||
|
scols_table_is_noheadings
|
||
|
+scols_table_is_noencoding
|
||
|
+scols_table_is_nolinesep
|
||
|
+scols_table_is_nowrap
|
||
|
scols_table_is_raw
|
||
|
scols_table_is_tree
|
||
|
+scols_table_move_column
|
||
|
scols_table_new_column
|
||
|
scols_table_new_line
|
||
|
scols_table_next_column
|
||
|
@@ -120,10 +159,14 @@ scols_table_remove_columns
|
||
|
scols_table_remove_line
|
||
|
scols_table_remove_lines
|
||
|
scols_table_set_column_separator
|
||
|
+scols_table_set_default_symbols
|
||
|
scols_table_set_line_separator
|
||
|
+scols_table_set_name
|
||
|
scols_table_set_stream
|
||
|
scols_table_set_symbols
|
||
|
-scols_sort_table
|
||
|
+scols_table_set_termforce
|
||
|
+scols_table_set_termheight
|
||
|
+scols_table_set_termwidth
|
||
|
scols_unref_table
|
||
|
</SECTION>
|
||
|
|
||
|
@@ -131,6 +174,8 @@ scols_unref_table
|
||
|
<FILE>table_print</FILE>
|
||
|
scols_print_table
|
||
|
scols_print_table_to_string
|
||
|
+scols_table_print_range
|
||
|
+scols_table_print_range_to_string
|
||
|
</SECTION>
|
||
|
|
||
|
<SECTION>
|
||
|
diff --git a/libsmartcols/samples/Makemodule.am b/libsmartcols/samples/Makemodule.am
|
||
|
new file mode 100644
|
||
|
index 000000000..0e0208f04
|
||
|
--- /dev/null
|
||
|
+++ b/libsmartcols/samples/Makemodule.am
|
||
|
@@ -0,0 +1,37 @@
|
||
|
+
|
||
|
+check_PROGRAMS += \
|
||
|
+ sample-scols-title \
|
||
|
+ sample-scols-wrap \
|
||
|
+ sample-scols-continuous \
|
||
|
+ sample-scols-fromfile \
|
||
|
+ sample-scols-maxout
|
||
|
+
|
||
|
+sample_scols_cflags = $(AM_CFLAGS) $(NO_UNUSED_WARN_CFLAGS) \
|
||
|
+ -I$(ul_libsmartcols_incdir)
|
||
|
+sample_scols_ldadd = libsmartcols.la $(LDADD)
|
||
|
+
|
||
|
+check_PROGRAMS += sample-scols-tree
|
||
|
+sample_scols_tree_SOURCES = libsmartcols/samples/tree.c
|
||
|
+sample_scols_tree_LDADD = $(sample_scols_ldadd) libcommon.la
|
||
|
+sample_scols_tree_CFLAGS = $(sample_scols_cflags)
|
||
|
+
|
||
|
+sample_scols_title_SOURCES = libsmartcols/samples/title.c
|
||
|
+sample_scols_title_LDADD = $(sample_scols_ldadd) libcommon.la
|
||
|
+sample_scols_title_CFLAGS = $(sample_scols_cflags)
|
||
|
+
|
||
|
+sample_scols_wrap_SOURCES = libsmartcols/samples/wrap.c
|
||
|
+sample_scols_wrap_LDADD = $(sample_scols_ldadd)
|
||
|
+sample_scols_wrap_CFLAGS = $(sample_scols_cflags)
|
||
|
+
|
||
|
+sample_scols_continuous_SOURCES = libsmartcols/samples/continuous.c
|
||
|
+sample_scols_continuous_LDADD = $(sample_scols_ldadd) libcommon.la
|
||
|
+sample_scols_continuous_CFLAGS = $(sample_scols_cflags)
|
||
|
+
|
||
|
+sample_scols_maxout_SOURCES = libsmartcols/samples/maxout.c
|
||
|
+sample_scols_maxout_LDADD = $(sample_scols_ldadd)
|
||
|
+sample_scols_maxout_CFLAGS = $(sample_scols_cflags)
|
||
|
+
|
||
|
+sample_scols_fromfile_SOURCES = libsmartcols/samples/fromfile.c
|
||
|
+sample_scols_fromfile_LDADD = $(sample_scols_ldadd) libcommon.la
|
||
|
+sample_scols_fromfile_CFLAGS = $(sample_scols_cflags)
|
||
|
+
|
||
|
diff --git a/libsmartcols/samples/continuous.c b/libsmartcols/samples/continuous.c
|
||
|
new file mode 100644
|
||
|
index 000000000..8f9d13e6b
|
||
|
--- /dev/null
|
||
|
+++ b/libsmartcols/samples/continuous.c
|
||
|
@@ -0,0 +1,138 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2016 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/time.h>
|
||
|
+
|
||
|
+#include "c.h"
|
||
|
+#include "nls.h"
|
||
|
+#include "strutils.h"
|
||
|
+#include "xalloc.h"
|
||
|
+
|
||
|
+#include "libsmartcols.h"
|
||
|
+
|
||
|
+#define TIME_PERIOD 3.0 /* seconds */
|
||
|
+
|
||
|
+enum { COL_NUM, COL_DATA, COL_TIME };
|
||
|
+
|
||
|
+static double time_diff(struct timeval *a, struct timeval *b)
|
||
|
+{
|
||
|
+ return (a->tv_sec - b->tv_sec) + (a->tv_usec - b->tv_usec) / 1E6;
|
||
|
+}
|
||
|
+
|
||
|
+/* add columns to the @tb */
|
||
|
+static void setup_columns(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ scols_table_enable_maxout(tb, 1);
|
||
|
+ if (!scols_table_new_column(tb, "#NUM", 0.1, SCOLS_FL_RIGHT))
|
||
|
+ goto fail;
|
||
|
+ if (!scols_table_new_column(tb, "DATA", 0.7, 0))
|
||
|
+ goto fail;
|
||
|
+ if (!scols_table_new_column(tb, "TIME", 0.2, 0))
|
||
|
+ goto fail;
|
||
|
+ return;
|
||
|
+fail:
|
||
|
+ scols_unref_table(tb);
|
||
|
+ err(EXIT_FAILURE, "failed to create output columns");
|
||
|
+}
|
||
|
+
|
||
|
+static struct libscols_line *add_line(struct libscols_table *tb, size_t i)
|
||
|
+{
|
||
|
+ char *p;
|
||
|
+ struct libscols_line *ln = scols_table_new_line(tb, NULL);
|
||
|
+
|
||
|
+ if (!ln)
|
||
|
+ err(EXIT_FAILURE, "failed to create output line");
|
||
|
+
|
||
|
+ xasprintf(&p, "%zu", i);
|
||
|
+ if (scols_line_refer_data(ln, COL_NUM, p))
|
||
|
+ goto fail;
|
||
|
+
|
||
|
+ xasprintf(&p, "data-%02zu-%02zu-%02zu-end", i + 1, i + 2, i + 3);
|
||
|
+ if (scols_line_refer_data(ln, COL_DATA, p))
|
||
|
+ goto fail;
|
||
|
+
|
||
|
+ return ln;
|
||
|
+fail:
|
||
|
+ scols_unref_table(tb);
|
||
|
+ err(EXIT_FAILURE, "failed to create output line");
|
||
|
+}
|
||
|
+
|
||
|
+int main(int argc, char *argv[])
|
||
|
+{
|
||
|
+ struct libscols_table *tb;
|
||
|
+ size_t i;
|
||
|
+ struct timeval last;
|
||
|
+
|
||
|
+ scols_init_debug(0);
|
||
|
+
|
||
|
+ tb = scols_new_table();
|
||
|
+ if (!tb)
|
||
|
+ err(EXIT_FAILURE, "failed to create output table");
|
||
|
+
|
||
|
+ setup_columns(tb);
|
||
|
+ gettimeofday(&last, NULL);
|
||
|
+
|
||
|
+ for (i = 0; i < 10; i++) {
|
||
|
+ struct libscols_line *line;
|
||
|
+ struct timeval now;
|
||
|
+ int done = 0;
|
||
|
+ char *timecell = xmalloc( sizeof(stringify_value(UINT_MAX)) );
|
||
|
+
|
||
|
+ line = add_line(tb, i);
|
||
|
+
|
||
|
+ /* Make a reference from cell data to the buffer, then we can
|
||
|
+ * update cell data without any interaction with libsmartcols
|
||
|
+ */
|
||
|
+ scols_line_refer_data(line, COL_TIME, timecell);
|
||
|
+
|
||
|
+ do {
|
||
|
+ double diff;
|
||
|
+
|
||
|
+ gettimeofday(&now, NULL);
|
||
|
+ diff = time_diff(&now, &last);
|
||
|
+
|
||
|
+ if (now.tv_sec == last.tv_sec + (long) TIME_PERIOD)
|
||
|
+ done = 1;
|
||
|
+ else
|
||
|
+ usleep(100000);
|
||
|
+
|
||
|
+ /* update "TIME" cell data */
|
||
|
+ sprintf(timecell, "%f [%3d%%]", diff,
|
||
|
+ done ? 100 : (int)(diff / (TIME_PERIOD / 100.0)));
|
||
|
+
|
||
|
+ /* Note that libsmartcols don't print \n for last line
|
||
|
+ * in the table, but if you print a line somewhere in
|
||
|
+ * the midle of the table you need
|
||
|
+ *
|
||
|
+ * scols_table_enable_nolinesep(tb, !done);
|
||
|
+ *
|
||
|
+ * to disable line breaks. In this example it's
|
||
|
+ * unnecessary as we print the latest line only.
|
||
|
+ */
|
||
|
+
|
||
|
+ /* print the line */
|
||
|
+ scols_table_print_range(tb, line, NULL);
|
||
|
+
|
||
|
+ if (!done) {
|
||
|
+ /* terminal is waiting for \n, fflush() to force output */
|
||
|
+ fflush(scols_table_get_stream(tb));
|
||
|
+ /* move to the begin of the line */
|
||
|
+ fputc('\r', scols_table_get_stream(tb));
|
||
|
+ } else
|
||
|
+ fputc('\n', scols_table_get_stream(tb));
|
||
|
+ } while (!done);
|
||
|
+
|
||
|
+ last = now;
|
||
|
+ }
|
||
|
+
|
||
|
+ scols_unref_table(tb);
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
diff --git a/libsmartcols/samples/fromfile.c b/libsmartcols/samples/fromfile.c
|
||
|
new file mode 100644
|
||
|
index 000000000..c1ab728fd
|
||
|
--- /dev/null
|
||
|
+++ b/libsmartcols/samples/fromfile.c
|
||
|
@@ -0,0 +1,344 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2016 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 "xalloc.h"
|
||
|
+#include "optutils.h"
|
||
|
+
|
||
|
+#include "libsmartcols.h"
|
||
|
+
|
||
|
+struct column_flag {
|
||
|
+ const char *name;
|
||
|
+ int mask;
|
||
|
+};
|
||
|
+
|
||
|
+static const struct column_flag flags[] = {
|
||
|
+ { "trunc", SCOLS_FL_TRUNC },
|
||
|
+ { "tree", SCOLS_FL_TREE },
|
||
|
+ { "right", SCOLS_FL_RIGHT },
|
||
|
+ { "strictwidth",SCOLS_FL_STRICTWIDTH },
|
||
|
+ { "noextremes", SCOLS_FL_NOEXTREMES },
|
||
|
+ { "hidden", SCOLS_FL_HIDDEN },
|
||
|
+ { "wrap", SCOLS_FL_WRAP },
|
||
|
+ { "wrapnl", SCOLS_FL_WRAP },
|
||
|
+ { "none", 0 }
|
||
|
+};
|
||
|
+
|
||
|
+static long name_to_flag(const char *name, size_t namesz)
|
||
|
+{
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ for (i = 0; i < ARRAY_SIZE(flags); i++) {
|
||
|
+ const char *cn = flags[i].name;
|
||
|
+
|
||
|
+ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
|
||
|
+ return flags[i].mask;
|
||
|
+ }
|
||
|
+ warnx("unknown flag: %s", name);
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+
|
||
|
+static int parse_column_flags(char *str)
|
||
|
+{
|
||
|
+ unsigned long num_flags = 0;
|
||
|
+
|
||
|
+ if (string_to_bitmask(str, &num_flags, name_to_flag))
|
||
|
+ err(EXIT_FAILURE, "failed to parse column flags");
|
||
|
+
|
||
|
+ return num_flags;
|
||
|
+}
|
||
|
+
|
||
|
+static struct libscols_column *parse_column(FILE *f)
|
||
|
+{
|
||
|
+ size_t len = 0;
|
||
|
+ char *line = NULL;
|
||
|
+ int nlines = 0;
|
||
|
+
|
||
|
+ struct libscols_column *cl = NULL;
|
||
|
+
|
||
|
+ while (getline(&line, &len, f) != -1) {
|
||
|
+
|
||
|
+ char *p = strrchr(line, '\n');
|
||
|
+ if (p)
|
||
|
+ *p = '\0';
|
||
|
+
|
||
|
+ switch (nlines) {
|
||
|
+ case 0: /* NAME */
|
||
|
+ {
|
||
|
+ struct libscols_cell *hr;
|
||
|
+
|
||
|
+ cl = scols_new_column();
|
||
|
+ if (!cl)
|
||
|
+ goto fail;
|
||
|
+ hr = scols_column_get_header(cl);
|
||
|
+ if (!hr || scols_cell_set_data(hr, line))
|
||
|
+ goto fail;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case 1: /* WIDTH-HINT */
|
||
|
+ {
|
||
|
+ double whint = strtod_or_err(line, "failed to parse column whint");
|
||
|
+ if (scols_column_set_whint(cl, whint))
|
||
|
+ goto fail;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case 2: /* FLAGS */
|
||
|
+ {
|
||
|
+ int num_flags = parse_column_flags(line);
|
||
|
+ if (scols_column_set_flags(cl, num_flags))
|
||
|
+ goto fail;
|
||
|
+ if (strcmp(line, "wrapnl") == 0) {
|
||
|
+ scols_column_set_wrapfunc(cl,
|
||
|
+ scols_wrapnl_chunksize,
|
||
|
+ scols_wrapnl_nextchunk,
|
||
|
+ NULL);
|
||
|
+ scols_column_set_safechars(cl, "\n");
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case 3: /* COLOR */
|
||
|
+ if (scols_column_set_color(cl, line))
|
||
|
+ goto fail;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ nlines++;
|
||
|
+ }
|
||
|
+
|
||
|
+ free(line);
|
||
|
+ return cl;
|
||
|
+fail:
|
||
|
+ free(line);
|
||
|
+ scols_unref_column(cl);
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static int parse_column_data(FILE *f, struct libscols_table *tb, int col)
|
||
|
+{
|
||
|
+ size_t len = 0, nlines = 0;
|
||
|
+ int i;
|
||
|
+ char *str = NULL;
|
||
|
+
|
||
|
+ while ((i = getline(&str, &len, f)) != -1) {
|
||
|
+
|
||
|
+ struct libscols_line *ln;
|
||
|
+ char *p = strrchr(str, '\n');
|
||
|
+ if (p)
|
||
|
+ *p = '\0';
|
||
|
+
|
||
|
+ while ((p = strrchr(str, '\\')) && *(p + 1) == 'n') {
|
||
|
+ *p = '\n';
|
||
|
+ memmove(p + 1, p + 2, i - (p + 2 - str));
|
||
|
+ }
|
||
|
+
|
||
|
+ ln = scols_table_get_line(tb, nlines++);
|
||
|
+ if (!ln)
|
||
|
+ break;
|
||
|
+
|
||
|
+ scols_line_set_data(ln, col, str);
|
||
|
+ }
|
||
|
+
|
||
|
+ free(str);
|
||
|
+ return 0;
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static struct libscols_line *get_line_with_id(struct libscols_table *tb,
|
||
|
+ int col_id, const char *id)
|
||
|
+{
|
||
|
+ struct libscols_line *ln;
|
||
|
+ struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
|
||
|
+
|
||
|
+ while (scols_table_next_line(tb, itr, &ln) == 0) {
|
||
|
+ struct libscols_cell *ce = scols_line_get_cell(ln, col_id);
|
||
|
+ const char *data = ce ? scols_cell_get_data(ce) : NULL;
|
||
|
+
|
||
|
+ if (data && strcmp(data, id) == 0)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ scols_free_iter(itr);
|
||
|
+ return ln;
|
||
|
+}
|
||
|
+
|
||
|
+static void compose_tree(struct libscols_table *tb, int parent_col, int id_col)
|
||
|
+{
|
||
|
+ struct libscols_line *ln;
|
||
|
+ struct libscols_iter *itr = scols_new_iter(SCOLS_ITER_FORWARD);
|
||
|
+
|
||
|
+ while (scols_table_next_line(tb, itr, &ln) == 0) {
|
||
|
+ struct libscols_line *parent = NULL;
|
||
|
+ struct libscols_cell *ce = scols_line_get_cell(ln, parent_col);
|
||
|
+ const char *data = ce ? scols_cell_get_data(ce) : NULL;
|
||
|
+
|
||
|
+ if (data)
|
||
|
+ parent = get_line_with_id(tb, id_col, data);
|
||
|
+ if (parent)
|
||
|
+ scols_line_add_child(parent, ln);
|
||
|
+ }
|
||
|
+
|
||
|
+ scols_free_iter(itr);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static void __attribute__((__noreturn__)) usage(void)
|
||
|
+{
|
||
|
+ FILE *out = stdout;
|
||
|
+ fprintf(out,
|
||
|
+ "\n %s [options] <column-data-file> ...\n\n", program_invocation_short_name);
|
||
|
+
|
||
|
+ fputs(" -m, --maxout fill all terminal width\n", out);
|
||
|
+ fputs(" -c, --column <file> column definition\n", out);
|
||
|
+ fputs(" -n, --nlines <num> number of lines\n", out);
|
||
|
+ fputs(" -J, --json JSON output format\n", out);
|
||
|
+ fputs(" -r, --raw RAW output format\n", out);
|
||
|
+ fputs(" -E, --export use key=\"value\" output format\n", out);
|
||
|
+ fputs(" -C, --colsep <str> set columns separator\n", out);
|
||
|
+ fputs(" -w, --width <num> hardcode terminal width\n", out);
|
||
|
+ fputs(" -p, --tree-parent-column <n> parent column\n", out);
|
||
|
+ fputs(" -i, --tree-id-column <n> id column\n", out);
|
||
|
+ fputs(" -h, --help this help\n", out);
|
||
|
+ fputs("\n", out);
|
||
|
+
|
||
|
+ exit(EXIT_SUCCESS);
|
||
|
+}
|
||
|
+
|
||
|
+int main(int argc, char *argv[])
|
||
|
+{
|
||
|
+ struct libscols_table *tb;
|
||
|
+ int c, n, nlines = 0;
|
||
|
+ int parent_col = -1, id_col = -1;
|
||
|
+
|
||
|
+ static const struct option longopts[] = {
|
||
|
+ { "maxout", 0, NULL, 'm' },
|
||
|
+ { "column", 1, NULL, 'c' },
|
||
|
+ { "nlines", 1, NULL, 'n' },
|
||
|
+ { "width", 1, NULL, 'w' },
|
||
|
+ { "tree-parent-column", 1, NULL, 'p' },
|
||
|
+ { "tree-id-column", 1, NULL, 'i' },
|
||
|
+ { "json", 0, NULL, 'J' },
|
||
|
+ { "raw", 0, NULL, 'r' },
|
||
|
+ { "export", 0, NULL, 'E' },
|
||
|
+ { "colsep", 1, NULL, 'C' },
|
||
|
+ { "help", 0, NULL, 'h' },
|
||
|
+ { NULL, 0, NULL, 0 },
|
||
|
+ };
|
||
|
+
|
||
|
+ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
|
||
|
+ { 'E', 'J', 'r' },
|
||
|
+ { 0 }
|
||
|
+ };
|
||
|
+ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
|
||
|
+
|
||
|
+ setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */
|
||
|
+ scols_init_debug(0);
|
||
|
+
|
||
|
+ tb = scols_new_table();
|
||
|
+ if (!tb)
|
||
|
+ err(EXIT_FAILURE, "failed to create output table");
|
||
|
+
|
||
|
+ while((c = getopt_long(argc, argv, "hCc:Ei:Jmn:p:rw:", longopts, NULL)) != -1) {
|
||
|
+
|
||
|
+ err_exclusive_options(c, longopts, excl, excl_st);
|
||
|
+
|
||
|
+ switch(c) {
|
||
|
+ case 'c': /* add column from file */
|
||
|
+ {
|
||
|
+ struct libscols_column *cl;
|
||
|
+ FILE *f = fopen(optarg, "r");
|
||
|
+
|
||
|
+ if (!f)
|
||
|
+ err(EXIT_FAILURE, "%s: open failed", optarg);
|
||
|
+ cl = parse_column(f);
|
||
|
+ if (cl && scols_table_add_column(tb, cl))
|
||
|
+ err(EXIT_FAILURE, "%s: failed to add column", optarg);
|
||
|
+ scols_unref_column(cl);
|
||
|
+ fclose(f);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case 'p':
|
||
|
+ parent_col = strtou32_or_err(optarg, "failed to parse tree PARENT column");
|
||
|
+ break;
|
||
|
+ case 'i':
|
||
|
+ id_col = strtou32_or_err(optarg, "failed to parse tree ID column");
|
||
|
+ break;
|
||
|
+ case 'J':
|
||
|
+ scols_table_enable_json(tb, 1);
|
||
|
+ scols_table_set_name(tb, "testtable");
|
||
|
+ break;
|
||
|
+ case 'm':
|
||
|
+ scols_table_enable_maxout(tb, TRUE);
|
||
|
+ break;
|
||
|
+ case 'r':
|
||
|
+ scols_table_enable_raw(tb, TRUE);
|
||
|
+ break;
|
||
|
+ case 'E':
|
||
|
+ scols_table_enable_export(tb, TRUE);
|
||
|
+ break;
|
||
|
+ case 'C':
|
||
|
+ scols_table_set_column_separator(tb, optarg);
|
||
|
+ break;
|
||
|
+ case 'n':
|
||
|
+ nlines = strtou32_or_err(optarg, "failed to parse number of lines");
|
||
|
+ break;
|
||
|
+ case 'w':
|
||
|
+ scols_table_set_termforce(tb, SCOLS_TERMFORCE_ALWAYS);
|
||
|
+ scols_table_set_termwidth(tb, strtou32_or_err(optarg, "failed to parse terminal width"));
|
||
|
+ break;
|
||
|
+ case 'h':
|
||
|
+ usage();
|
||
|
+ default:
|
||
|
+ errtryhelp(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (nlines <= 0)
|
||
|
+ errx(EXIT_FAILURE, "--nlines not set");
|
||
|
+
|
||
|
+ for (n = 0; n < nlines; n++) {
|
||
|
+ struct libscols_line *ln = scols_new_line();
|
||
|
+
|
||
|
+ if (!ln || scols_table_add_line(tb, ln))
|
||
|
+ err(EXIT_FAILURE, "failed to add a new line");
|
||
|
+
|
||
|
+ scols_unref_line(ln);
|
||
|
+ }
|
||
|
+
|
||
|
+ n = 0;
|
||
|
+
|
||
|
+ while (optind < argc) {
|
||
|
+ FILE *f = fopen(argv[optind], "r");
|
||
|
+
|
||
|
+ if (!f)
|
||
|
+ err(EXIT_FAILURE, "%s: open failed", argv[optind]);
|
||
|
+
|
||
|
+ parse_column_data(f, tb, n);
|
||
|
+ optind++;
|
||
|
+ n++;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (scols_table_is_tree(tb) && parent_col >= 0 && id_col >= 0)
|
||
|
+ compose_tree(tb, parent_col, id_col);
|
||
|
+
|
||
|
+ scols_table_enable_colors(tb, isatty(STDOUT_FILENO));
|
||
|
+
|
||
|
+ scols_print_table(tb);
|
||
|
+ scols_unref_table(tb);
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
diff --git a/libsmartcols/samples/maxout.c b/libsmartcols/samples/maxout.c
|
||
|
new file mode 100644
|
||
|
index 000000000..07a05e13f
|
||
|
--- /dev/null
|
||
|
+++ b/libsmartcols/samples/maxout.c
|
||
|
@@ -0,0 +1,56 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2016 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 "libsmartcols.h"
|
||
|
+
|
||
|
+enum { COL_LEFT, COL_FOO, COL_RIGHT };
|
||
|
+
|
||
|
+int main(int argc, char *argv[])
|
||
|
+{
|
||
|
+ struct libscols_table *tb;
|
||
|
+ int rc = -1, nlines = 3;
|
||
|
+
|
||
|
+ setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */
|
||
|
+
|
||
|
+ scols_init_debug(0);
|
||
|
+
|
||
|
+ tb = scols_new_table();
|
||
|
+ if (!tb)
|
||
|
+ err(EXIT_FAILURE, "failed to create output table");
|
||
|
+
|
||
|
+ scols_table_enable_maxout(tb, TRUE);
|
||
|
+ if (!scols_table_new_column(tb, "LEFT", 0, 0))
|
||
|
+ goto done;
|
||
|
+ if (!scols_table_new_column(tb, "FOO", 0, 0))
|
||
|
+ goto done;
|
||
|
+ if (!scols_table_new_column(tb, "RIGHT", 0, SCOLS_FL_RIGHT))
|
||
|
+ goto done;
|
||
|
+
|
||
|
+ while (nlines--) {
|
||
|
+ struct libscols_line *ln = scols_table_new_line(tb, NULL);
|
||
|
+
|
||
|
+ scols_line_set_data(ln, COL_LEFT, "A");
|
||
|
+ scols_line_set_data(ln, COL_FOO, "B");
|
||
|
+ scols_line_set_data(ln, COL_RIGHT, "C");
|
||
|
+ }
|
||
|
+
|
||
|
+ scols_print_table(tb);
|
||
|
+ rc = 0;
|
||
|
+done:
|
||
|
+ scols_unref_table(tb);
|
||
|
+ return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||
|
+}
|
||
|
diff --git a/libsmartcols/samples/title.c b/libsmartcols/samples/title.c
|
||
|
new file mode 100644
|
||
|
index 000000000..131400da4
|
||
|
--- /dev/null
|
||
|
+++ b/libsmartcols/samples/title.c
|
||
|
@@ -0,0 +1,135 @@
|
||
|
+/*
|
||
|
+ * 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 "xalloc.h"
|
||
|
+
|
||
|
+#include "libsmartcols.h"
|
||
|
+
|
||
|
+
|
||
|
+enum { COL_NAME, COL_DATA };
|
||
|
+
|
||
|
+/* add columns to the @tb */
|
||
|
+static void setup_columns(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ if (!scols_table_new_column(tb, "NAME", 0, 0))
|
||
|
+ goto fail;
|
||
|
+ if (!scols_table_new_column(tb, "DATA", 0, 0))
|
||
|
+ goto fail;
|
||
|
+ return;
|
||
|
+fail:
|
||
|
+ scols_unref_table(tb);
|
||
|
+ err(EXIT_FAILURE, "failed to create output columns");
|
||
|
+}
|
||
|
+
|
||
|
+static void add_line(struct libscols_table *tb, const char *name, const char *data)
|
||
|
+{
|
||
|
+ struct libscols_line *ln = scols_table_new_line(tb, NULL);
|
||
|
+ if (!ln)
|
||
|
+ err(EXIT_FAILURE, "failed to create output line");
|
||
|
+
|
||
|
+ if (scols_line_set_data(ln, COL_NAME, name))
|
||
|
+ goto fail;
|
||
|
+ if (scols_line_set_data(ln, COL_DATA, data))
|
||
|
+ goto fail;
|
||
|
+ return;
|
||
|
+fail:
|
||
|
+ scols_unref_table(tb);
|
||
|
+ err(EXIT_FAILURE, "failed to create output line");
|
||
|
+}
|
||
|
+
|
||
|
+int main(int argc, char *argv[])
|
||
|
+{
|
||
|
+ struct libscols_table *tb;
|
||
|
+ struct libscols_symbols *sy;
|
||
|
+ struct libscols_cell *title;
|
||
|
+ int c;
|
||
|
+
|
||
|
+ static const struct option longopts[] = {
|
||
|
+ { "maxout", 0, NULL, 'm' },
|
||
|
+ { "width", 1, NULL, 'w' },
|
||
|
+ { "help", 1, NULL, 'h' },
|
||
|
+
|
||
|
+ { NULL, 0, NULL, 0 },
|
||
|
+ };
|
||
|
+
|
||
|
+ setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */
|
||
|
+
|
||
|
+ scols_init_debug(0);
|
||
|
+
|
||
|
+ tb = scols_new_table();
|
||
|
+ if (!tb)
|
||
|
+ err(EXIT_FAILURE, "failed to create output table");
|
||
|
+
|
||
|
+ while((c = getopt_long(argc, argv, "hmw:", longopts, NULL)) != -1) {
|
||
|
+ switch(c) {
|
||
|
+ case 'h':
|
||
|
+ printf("%s [--help | --maxout | --width <num>]\n", program_invocation_short_name);
|
||
|
+ break;
|
||
|
+ case 'm':
|
||
|
+ scols_table_enable_maxout(tb, TRUE);
|
||
|
+ break;
|
||
|
+ case 'w':
|
||
|
+ scols_table_set_termforce(tb, SCOLS_TERMFORCE_ALWAYS);
|
||
|
+ scols_table_set_termwidth(tb, strtou32_or_err(optarg, "failed to parse terminal width"));
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ scols_table_enable_colors(tb, isatty(STDOUT_FILENO));
|
||
|
+ setup_columns(tb);
|
||
|
+ add_line(tb, "foo", "bla bla bla");
|
||
|
+ add_line(tb, "bar", "alb alb alb");
|
||
|
+
|
||
|
+ title = scols_table_get_title(tb);
|
||
|
+
|
||
|
+ /* right */
|
||
|
+ scols_cell_set_data(title, "This is right title");
|
||
|
+ scols_cell_set_color(title, "red");
|
||
|
+ scols_cell_set_flags(title, SCOLS_CELL_FL_RIGHT);
|
||
|
+ scols_print_table(tb);
|
||
|
+
|
||
|
+ /* left without padding */
|
||
|
+ scols_cell_set_data(title, "This is left title (without padding)");
|
||
|
+ scols_cell_set_color(title, "yellow");
|
||
|
+ scols_cell_set_flags(title, SCOLS_CELL_FL_LEFT);
|
||
|
+ scols_print_table(tb);
|
||
|
+
|
||
|
+ /* center */
|
||
|
+ sy = scols_new_symbols();
|
||
|
+ if (!sy)
|
||
|
+ err_oom();
|
||
|
+ scols_table_set_symbols(tb, sy);
|
||
|
+ scols_unref_symbols(sy);
|
||
|
+
|
||
|
+ scols_symbols_set_title_padding(sy, "=");
|
||
|
+ scols_cell_set_data(title, "This is center title (with padding)");
|
||
|
+ scols_cell_set_color(title, "green");
|
||
|
+ scols_cell_set_flags(title, SCOLS_CELL_FL_CENTER);
|
||
|
+ scols_print_table(tb);
|
||
|
+
|
||
|
+ /* left with padding */
|
||
|
+ scols_symbols_set_title_padding(sy, "-");
|
||
|
+ scols_cell_set_data(title, "This is left title (with padding)");
|
||
|
+ scols_cell_set_color(title, "blue");
|
||
|
+ scols_cell_set_flags(title, SCOLS_CELL_FL_LEFT);
|
||
|
+ scols_print_table(tb);
|
||
|
+
|
||
|
+
|
||
|
+ scols_unref_table(tb);
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
diff --git a/libsmartcols/src/test.c b/libsmartcols/samples/tree.c
|
||
|
similarity index 68%
|
||
|
rename from libsmartcols/src/test.c
|
||
|
rename to libsmartcols/samples/tree.c
|
||
|
index dd87fd38b..0cdb99420 100644
|
||
|
--- a/libsmartcols/src/test.c
|
||
|
+++ b/libsmartcols/samples/tree.c
|
||
|
@@ -39,7 +39,7 @@ static void setup_columns(struct libscols_table *tb, int notree)
|
||
|
return;
|
||
|
fail:
|
||
|
scols_unref_table(tb);
|
||
|
- err(EXIT_FAILURE, "faild to create output columns");
|
||
|
+ err(EXIT_FAILURE, "failed to create output columns");
|
||
|
}
|
||
|
|
||
|
/* add a new line to @tb, the content is based on @st */
|
||
|
@@ -104,7 +104,7 @@ fail:
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
-/* read all entrines from directory addressed by @fd */
|
||
|
+/* read all entries from directory addressed by @fd */
|
||
|
static int add_children(struct libscols_table *tb,
|
||
|
struct libscols_line *ln,
|
||
|
int fd)
|
||
|
@@ -142,12 +142,15 @@ static void add_lines(struct libscols_table *tb, const char *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);
|
||
|
+ 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(" -J, --json use JSON output format\n", out);
|
||
|
+ fputs(" -r, --raw use raw output format\n", out);
|
||
|
+ fputs(" -S, --range-start <n> first line to print\n", out);
|
||
|
+ fputs(" -E, --range-end <n> last line to print\n", out);
|
||
|
|
||
|
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
||
|
}
|
||
|
@@ -155,17 +158,20 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
struct libscols_table *tb;
|
||
|
- int c, notree = 0;
|
||
|
+ int c, notree = 0, nstart = -1, nend = -1;
|
||
|
+
|
||
|
|
||
|
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 },
|
||
|
+ { "ascii", 0, NULL, 'i' },
|
||
|
+ { "csv", 0, NULL, 'c' },
|
||
|
+ { "list", 0, NULL, 'l' },
|
||
|
+ { "noheadings", 0, NULL, 'n' },
|
||
|
+ { "pairs", 0, NULL, 'p' },
|
||
|
+ { "json", 0, NULL, 'J' },
|
||
|
+ { "raw", 0, NULL, 'r' },
|
||
|
+ { "range-start",1, NULL, 'S' },
|
||
|
+ { "range-end", 1, NULL, 'E' },
|
||
|
+ { NULL, 0, NULL, 0 },
|
||
|
};
|
||
|
|
||
|
setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */
|
||
|
@@ -174,9 +180,9 @@ int main(int argc, char *argv[])
|
||
|
|
||
|
tb = scols_new_table();
|
||
|
if (!tb)
|
||
|
- err(EXIT_FAILURE, "faild to create output table");
|
||
|
+ err(EXIT_FAILURE, "failed to create output table");
|
||
|
|
||
|
- while((c = getopt_long(argc, argv, "cilnpr", longopts, NULL)) != -1) {
|
||
|
+ while((c = getopt_long(argc, argv, "ciJlnprS:E:", longopts, NULL)) != -1) {
|
||
|
switch(c) {
|
||
|
case 'c':
|
||
|
scols_table_set_column_separator(tb, ",");
|
||
|
@@ -186,6 +192,10 @@ int main(int argc, char *argv[])
|
||
|
case 'i':
|
||
|
scols_table_enable_ascii(tb, 1);
|
||
|
break;
|
||
|
+ case 'J':
|
||
|
+ scols_table_set_name(tb, "scolstest");
|
||
|
+ scols_table_enable_json(tb, 1);
|
||
|
+ break;
|
||
|
case 'l':
|
||
|
notree = 1;
|
||
|
break;
|
||
|
@@ -200,19 +210,40 @@ int main(int argc, char *argv[])
|
||
|
scols_table_enable_raw(tb, 1);
|
||
|
notree = 1;
|
||
|
break;
|
||
|
+ case 'S':
|
||
|
+ nstart = strtos32_or_err(optarg, "failed to parse range start") - 1;
|
||
|
+ break;
|
||
|
+ case 'E':
|
||
|
+ nend = strtos32_or_err(optarg, "failed to parse range end") - 1;
|
||
|
+ break;
|
||
|
default:
|
||
|
usage(stderr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- scols_table_enable_colors(tb, 1);
|
||
|
+ scols_table_enable_colors(tb, isatty(STDOUT_FILENO));
|
||
|
setup_columns(tb, notree);
|
||
|
|
||
|
- while (optind < argc)
|
||
|
+ if (optind == argc)
|
||
|
+ add_lines(tb, ".");
|
||
|
+ else while (optind < argc)
|
||
|
add_lines(tb, argv[optind++]);
|
||
|
|
||
|
- scols_print_table(tb);
|
||
|
- scols_unref_table(tb);
|
||
|
+ if (nstart >= 0 || nend >= 0) {
|
||
|
+ /* print subset */
|
||
|
+ struct libscols_line *start = NULL, *end = NULL;
|
||
|
+
|
||
|
+ if (nstart >= 0)
|
||
|
+ start = scols_table_get_line(tb, nstart);
|
||
|
+ if (nend >= 0)
|
||
|
+ end = scols_table_get_line(tb, nend);
|
||
|
|
||
|
+ if (start || end)
|
||
|
+ scols_table_print_range(tb, start, end);
|
||
|
+ } else
|
||
|
+ /* print all table */
|
||
|
+ scols_print_table(tb);
|
||
|
+
|
||
|
+ scols_unref_table(tb);
|
||
|
return EXIT_SUCCESS;
|
||
|
}
|
||
|
diff --git a/libsmartcols/samples/wrap.c b/libsmartcols/samples/wrap.c
|
||
|
new file mode 100644
|
||
|
index 000000000..795bef714
|
||
|
--- /dev/null
|
||
|
+++ b/libsmartcols/samples/wrap.c
|
||
|
@@ -0,0 +1,111 @@
|
||
|
+/*
|
||
|
+ * 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 "xalloc.h"
|
||
|
+
|
||
|
+#include "libsmartcols.h"
|
||
|
+
|
||
|
+
|
||
|
+enum { COL_NAME, COL_DESC, COL_FOO, COL_LIKE, COL_TEXT };
|
||
|
+
|
||
|
+/* add columns to the @tb */
|
||
|
+static void setup_columns(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ if (!scols_table_new_column(tb, "NAME", 0, SCOLS_FL_TREE))
|
||
|
+ goto fail;
|
||
|
+ if (!scols_table_new_column(tb, "DESC", 0, 0))
|
||
|
+ goto fail;
|
||
|
+ if (!scols_table_new_column(tb, "FOO", 0, SCOLS_FL_WRAP))
|
||
|
+ goto fail;
|
||
|
+ if (!scols_table_new_column(tb, "LIKE", 0, SCOLS_FL_RIGHT))
|
||
|
+ goto fail;
|
||
|
+ if (!scols_table_new_column(tb, "TEXT", 0, SCOLS_FL_WRAP))
|
||
|
+ goto fail;
|
||
|
+ return;
|
||
|
+fail:
|
||
|
+ scols_unref_table(tb);
|
||
|
+ err(EXIT_FAILURE, "failed to create output columns");
|
||
|
+}
|
||
|
+
|
||
|
+static char *gen_text(const char *prefix, const char *sub_prefix, char *buf, size_t sz)
|
||
|
+{
|
||
|
+ int x = snprintf(buf, sz, "%s-%s-", prefix, sub_prefix);
|
||
|
+
|
||
|
+ for ( ; (size_t)x < sz - 1; x++)
|
||
|
+ buf[x] = *prefix;
|
||
|
+
|
||
|
+ buf[x++] = 'x';
|
||
|
+ buf[x] = '\0';
|
||
|
+ return buf;
|
||
|
+}
|
||
|
+
|
||
|
+static struct libscols_line * add_line( struct libscols_table *tb,
|
||
|
+ struct libscols_line *parent,
|
||
|
+ const char *prefix)
|
||
|
+{
|
||
|
+ char buf[BUFSIZ];
|
||
|
+ struct libscols_line *ln = scols_table_new_line(tb, parent);
|
||
|
+ if (!ln)
|
||
|
+ err(EXIT_FAILURE, "failed to create output line");
|
||
|
+
|
||
|
+ if (scols_line_set_data(ln, COL_NAME, gen_text(prefix, "N", buf, 15)))
|
||
|
+ goto fail;
|
||
|
+ if (scols_line_set_data(ln, COL_DESC, gen_text(prefix, "D", buf, 10)))
|
||
|
+ goto fail;
|
||
|
+ if (scols_line_set_data(ln, COL_FOO, gen_text(prefix, "U", buf, 55)))
|
||
|
+ goto fail;
|
||
|
+ if (scols_line_set_data(ln, COL_LIKE, "1"))
|
||
|
+ goto fail;
|
||
|
+ if (scols_line_set_data(ln, COL_TEXT, gen_text(prefix, "T", buf, 50)))
|
||
|
+ goto fail;
|
||
|
+ return ln;
|
||
|
+fail:
|
||
|
+ scols_unref_table(tb);
|
||
|
+ err(EXIT_FAILURE, "failed to create output line");
|
||
|
+}
|
||
|
+
|
||
|
+int main(int argc, char *argv[])
|
||
|
+{
|
||
|
+ struct libscols_table *tb;
|
||
|
+ struct libscols_line *ln, *xln;
|
||
|
+
|
||
|
+ setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */
|
||
|
+
|
||
|
+ scols_init_debug(0);
|
||
|
+
|
||
|
+ tb = scols_new_table();
|
||
|
+ if (!tb)
|
||
|
+ err(EXIT_FAILURE, "failed to create output table");
|
||
|
+
|
||
|
+ scols_table_enable_colors(tb, isatty(STDOUT_FILENO));
|
||
|
+ setup_columns(tb);
|
||
|
+
|
||
|
+ ln = add_line(tb, NULL, "A");
|
||
|
+ add_line(tb, ln, "aa");
|
||
|
+ add_line(tb, ln, "ab");
|
||
|
+
|
||
|
+ ln = add_line(tb, NULL, "B");
|
||
|
+ xln = add_line(tb, ln, "ba");
|
||
|
+ add_line(tb, xln, "baa");
|
||
|
+ add_line(tb, xln, "bab");
|
||
|
+ add_line(tb, ln, "bb");
|
||
|
+
|
||
|
+ scols_print_table(tb);
|
||
|
+ scols_unref_table(tb);
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
diff --git a/libsmartcols/src/Makemodule.am b/libsmartcols/src/Makemodule.am
|
||
|
index bfe8c75c1..952d5e58f 100644
|
||
|
--- a/libsmartcols/src/Makemodule.am
|
||
|
+++ b/libsmartcols/src/Makemodule.am
|
||
|
@@ -1,10 +1,10 @@
|
||
|
|
||
|
|
||
|
-## 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
|
||
|
+# smartcols.h is generated, so it's stored in builddir!
|
||
|
+smartcolsincdir = $(includedir)/libsmartcols
|
||
|
+nodist_smartcolsinc_HEADERS = libsmartcols/src/libsmartcols.h
|
||
|
|
||
|
-noinst_LTLIBRARIES += libsmartcols.la
|
||
|
+usrlib_exec_LTLIBRARIES += libsmartcols.la
|
||
|
libsmartcols_la_SOURCES= \
|
||
|
include/list.h \
|
||
|
\
|
||
|
@@ -17,49 +17,32 @@ libsmartcols_la_SOURCES= \
|
||
|
libsmartcols/src/table.c \
|
||
|
libsmartcols/src/table_print.c \
|
||
|
libsmartcols/src/version.c \
|
||
|
- libsmartcols/src/init.c \
|
||
|
- $(nodist_smartcolsinc_HEADERS)
|
||
|
+ libsmartcols/src/init.c
|
||
|
|
||
|
-nodist_libsmartcols_la_SOURCES = libsmartcols/src/smartcolsP.h
|
||
|
-
|
||
|
-libsmartcols_la_LIBADD = libcommon.la
|
||
|
+libsmartcols_la_LIBADD = $(LDADD) libcommon.la
|
||
|
|
||
|
libsmartcols_la_CFLAGS = \
|
||
|
+ $(AM_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
|
||
|
+EXTRA_libsmartcols_la_DEPENDENCIES = \
|
||
|
+ libsmartcols/src/libsmartcols.sym
|
||
|
|
||
|
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
|
||
|
|
||
|
+EXTRA_DIST += \
|
||
|
+ libsmartcols/src/libsmartcols.sym
|
||
|
|
||
|
# 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); \
|
||
|
+ $(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'); \
|
||
|
diff --git a/libsmartcols/src/cell.c b/libsmartcols/src/cell.c
|
||
|
index ea41f698f..0717a2d09 100644
|
||
|
--- a/libsmartcols/src/cell.c
|
||
|
+++ b/libsmartcols/src/cell.c
|
||
|
@@ -11,7 +11,7 @@
|
||
|
/**
|
||
|
* SECTION: cell
|
||
|
* @title: Cell
|
||
|
- * @short_description: cell API
|
||
|
+ * @short_description: container for your data
|
||
|
*
|
||
|
* 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
|
||
|
@@ -41,8 +41,6 @@
|
||
|
*/
|
||
|
int scols_reset_cell(struct libscols_cell *ce)
|
||
|
{
|
||
|
- assert(ce);
|
||
|
-
|
||
|
if (!ce)
|
||
|
return -EINVAL;
|
||
|
|
||
|
@@ -56,34 +54,21 @@ int scols_reset_cell(struct libscols_cell *ce)
|
||
|
/**
|
||
|
* scols_cell_set_data:
|
||
|
* @ce: a pointer to a struct libscols_cell instance
|
||
|
- * @str: data (used for scols_printtable())
|
||
|
+ * @data: data (used for scols_print_table())
|
||
|
*
|
||
|
- * Stores a copy of the @str in @ce.
|
||
|
+ * Stores a copy of the @str in @ce, the old data are deallocated by free().
|
||
|
*
|
||
|
* Returns: 0, a negative value in case of an error.
|
||
|
*/
|
||
|
-int scols_cell_set_data(struct libscols_cell *ce, const char *str)
|
||
|
+int scols_cell_set_data(struct libscols_cell *ce, const char *data)
|
||
|
{
|
||
|
- 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;
|
||
|
+ return strdup_to_struct_member(ce, data, data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_cell_refer_data:
|
||
|
* @ce: a pointer to a struct libscols_cell instance
|
||
|
- * @str: data (used for scols_printtable())
|
||
|
+ * @data: data (used for scols_print_table())
|
||
|
*
|
||
|
* Adds a reference to @str to @ce. The pointer is deallocated by
|
||
|
* scols_reset_cell() or scols_unref_line(). This function is mostly designed
|
||
|
@@ -92,14 +77,12 @@ int scols_cell_set_data(struct libscols_cell *ce, const char *str)
|
||
|
*
|
||
|
* Returns: 0, a negative value in case of an error.
|
||
|
*/
|
||
|
-int scols_cell_refer_data(struct libscols_cell *ce, char *str)
|
||
|
+int scols_cell_refer_data(struct libscols_cell *ce, char *data)
|
||
|
{
|
||
|
- assert(ce);
|
||
|
-
|
||
|
if (!ce)
|
||
|
return -EINVAL;
|
||
|
free(ce->data);
|
||
|
- ce->data = str;
|
||
|
+ ce->data = data;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -111,7 +94,6 @@ int scols_cell_refer_data(struct libscols_cell *ce, char *str)
|
||
|
*/
|
||
|
const char *scols_cell_get_data(const struct libscols_cell *ce)
|
||
|
{
|
||
|
- assert(ce);
|
||
|
return ce ? ce->data : NULL;
|
||
|
}
|
||
|
|
||
|
@@ -124,8 +106,6 @@ const char *scols_cell_get_data(const struct libscols_cell *ce)
|
||
|
*/
|
||
|
int scols_cell_set_userdata(struct libscols_cell *ce, void *data)
|
||
|
{
|
||
|
- assert(ce);
|
||
|
-
|
||
|
if (!ce)
|
||
|
return -EINVAL;
|
||
|
ce->userdata = data;
|
||
|
@@ -140,7 +120,7 @@ int scols_cell_set_userdata(struct libscols_cell *ce, void *data)
|
||
|
*/
|
||
|
void *scols_cell_get_userdata(struct libscols_cell *ce)
|
||
|
{
|
||
|
- return ce ? ce->userdata : NULL;
|
||
|
+ return ce->userdata;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -178,7 +158,7 @@ int scols_cmpstr_cells(struct libscols_cell *a,
|
||
|
/**
|
||
|
* scols_cell_set_color:
|
||
|
* @ce: a pointer to a struct libscols_cell instance
|
||
|
- * @color: ESC sequence
|
||
|
+ * @color: color name or ESC sequence
|
||
|
*
|
||
|
* Set the color of @ce to @color.
|
||
|
*
|
||
|
@@ -186,32 +166,70 @@ int scols_cmpstr_cells(struct libscols_cell *a,
|
||
|
*/
|
||
|
int scols_cell_set_color(struct libscols_cell *ce, const char *color)
|
||
|
{
|
||
|
- char *p = NULL;
|
||
|
+ if (color && isalpha(*color)) {
|
||
|
+ color = color_sequence_from_colorname(color);
|
||
|
+ if (!color)
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+ return strdup_to_struct_member(ce, color, color);
|
||
|
+}
|
||
|
|
||
|
- assert(ce);
|
||
|
+/**
|
||
|
+ * 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)
|
||
|
+{
|
||
|
+ return ce->color;
|
||
|
+}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_cell_set_flags:
|
||
|
+ * @ce: a pointer to a struct libscols_cell instance
|
||
|
+ * @flags: SCOLS_CELL_FL_* flags
|
||
|
+ *
|
||
|
+ * Note that cells in the table are always aligned by column flags. The cell
|
||
|
+ * flags are used for table title only (now).
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ */
|
||
|
+int scols_cell_set_flags(struct libscols_cell *ce, int flags)
|
||
|
+{
|
||
|
if (!ce)
|
||
|
return -EINVAL;
|
||
|
- if (color) {
|
||
|
- p = strdup(color);
|
||
|
- if (!p)
|
||
|
- return -ENOMEM;
|
||
|
- }
|
||
|
- free(ce->color);
|
||
|
- ce->color = p;
|
||
|
+ ce->flags = flags;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
- * scols_cell_get_color:
|
||
|
+ * scols_cell_get_flags:
|
||
|
* @ce: a pointer to a struct libscols_cell instance
|
||
|
*
|
||
|
- * Returns: the current color of @ce.
|
||
|
+ * Returns: the current flags
|
||
|
*/
|
||
|
-const char *scols_cell_get_color(const struct libscols_cell *ce)
|
||
|
+int scols_cell_get_flags(const struct libscols_cell *ce)
|
||
|
{
|
||
|
- assert(ce);
|
||
|
- return ce ? ce->color : NULL;
|
||
|
+ return ce->flags;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_cell_get_alignment:
|
||
|
+ * @ce: a pointer to a struct libscols_cell instance
|
||
|
+ *
|
||
|
+ * Since: 2.30
|
||
|
+ *
|
||
|
+ * Returns: SCOLS_CELL_FL_{RIGHT,CELNTER,LEFT}
|
||
|
+ */
|
||
|
+int scols_cell_get_alignment(const struct libscols_cell *ce)
|
||
|
+{
|
||
|
+ if (ce->flags & SCOLS_CELL_FL_RIGHT)
|
||
|
+ return SCOLS_CELL_FL_RIGHT;
|
||
|
+ else if (ce->flags & SCOLS_CELL_FL_CENTER)
|
||
|
+ return SCOLS_CELL_FL_CENTER;
|
||
|
+
|
||
|
+ return SCOLS_CELL_FL_LEFT; /* default */
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -228,15 +246,12 @@ int scols_cell_copy_content(struct libscols_cell *dest,
|
||
|
{
|
||
|
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));
|
||
|
+ DBG(CELL, ul_debugobj(src, "copy"));
|
||
|
return rc;
|
||
|
}
|
||
|
diff --git a/libsmartcols/src/column.c b/libsmartcols/src/column.c
|
||
|
index d1d10a6d0..e9d6dc404 100644
|
||
|
--- a/libsmartcols/src/column.c
|
||
|
+++ b/libsmartcols/src/column.c
|
||
|
@@ -11,7 +11,7 @@
|
||
|
/**
|
||
|
* SECTION: column
|
||
|
* @title: Column
|
||
|
- * @short_description: column API
|
||
|
+ * @short_description: defines output columns formats, headers, etc.
|
||
|
*
|
||
|
* An API to access and modify per-column data and information.
|
||
|
*/
|
||
|
@@ -22,6 +22,8 @@
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
+#include "mbsalign.h"
|
||
|
+
|
||
|
#include "smartcolsP.h"
|
||
|
|
||
|
/**
|
||
|
@@ -29,7 +31,7 @@
|
||
|
*
|
||
|
* Allocates space for a new column.
|
||
|
*
|
||
|
- * Returns: a pointer to a new struct libscols_cell instance, NULL in case of an ENOMEM error.
|
||
|
+ * Returns: a pointer to a new struct libscols_column instance, NULL in case of an ENOMEM error.
|
||
|
*/
|
||
|
struct libscols_column *scols_new_column(void)
|
||
|
{
|
||
|
@@ -70,6 +72,8 @@ void scols_unref_column(struct libscols_column *cl)
|
||
|
list_del(&cl->cl_columns);
|
||
|
scols_reset_cell(&cl->header);
|
||
|
free(cl->color);
|
||
|
+ free(cl->safechars);
|
||
|
+ free(cl->pending_data_buf);
|
||
|
free(cl);
|
||
|
}
|
||
|
}
|
||
|
@@ -86,14 +90,13 @@ 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));
|
||
|
+ DBG(COL, ul_debugobj(cl, "copy"));
|
||
|
|
||
|
if (scols_column_set_color(ret, cl->color))
|
||
|
goto err;
|
||
|
@@ -119,14 +122,12 @@ err:
|
||
|
* @cl: a pointer to a struct libscols_column instance
|
||
|
* @whint: a width hint
|
||
|
*
|
||
|
- * Sets the width hint of column @cl to @whint.
|
||
|
+ * Sets the width hint of column @cl to @whint. See scols_table_new_column().
|
||
|
*
|
||
|
* 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;
|
||
|
|
||
|
@@ -140,10 +141,9 @@ int scols_column_set_whint(struct libscols_column *cl, double whint)
|
||
|
*
|
||
|
* Returns: The width hint of column @cl, a negative value in case of an error.
|
||
|
*/
|
||
|
-double scols_column_get_whint(struct libscols_column *cl)
|
||
|
+double scols_column_get_whint(const struct libscols_column *cl)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
- return cl ? cl->width_hint : -EINVAL;
|
||
|
+ return cl->width_hint;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -157,25 +157,78 @@ double scols_column_get_whint(struct libscols_column *cl)
|
||
|
*/
|
||
|
int scols_column_set_flags(struct libscols_column *cl, int flags)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
-
|
||
|
if (!cl)
|
||
|
return -EINVAL;
|
||
|
|
||
|
+ if (cl->table) {
|
||
|
+ if (!(cl->flags & SCOLS_FL_TREE) && (flags & SCOLS_FL_TREE))
|
||
|
+ cl->table->ntreecols++;
|
||
|
+ else if ((cl->flags & SCOLS_FL_TREE) && !(flags & SCOLS_FL_TREE))
|
||
|
+ cl->table->ntreecols--;
|
||
|
+ }
|
||
|
+
|
||
|
cl->flags = flags;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_column_set_json_type:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ * @type: SCOLS_JSON_* type
|
||
|
+ *
|
||
|
+ * Sets the type used for JSON formatting, the default is SCOLS_JSON_STRING.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.33
|
||
|
+ */
|
||
|
+int scols_column_set_json_type(struct libscols_column *cl, int type)
|
||
|
+{
|
||
|
+ if (!cl)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ cl->json_type = type;
|
||
|
+ return 0;
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_column_get_json_type:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ *
|
||
|
+ * Note that SCOLS_JSON_BOOLEAN interprets NULL, empty strings, '0', 'N' and
|
||
|
+ * 'n' as "false"; and everything else as "true".
|
||
|
+ *
|
||
|
+ * Returns: JSON type used for formatting or a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.33
|
||
|
+ */
|
||
|
+int scols_column_get_json_type(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return cl ? cl->json_type : -EINVAL;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_column_get_table:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ *
|
||
|
+ * Returns: pointer to the table where columns is used
|
||
|
+ */
|
||
|
+struct libscols_table *scols_column_get_table(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return cl->table;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* 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)
|
||
|
+int scols_column_get_flags(const struct libscols_column *cl)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
- return cl ? cl->flags : -EINVAL;
|
||
|
+ return cl->flags;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -187,14 +240,13 @@ int scols_column_get_flags(struct libscols_column *cl)
|
||
|
*/
|
||
|
struct libscols_cell *scols_column_get_header(struct libscols_column *cl)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
- return cl ? &cl->header : NULL;
|
||
|
+ return &cl->header;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_column_set_color:
|
||
|
* @cl: a pointer to a struct libscols_column instance
|
||
|
- * @color: ESC sequence
|
||
|
+ * @color: color name or ESC sequence
|
||
|
*
|
||
|
* The default color for data cells and column header.
|
||
|
*
|
||
|
@@ -208,20 +260,12 @@ struct libscols_cell *scols_column_get_header(struct libscols_column *cl)
|
||
|
*/
|
||
|
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;
|
||
|
+ if (color && isalpha(*color)) {
|
||
|
+ color = color_sequence_from_colorname(color);
|
||
|
+ if (!color)
|
||
|
+ return -EINVAL;
|
||
|
}
|
||
|
-
|
||
|
- free(cl->color);
|
||
|
- cl->color = p;
|
||
|
- return 0;
|
||
|
+ return strdup_to_struct_member(cl, color, color);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -230,12 +274,79 @@ int scols_column_set_color(struct libscols_column *cl, const char *color)
|
||
|
*
|
||
|
* Returns: The current color setting of the column @cl.
|
||
|
*/
|
||
|
-const char *scols_column_get_color(struct libscols_column *cl)
|
||
|
+const char *scols_column_get_color(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return cl->color;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_wrapnl_nextchunk:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ * @data: string
|
||
|
+ * @userdata: callback private data
|
||
|
+ *
|
||
|
+ * This is built-in function for scols_column_set_wrapfunc(). This function
|
||
|
+ * terminates the current chunk by \0 and returns pointer to the begin of
|
||
|
+ * the next chunk. The chunks are based on \n.
|
||
|
+ *
|
||
|
+ * For example for data "AAA\nBBB\nCCC" the next chunk is "BBB".
|
||
|
+ *
|
||
|
+ * Returns: next chunk
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+char *scols_wrapnl_nextchunk(const struct libscols_column *cl __attribute__((unused)),
|
||
|
+ char *data,
|
||
|
+ void *userdata __attribute__((unused)))
|
||
|
{
|
||
|
- assert(cl);
|
||
|
- return cl ? cl->color : NULL;
|
||
|
+ char *p = data ? strchr(data, '\n') : NULL;
|
||
|
+
|
||
|
+ if (p) {
|
||
|
+ *p = '\0';
|
||
|
+ return p + 1;
|
||
|
+ }
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_wrapnl_chunksize:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ * @data: string
|
||
|
+ * @userdata: callback private data
|
||
|
+ *
|
||
|
+ * Analyzes @data and returns size of the largest chunk. The chunks are based
|
||
|
+ * on \n. For example for data "AAA\nBBB\nCCCC" the largest chunk size is 4.
|
||
|
+ *
|
||
|
+ * Note that the size has to be based on number of terminal cells rather than
|
||
|
+ * bytes to support multu-byte output.
|
||
|
+ *
|
||
|
+ * Returns: size of the largest chunk.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+size_t scols_wrapnl_chunksize(const struct libscols_column *cl __attribute__((unused)),
|
||
|
+ const char *data,
|
||
|
+ void *userdata __attribute__((unused)))
|
||
|
+{
|
||
|
+ size_t sum = 0;
|
||
|
+
|
||
|
+ while (data && *data) {
|
||
|
+ const char *p;
|
||
|
+ size_t sz;
|
||
|
+
|
||
|
+ p = strchr(data, '\n');
|
||
|
+ if (p) {
|
||
|
+ sz = mbs_safe_nwidth(data, p - data, NULL);
|
||
|
+ p++;
|
||
|
+ } else
|
||
|
+ sz = mbs_safe_width(data);
|
||
|
+
|
||
|
+ sum = max(sum, sz);
|
||
|
+ data = p;
|
||
|
+ }
|
||
|
+
|
||
|
+ return sum;
|
||
|
+}
|
||
|
|
||
|
/**
|
||
|
* scols_column_set_cmpfunc:
|
||
|
@@ -251,7 +362,6 @@ int scols_column_set_cmpfunc(struct libscols_column *cl,
|
||
|
void *),
|
||
|
void *data)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
if (!cl)
|
||
|
return -EINVAL;
|
||
|
|
||
|
@@ -261,19 +371,114 @@ int scols_column_set_cmpfunc(struct libscols_column *cl,
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
- * scols_column_is_trunc:
|
||
|
+ * scols_column_set_wrapfunc:
|
||
|
* @cl: a pointer to a struct libscols_column instance
|
||
|
+ * @wrap_chunksize: function to return size of the largest chink of data
|
||
|
+ * @wrap_nextchunk: function to return next zero terminated data
|
||
|
+ * @userdata: optional stuff for callbacks
|
||
|
*
|
||
|
- * Gets the value of @cl's flag trunc.
|
||
|
+ * Extends SCOLS_FL_WRAP and allows to set custom wrap function. The default
|
||
|
+ * is to wrap by column size, but you can create functions to wrap for example
|
||
|
+ * after \n or after words, etc.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
*
|
||
|
- * Returns: trunc flag value, negative value in case of an error.
|
||
|
+ * Since: 2.29
|
||
|
*/
|
||
|
-int scols_column_is_trunc(struct libscols_column *cl)
|
||
|
+int scols_column_set_wrapfunc(struct libscols_column *cl,
|
||
|
+ size_t (*wrap_chunksize)(const struct libscols_column *,
|
||
|
+ const char *,
|
||
|
+ void *),
|
||
|
+ char * (*wrap_nextchunk)(const struct libscols_column *,
|
||
|
+ char *,
|
||
|
+ void *),
|
||
|
+ void *userdata)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
if (!cl)
|
||
|
return -EINVAL;
|
||
|
- return cl->flags & SCOLS_FL_TRUNC;
|
||
|
+
|
||
|
+ cl->wrap_nextchunk = wrap_nextchunk;
|
||
|
+ cl->wrap_chunksize = wrap_chunksize;
|
||
|
+ cl->wrapfunc_data = userdata;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_column_set_safechars:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ * @safe: safe characters (e.g. "\n\t")
|
||
|
+ *
|
||
|
+ * Use for bytes you don't want to encode on output. This is for example
|
||
|
+ * necessary if you want to use custom wrap function based on \n, in this case
|
||
|
+ * you have to set "\n" as a safe char.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_column_set_safechars(struct libscols_column *cl, const char *safe)
|
||
|
+{
|
||
|
+ return strdup_to_struct_member(cl, safechars, safe);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_column_get_safechars:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ *
|
||
|
+ * Returns: safe chars
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+const char *scols_column_get_safechars(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return cl->safechars;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_column_get_width:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ *
|
||
|
+ * Important note: the column width is unknown until library starts printing
|
||
|
+ * (width is calculated before printing). The function is usable for example in
|
||
|
+ * nextchunk() callback specified by scols_column_set_wrapfunc().
|
||
|
+ *
|
||
|
+ * See also scols_column_get_whint(), it returns wanted size (!= final size).
|
||
|
+ *
|
||
|
+ * Returns: column width
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+size_t scols_column_get_width(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return cl->width;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_column_is_hidden:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ *
|
||
|
+ * Gets the value of @cl's flag hidden.
|
||
|
+ *
|
||
|
+ * Returns: 0 or 1
|
||
|
+ *
|
||
|
+ * Since: 2.27
|
||
|
+ */
|
||
|
+int scols_column_is_hidden(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return cl->flags & SCOLS_FL_HIDDEN ? 1 : 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_column_is_trunc:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ *
|
||
|
+ * Gets the value of @cl's flag trunc.
|
||
|
+ *
|
||
|
+ * Returns: 0 or 1
|
||
|
+ */
|
||
|
+int scols_column_is_trunc(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return cl->flags & SCOLS_FL_TRUNC ? 1 : 0;
|
||
|
}
|
||
|
/**
|
||
|
* scols_column_is_tree:
|
||
|
@@ -281,14 +486,11 @@ int scols_column_is_trunc(struct libscols_column *cl)
|
||
|
*
|
||
|
* Gets the value of @cl's flag tree.
|
||
|
*
|
||
|
- * Returns: tree flag value, negative value in case of an error.
|
||
|
+ * Returns: 0 or 1
|
||
|
*/
|
||
|
-int scols_column_is_tree(struct libscols_column *cl)
|
||
|
+int scols_column_is_tree(const struct libscols_column *cl)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
- if (!cl)
|
||
|
- return -EINVAL;
|
||
|
- return cl->flags & SCOLS_FL_TREE;
|
||
|
+ return cl->flags & SCOLS_FL_TREE ? 1 : 0;
|
||
|
}
|
||
|
/**
|
||
|
* scols_column_is_right:
|
||
|
@@ -296,14 +498,11 @@ int scols_column_is_tree(struct libscols_column *cl)
|
||
|
*
|
||
|
* Gets the value of @cl's flag right.
|
||
|
*
|
||
|
- * Returns: right flag value, negative value in case of an error.
|
||
|
+ * Returns: 0 or 1
|
||
|
*/
|
||
|
-int scols_column_is_right(struct libscols_column *cl)
|
||
|
+int scols_column_is_right(const struct libscols_column *cl)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
- if (!cl)
|
||
|
- return -EINVAL;
|
||
|
- return cl->flags & SCOLS_FL_RIGHT;
|
||
|
+ return cl->flags & SCOLS_FL_RIGHT ? 1 : 0;
|
||
|
}
|
||
|
/**
|
||
|
* scols_column_is_strict_width:
|
||
|
@@ -311,14 +510,11 @@ int scols_column_is_right(struct libscols_column *cl)
|
||
|
*
|
||
|
* Gets the value of @cl's flag strict_width.
|
||
|
*
|
||
|
- * Returns: strict_width flag value, negative value in case of an error.
|
||
|
+ * Returns: 0 or 1
|
||
|
*/
|
||
|
-int scols_column_is_strict_width(struct libscols_column *cl)
|
||
|
+int scols_column_is_strict_width(const struct libscols_column *cl)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
- if (!cl)
|
||
|
- return -EINVAL;
|
||
|
- return cl->flags & SCOLS_FL_STRICTWIDTH;
|
||
|
+ return cl->flags & SCOLS_FL_STRICTWIDTH ? 1 : 0;
|
||
|
}
|
||
|
/**
|
||
|
* scols_column_is_noextremes:
|
||
|
@@ -326,12 +522,37 @@ int scols_column_is_strict_width(struct libscols_column *cl)
|
||
|
*
|
||
|
* Gets the value of @cl's flag no_extremes.
|
||
|
*
|
||
|
- * Returns: no_extremes flag value, negative value in case of an error.
|
||
|
+ * Returns: 0 or 1
|
||
|
*/
|
||
|
-int scols_column_is_noextremes(struct libscols_column *cl)
|
||
|
+int scols_column_is_noextremes(const struct libscols_column *cl)
|
||
|
{
|
||
|
- assert(cl);
|
||
|
- if (!cl)
|
||
|
- return -EINVAL;
|
||
|
- return cl->flags & SCOLS_FL_NOEXTREMES;
|
||
|
+ return cl->flags & SCOLS_FL_NOEXTREMES ? 1 : 0;
|
||
|
+}
|
||
|
+/**
|
||
|
+ * scols_column_is_wrap:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ *
|
||
|
+ * Gets the value of @cl's flag wrap.
|
||
|
+ *
|
||
|
+ * Returns: 0 or 1
|
||
|
+ *
|
||
|
+ * Since: 2.28
|
||
|
+ */
|
||
|
+int scols_column_is_wrap(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return cl->flags & SCOLS_FL_WRAP ? 1 : 0;
|
||
|
+}
|
||
|
+/**
|
||
|
+ * scols_column_is_customwrap:
|
||
|
+ * @cl: a pointer to a struct libscols_column instance
|
||
|
+ *
|
||
|
+ * Returns: 0 or 1
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_column_is_customwrap(const struct libscols_column *cl)
|
||
|
+{
|
||
|
+ return (cl->flags & SCOLS_FL_WRAP)
|
||
|
+ && cl->wrap_chunksize
|
||
|
+ && cl->wrap_nextchunk ? 1 : 0;
|
||
|
}
|
||
|
diff --git a/libsmartcols/src/iter.c b/libsmartcols/src/iter.c
|
||
|
index 72c7865a8..91cc08009 100644
|
||
|
--- a/libsmartcols/src/iter.c
|
||
|
+++ b/libsmartcols/src/iter.c
|
||
|
@@ -68,7 +68,7 @@ void scols_reset_iter(struct libscols_iter *itr, int direction)
|
||
|
*
|
||
|
* Returns: SCOLS_INTER_{FOR,BACK}WARD
|
||
|
*/
|
||
|
-int scols_iter_get_direction(struct libscols_iter *itr)
|
||
|
+int scols_iter_get_direction(const struct libscols_iter *itr)
|
||
|
{
|
||
|
return itr->direction;
|
||
|
}
|
||
|
diff --git a/libsmartcols/src/libsmartcols.h.in b/libsmartcols/src/libsmartcols.h.in
|
||
|
index e61256022..f8be0bc04 100644
|
||
|
--- a/libsmartcols/src/libsmartcols.h.in
|
||
|
+++ b/libsmartcols/src/libsmartcols.h.in
|
||
|
@@ -83,12 +83,33 @@ enum {
|
||
|
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*/
|
||
|
+ SCOLS_FL_HIDDEN = (1 << 5), /* maintain data, but don't print */
|
||
|
+ SCOLS_FL_WRAP = (1 << 6) /* wrap long lines to multi-line cells */
|
||
|
+};
|
||
|
+
|
||
|
+/*
|
||
|
+ * Column JSON types
|
||
|
+ */
|
||
|
+enum {
|
||
|
+ SCOLS_JSON_STRING = 0, /* default */
|
||
|
+ SCOLS_JSON_NUMBER = 1,
|
||
|
+ SCOLS_JSON_BOOLEAN = 2
|
||
|
+};
|
||
|
+
|
||
|
+/*
|
||
|
+ * Cell flags, see scols_cell_set_flags() before use
|
||
|
+ */
|
||
|
+enum {
|
||
|
+ /* alignment evaluated in order: right,center,left */
|
||
|
+ SCOLS_CELL_FL_LEFT = 0,
|
||
|
+ SCOLS_CELL_FL_CENTER = (1 << 0),
|
||
|
+ SCOLS_CELL_FL_RIGHT = (1 << 1)
|
||
|
};
|
||
|
|
||
|
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);
|
||
|
+extern int scols_iter_get_direction(const struct libscols_iter *itr);
|
||
|
|
||
|
/* init.c */
|
||
|
extern void scols_init_debug(int mask);
|
||
|
@@ -101,50 +122,78 @@ extern int scols_get_library_version(const char **ver_string);
|
||
|
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);
|
||
|
+extern struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sy);
|
||
|
+extern int scols_symbols_set_branch(struct libscols_symbols *sy, const char *str);
|
||
|
+extern int scols_symbols_set_vertical(struct libscols_symbols *sy, const char *str);
|
||
|
+extern int scols_symbols_set_right(struct libscols_symbols *sy, const char *str);
|
||
|
+extern int scols_symbols_set_title_padding(struct libscols_symbols *sy, const char *str);
|
||
|
+extern int scols_symbols_set_cell_padding(struct libscols_symbols *sy, 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 int scols_cell_set_data(struct libscols_cell *ce, const char *data);
|
||
|
+extern int scols_cell_refer_data(struct libscols_cell *ce, char *data);
|
||
|
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 int scols_cell_set_flags(struct libscols_cell *ce, int flags);
|
||
|
+extern int scols_cell_get_flags(const struct libscols_cell *ce);
|
||
|
+extern int scols_cell_get_alignment(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_is_tree(const struct libscols_column *cl);
|
||
|
+extern int scols_column_is_trunc(const struct libscols_column *cl);
|
||
|
+extern int scols_column_is_right(const struct libscols_column *cl);
|
||
|
+extern int scols_column_is_strict_width(const struct libscols_column *cl);
|
||
|
+extern int scols_column_is_hidden(const struct libscols_column *cl);
|
||
|
+extern int scols_column_is_noextremes(const struct libscols_column *cl);
|
||
|
+extern int scols_column_is_wrap(const struct libscols_column *cl);
|
||
|
+extern int scols_column_is_customwrap(const struct libscols_column *cl);
|
||
|
+
|
||
|
+extern size_t scols_column_get_width(const struct libscols_column *cl);
|
||
|
+
|
||
|
+extern int scols_column_set_safechars(struct libscols_column *cl, const char *safe);
|
||
|
+extern const char *scols_column_get_safechars(const struct libscols_column *cl);
|
||
|
+
|
||
|
+extern int scols_column_set_json_type(struct libscols_column *cl, int type);
|
||
|
+extern int scols_column_get_json_type(const 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 int scols_column_get_flags(const 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 double scols_column_get_whint(const 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 const char *scols_column_get_color(const struct libscols_column *cl);
|
||
|
+extern struct libscols_table *scols_column_get_table(const 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);
|
||
|
|
||
|
+extern int scols_column_set_wrapfunc(struct libscols_column *cl,
|
||
|
+ size_t (*wrap_chunksize)(const struct libscols_column *,
|
||
|
+ const char *, void *),
|
||
|
+ char * (*wrap_nextchunk)(const struct libscols_column *,
|
||
|
+ char *, void *),
|
||
|
+ void *userdata);
|
||
|
+
|
||
|
+extern char *scols_wrapnl_nextchunk(const struct libscols_column *cl, char *data, void *userdata);
|
||
|
+extern size_t scols_wrapnl_chunksize(const struct libscols_column *cl, const char *data, void *userdata);
|
||
|
+
|
||
|
/* line.c */
|
||
|
extern struct libscols_line *scols_new_line(void);
|
||
|
extern void scols_ref_line(struct libscols_line *ln);
|
||
|
@@ -156,36 +205,52 @@ 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_is_ancestor(struct libscols_line *ln, struct libscols_line *parent);
|
||
|
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 struct libscols_line *scols_line_get_parent(const 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 const char *scols_line_get_color(const struct libscols_line *ln);
|
||
|
+extern size_t scols_line_get_ncells(const 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);
|
||
|
+extern int scols_line_set_column_data(struct libscols_line *ln, struct libscols_column *cl, const char *data);
|
||
|
+extern int scols_line_refer_column_data(struct libscols_line *ln, struct libscols_column *cl, char *data);
|
||
|
+extern struct libscols_line *scols_copy_line(const 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_colors_wanted(const struct libscols_table *tb);
|
||
|
+extern int scols_table_set_name(struct libscols_table *tb, const char *name);
|
||
|
+extern const char *scols_table_get_name(const struct libscols_table *tb);
|
||
|
+extern struct libscols_cell *scols_table_get_title(struct libscols_table *tb);
|
||
|
+extern int scols_table_is_raw(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_ascii(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_json(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_noheadings(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_header_repeat(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_empty(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_export(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_maxout(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_nowrap(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_nolinesep(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_tree(const struct libscols_table *tb);
|
||
|
+extern int scols_table_is_noencoding(const 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_json(struct libscols_table *tb, int enable);
|
||
|
extern int scols_table_enable_noheadings(struct libscols_table *tb, int enable);
|
||
|
+extern int scols_table_enable_header_repeat(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_enable_nowrap(struct libscols_table *tb, int enable);
|
||
|
+extern int scols_table_enable_nolinesep(struct libscols_table *tb, int enable);
|
||
|
+extern int scols_table_enable_noencoding(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);
|
||
|
@@ -196,12 +261,13 @@ 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 int scols_table_move_column(struct libscols_table *tb, struct libscols_column *pre, struct libscols_column *cl);
|
||
|
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 const char *scols_table_get_column_separator(const struct libscols_table *tb);
|
||
|
+extern const char *scols_table_get_line_separator(const struct libscols_table *tb);
|
||
|
+extern size_t scols_table_get_ncols(const struct libscols_table *tb);
|
||
|
+extern size_t scols_table_get_nlines(const 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);
|
||
|
@@ -211,17 +277,43 @@ extern struct libscols_line *scols_table_new_line(struct libscols_table *tb, str
|
||
|
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_default_symbols(struct libscols_table *tb);
|
||
|
+extern struct libscols_symbols *scols_table_get_symbols(const struct libscols_table *tb);
|
||
|
|
||
|
extern int scols_table_set_stream(struct libscols_table *tb, FILE *stream);
|
||
|
-extern FILE *scols_table_get_stream(struct libscols_table *tb);
|
||
|
+extern FILE *scols_table_get_stream(const 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);
|
||
|
+extern int scols_sort_table_by_tree(struct libscols_table *tb);
|
||
|
+/*
|
||
|
+ *
|
||
|
+ */
|
||
|
+enum {
|
||
|
+ SCOLS_TERMFORCE_AUTO = 0,
|
||
|
+ SCOLS_TERMFORCE_NEVER,
|
||
|
+ SCOLS_TERMFORCE_ALWAYS
|
||
|
+};
|
||
|
+extern int scols_table_set_termforce(struct libscols_table *tb, int force);
|
||
|
+extern int scols_table_get_termforce(const struct libscols_table *tb);
|
||
|
+extern int scols_table_set_termwidth(struct libscols_table *tb, size_t width);
|
||
|
+extern size_t scols_table_get_termwidth(const struct libscols_table *tb);
|
||
|
+extern int scols_table_set_termheight(struct libscols_table *tb, size_t height);
|
||
|
+extern size_t scols_table_get_termheight(const struct libscols_table *tb);
|
||
|
+
|
||
|
|
||
|
/* 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);
|
||
|
|
||
|
+extern int scols_table_print_range( struct libscols_table *tb,
|
||
|
+ struct libscols_line *start,
|
||
|
+ struct libscols_line *end);
|
||
|
+extern int scols_table_print_range_to_string( struct libscols_table *tb,
|
||
|
+ struct libscols_line *start,
|
||
|
+ struct libscols_line *end,
|
||
|
+ char **data);
|
||
|
+
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
diff --git a/libsmartcols/src/libsmartcols.sym b/libsmartcols/src/libsmartcols.sym
|
||
|
index a4de524f4..331a55554 100644
|
||
|
--- a/libsmartcols/src/libsmartcols.sym
|
||
|
+++ b/libsmartcols/src/libsmartcols.sym
|
||
|
@@ -1,5 +1,7 @@
|
||
|
/*
|
||
|
* symbols since util-linux 2.25
|
||
|
+ *
|
||
|
+ * Copyright (C) 2014-2016 Karel Zak <kzak@redhat.com>
|
||
|
*/
|
||
|
SMARTCOLS_2.25 {
|
||
|
global:
|
||
|
@@ -110,3 +112,73 @@ global:
|
||
|
local:
|
||
|
*;
|
||
|
};
|
||
|
+
|
||
|
+SMARTCOLS_2.27 {
|
||
|
+global:
|
||
|
+ scols_column_is_hidden;
|
||
|
+ scols_table_enable_json;
|
||
|
+ scols_table_is_json;
|
||
|
+ scols_table_set_name;
|
||
|
+} SMARTCOLS_2.25;
|
||
|
+
|
||
|
+SMARTCOLS_2.28 {
|
||
|
+global:
|
||
|
+ scols_column_is_wrap;
|
||
|
+ scols_line_refer_column_data;
|
||
|
+ scols_line_set_column_data;
|
||
|
+ scols_symbols_set_title_padding;
|
||
|
+ scols_table_enable_nowrap;
|
||
|
+ scols_table_get_title;
|
||
|
+ scols_cell_get_flags;
|
||
|
+ scols_cell_set_flags;
|
||
|
+ scols_table_print_range;
|
||
|
+ scols_table_print_range_to_string;
|
||
|
+ scols_table_enable_nolinesep;
|
||
|
+} SMARTCOLS_2.27;
|
||
|
+
|
||
|
+SMARTCOLS_2.29 {
|
||
|
+global:
|
||
|
+ scols_column_get_safechars;
|
||
|
+ scols_column_get_table;
|
||
|
+ scols_column_get_width;
|
||
|
+ scols_column_is_customwrap;
|
||
|
+ scols_column_set_safechars;
|
||
|
+ scols_column_set_wrapfunc;
|
||
|
+ scols_symbols_set_cell_padding;
|
||
|
+ scols_table_get_name;
|
||
|
+ scols_table_get_symbols;
|
||
|
+ scols_table_get_termforce;
|
||
|
+ scols_table_get_termwidth;
|
||
|
+ scols_table_is_nolinesep;
|
||
|
+ scols_table_is_nowrap;
|
||
|
+ scols_table_set_default_symbols;
|
||
|
+ scols_table_set_termforce;
|
||
|
+ scols_table_set_termwidth;
|
||
|
+ scols_wrapnl_chunksize;
|
||
|
+ scols_wrapnl_nextchunk;
|
||
|
+} SMARTCOLS_2.28;
|
||
|
+
|
||
|
+
|
||
|
+SMARTCOLS_2.30 {
|
||
|
+global:
|
||
|
+ scols_cell_get_alignment;
|
||
|
+ scols_table_move_column;
|
||
|
+ scols_sort_table_by_tree;
|
||
|
+ scols_line_is_ancestor;
|
||
|
+} SMARTCOLS_2.29;
|
||
|
+
|
||
|
+
|
||
|
+SMARTCOLS_2.31 {
|
||
|
+ scols_table_set_termheight;
|
||
|
+ scols_table_get_termheight;
|
||
|
+ scols_table_is_header_repeat;
|
||
|
+ scols_table_enable_header_repeat;
|
||
|
+ scols_table_enable_noencoding;
|
||
|
+ scols_table_is_noencoding;
|
||
|
+} SMARTCOLS_2.30;
|
||
|
+
|
||
|
+
|
||
|
+SMARTCOLS_2.33 {
|
||
|
+ scols_column_set_json_type;
|
||
|
+ scols_column_get_json_type;
|
||
|
+} SMARTCOLS_2.31;
|
||
|
diff --git a/libsmartcols/src/line.c b/libsmartcols/src/line.c
|
||
|
index debfeab78..60be2c135 100644
|
||
|
--- a/libsmartcols/src/line.c
|
||
|
+++ b/libsmartcols/src/line.c
|
||
|
@@ -11,7 +11,7 @@
|
||
|
/**
|
||
|
* SECTION: line
|
||
|
* @title: Line
|
||
|
- * @short_description: line API
|
||
|
+ * @short_description: cells container, also keeps tree (parent->child) information
|
||
|
*
|
||
|
* An API to access and modify per-line data and information.
|
||
|
*/
|
||
|
@@ -71,7 +71,6 @@ void scols_ref_line(struct libscols_line *ln)
|
||
|
*/
|
||
|
void scols_unref_line(struct libscols_line *ln)
|
||
|
{
|
||
|
-
|
||
|
if (ln && --ln->refcount <= 0) {
|
||
|
DBG(CELL, ul_debugobj(ln, "dealloc"));
|
||
|
list_del(&ln->ln_lines);
|
||
|
@@ -122,8 +121,6 @@ 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)
|
||
|
@@ -149,6 +146,35 @@ int scols_line_alloc_cells(struct libscols_line *ln, size_t n)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+int scols_line_move_cells(struct libscols_line *ln, size_t newn, size_t oldn)
|
||
|
+{
|
||
|
+ struct libscols_cell ce;
|
||
|
+
|
||
|
+ if (!ln || newn >= ln->ncells || oldn >= ln->ncells)
|
||
|
+ return -EINVAL;
|
||
|
+ if (oldn == newn)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ DBG(LINE, ul_debugobj(ln, "move cells[%zu] -> cells[%zu]", oldn, newn));
|
||
|
+
|
||
|
+ /* remember data from old position */
|
||
|
+ memcpy(&ce, &ln->cells[oldn], sizeof(struct libscols_cell));
|
||
|
+
|
||
|
+ /* remove old position (move data behind oldn to oldn) */
|
||
|
+ if (oldn + 1 < ln->ncells)
|
||
|
+ memmove(ln->cells + oldn, ln->cells + oldn + 1,
|
||
|
+ (ln->ncells - oldn - 1) * sizeof(struct libscols_cell));
|
||
|
+
|
||
|
+ /* create a space for new position */
|
||
|
+ if (newn + 1 < ln->ncells)
|
||
|
+ memmove(ln->cells + newn + 1, ln->cells + newn,
|
||
|
+ (ln->ncells - newn - 1) * sizeof(struct libscols_cell));
|
||
|
+
|
||
|
+ /* copy original data to new position */
|
||
|
+ memcpy(&ln->cells[newn], &ce, sizeof(struct libscols_cell));
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_line_set_userdata:
|
||
|
* @ln: a pointer to a struct libscols_line instance
|
||
|
@@ -160,7 +186,6 @@ int scols_line_alloc_cells(struct libscols_line *ln, size_t n)
|
||
|
*/
|
||
|
int scols_line_set_userdata(struct libscols_line *ln, void *data)
|
||
|
{
|
||
|
- assert(ln);
|
||
|
if (!ln)
|
||
|
return -EINVAL;
|
||
|
ln->userdata = data;
|
||
|
@@ -171,12 +196,11 @@ int scols_line_set_userdata(struct libscols_line *ln, void *data)
|
||
|
* scols_line_get_userdata:
|
||
|
* @ln: a pointer to a struct libscols_line instance
|
||
|
*
|
||
|
- * Returns: 0, a negative value in case of an error.
|
||
|
+ * Returns: user data
|
||
|
*/
|
||
|
void *scols_line_get_userdata(struct libscols_line *ln)
|
||
|
{
|
||
|
- assert(ln);
|
||
|
- return ln ? ln->userdata : NULL;
|
||
|
+ return ln->userdata;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -190,13 +214,10 @@ void *scols_line_get_userdata(struct libscols_line *ln)
|
||
|
*/
|
||
|
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));
|
||
|
+ DBG(LINE, ul_debugobj(ln, "remove child"));
|
||
|
|
||
|
list_del_init(&child->ln_children);
|
||
|
child->parent = NULL;
|
||
|
@@ -217,26 +238,22 @@ int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *chil
|
||
|
*/
|
||
|
int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child)
|
||
|
{
|
||
|
- assert(ln);
|
||
|
- assert(child);
|
||
|
-
|
||
|
if (!ln || !child)
|
||
|
return -EINVAL;
|
||
|
|
||
|
+ DBG(LINE, ul_debugobj(ln, "add child"));
|
||
|
+ scols_ref_line(child);
|
||
|
+ scols_ref_line(ln);
|
||
|
+
|
||
|
/* 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;
|
||
|
}
|
||
|
|
||
|
@@ -246,9 +263,8 @@ int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child)
|
||
|
*
|
||
|
* 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)
|
||
|
+struct libscols_line *scols_line_get_parent(const struct libscols_line *ln)
|
||
|
{
|
||
|
- assert(ln);
|
||
|
return ln ? ln->parent : NULL;
|
||
|
}
|
||
|
|
||
|
@@ -260,7 +276,6 @@ struct libscols_line *scols_line_get_parent(struct libscols_line *ln)
|
||
|
*/
|
||
|
int scols_line_has_children(struct libscols_line *ln)
|
||
|
{
|
||
|
- assert(ln);
|
||
|
return ln ? !list_empty(&ln->ln_branch) : 0;
|
||
|
}
|
||
|
|
||
|
@@ -294,29 +309,44 @@ int scols_line_next_child(struct libscols_line *ln,
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_line_is_ancestor:
|
||
|
+ * @ln: line
|
||
|
+ * @parent: potential parent
|
||
|
+ *
|
||
|
+ * The function is designed to detect circular dependencies between @ln and
|
||
|
+ * @parent. It checks if @ln is not any (grand) parent in the @parent's tree.
|
||
|
+ *
|
||
|
+ * Since: 2.30
|
||
|
+ *
|
||
|
+ * Returns: 0 or 1
|
||
|
+ */
|
||
|
+int scols_line_is_ancestor(struct libscols_line *ln, struct libscols_line *parent)
|
||
|
+{
|
||
|
+ while (parent) {
|
||
|
+ if (parent == ln)
|
||
|
+ return 1;
|
||
|
+ parent = scols_line_get_parent(parent);
|
||
|
+ };
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_line_set_color:
|
||
|
* @ln: a pointer to a struct libscols_line instance
|
||
|
- * @color: ESC sequence
|
||
|
+ * @color: color name or 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;
|
||
|
+ if (color && isalnum(*color)) {
|
||
|
+ color = color_sequence_from_colorname(color);
|
||
|
+ if (!color)
|
||
|
+ return -EINVAL;
|
||
|
}
|
||
|
-
|
||
|
- free(ln->color);
|
||
|
- ln->color = p;
|
||
|
- return 0;
|
||
|
+ return strdup_to_struct_member(ln, color, color);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -325,22 +355,20 @@ int scols_line_set_color(struct libscols_line *ln, const char *color)
|
||
|
*
|
||
|
* Returns: @ln's color string, NULL in case of an error.
|
||
|
*/
|
||
|
-const char *scols_line_get_color(struct libscols_line *ln)
|
||
|
+const char *scols_line_get_color(const struct libscols_line *ln)
|
||
|
{
|
||
|
- assert(ln);
|
||
|
- return ln ? ln->color : NULL;
|
||
|
+ return ln->color;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_line_get_ncells:
|
||
|
* @ln: a pointer to a struct libscols_line instance
|
||
|
*
|
||
|
- * Returns: @ln's number of cells
|
||
|
+ * Returns: number of cells
|
||
|
*/
|
||
|
-size_t scols_line_get_ncells(struct libscols_line *ln)
|
||
|
+size_t scols_line_get_ncells(const struct libscols_line *ln)
|
||
|
{
|
||
|
- assert(ln);
|
||
|
- return ln ? ln->ncells : 0;
|
||
|
+ return ln->ncells;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -353,8 +381,6 @@ size_t scols_line_get_ncells(struct libscols_line *ln)
|
||
|
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];
|
||
|
@@ -373,15 +399,15 @@ struct libscols_cell *scols_line_get_column_cell(
|
||
|
struct libscols_line *ln,
|
||
|
struct libscols_column *cl)
|
||
|
{
|
||
|
- assert(ln);
|
||
|
- assert(cl);
|
||
|
+ if (!ln || !cl)
|
||
|
+ return NULL;
|
||
|
|
||
|
return scols_line_get_cell(ln, cl->seqnum);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_line_set_data:
|
||
|
- * @ln: a pointer to a struct libscols_cell instance
|
||
|
+ * @ln: a pointer to a struct libscols_line instance
|
||
|
* @n: number of the cell, whose data is to be set
|
||
|
* @data: actual data to set
|
||
|
*
|
||
|
@@ -396,9 +422,28 @@ int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data)
|
||
|
return scols_cell_set_data(ce, data);
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_line_set_column_data:
|
||
|
+ * @ln: a pointer to a struct libscols_line instance
|
||
|
+ * @cl: column, whose data is to be set
|
||
|
+ * @data: actual data to set
|
||
|
+ *
|
||
|
+ * The same as scols_line_set_data() but cell is referenced by column object.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.28
|
||
|
+ */
|
||
|
+int scols_line_set_column_data(struct libscols_line *ln,
|
||
|
+ struct libscols_column *cl,
|
||
|
+ const char *data)
|
||
|
+{
|
||
|
+ return scols_line_set_data(ln, cl->seqnum, data);
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_line_refer_data:
|
||
|
- * @ln: a pointer to a struct libscols_cell instance
|
||
|
+ * @ln: a pointer to a struct libscols_line instance
|
||
|
* @n: number of the cell which will refer to @data
|
||
|
* @data: actual data to refer to
|
||
|
*
|
||
|
@@ -413,18 +458,36 @@ int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data)
|
||
|
return scols_cell_refer_data(ce, data);
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_line_refer_column_data:
|
||
|
+ * @ln: a pointer to a struct libscols_line instance
|
||
|
+ * @cl: column, whose data is to be set
|
||
|
+ * @data: actual data to refer to
|
||
|
+ *
|
||
|
+ * The same as scols_line_refer_data() but cell is referenced by column object.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.28
|
||
|
+ */
|
||
|
+int scols_line_refer_column_data(struct libscols_line *ln,
|
||
|
+ struct libscols_column *cl,
|
||
|
+ char *data)
|
||
|
+{
|
||
|
+ return scols_line_refer_data(ln, cl->seqnum, data);
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_copy_line:
|
||
|
- * @ln: a pointer to a struct libscols_cell instance
|
||
|
+ * @ln: a pointer to a struct libscols_line 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 *scols_copy_line(const struct libscols_line *ln)
|
||
|
{
|
||
|
struct libscols_line *ret;
|
||
|
size_t i;
|
||
|
|
||
|
- assert (ln);
|
||
|
if (!ln)
|
||
|
return NULL;
|
||
|
|
||
|
@@ -440,7 +503,7 @@ struct libscols_line *scols_copy_line(struct libscols_line *ln)
|
||
|
ret->ncells = ln->ncells;
|
||
|
ret->seqnum = ln->seqnum;
|
||
|
|
||
|
- DBG(LINE, ul_debugobj(ln, "copy to %p", ret));
|
||
|
+ DBG(LINE, ul_debugobj(ln, "copy"));
|
||
|
|
||
|
for (i = 0; i < ret->ncells; ++i) {
|
||
|
if (scols_cell_copy_content(&ret->cells[i], &ln->cells[i]))
|
||
|
@@ -452,5 +515,3 @@ err:
|
||
|
scols_unref_line(ret);
|
||
|
return NULL;
|
||
|
}
|
||
|
-
|
||
|
-
|
||
|
diff --git a/libsmartcols/src/smartcolsP.h b/libsmartcols/src/smartcolsP.h
|
||
|
index cea4f3101..398e6f064 100644
|
||
|
--- a/libsmartcols/src/smartcolsP.h
|
||
|
+++ b/libsmartcols/src/smartcolsP.h
|
||
|
@@ -13,23 +13,18 @@
|
||
|
|
||
|
#include "c.h"
|
||
|
#include "list.h"
|
||
|
+#include "strutils.h"
|
||
|
#include "colors.h"
|
||
|
#include "debug.h"
|
||
|
|
||
|
-#include "libsmartcols.h"
|
||
|
-
|
||
|
-/* features */
|
||
|
-#define CONFIG_LIBSMARTCOLS_ASSERT
|
||
|
+#include <assert.h>
|
||
|
|
||
|
-#ifdef CONFIG_LIBSMARTCOLS_ASSERT
|
||
|
-# include <assert.h>
|
||
|
-#else
|
||
|
-# define assert(x)
|
||
|
-#endif
|
||
|
+#include "libsmartcols.h"
|
||
|
|
||
|
/*
|
||
|
* Debug
|
||
|
*/
|
||
|
+#define SCOLS_DEBUG_HELP (1 << 0)
|
||
|
#define SCOLS_DEBUG_INIT (1 << 1)
|
||
|
#define SCOLS_DEBUG_CELL (1 << 2)
|
||
|
#define SCOLS_DEBUG_LINE (1 << 3)
|
||
|
@@ -43,7 +38,7 @@ UL_DEBUG_DECLARE_MASK(libsmartcols);
|
||
|
#define ON_DBG(m, x) __UL_DBG_CALL(libsmartcols, SCOLS_DEBUG_, m, x)
|
||
|
#define DBG_FLUSH __UL_DBG_FLUSH(libsmartcols, SCOLS_DEBUG_)
|
||
|
|
||
|
-#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(libsmartcols)
|
||
|
+#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(libsmartcols)
|
||
|
#include "debugobj.h"
|
||
|
|
||
|
/*
|
||
|
@@ -63,6 +58,8 @@ struct libscols_symbols {
|
||
|
char *branch;
|
||
|
char *vert;
|
||
|
char *right;
|
||
|
+ char *title_padding;
|
||
|
+ char *cell_padding;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
@@ -72,8 +69,10 @@ struct libscols_cell {
|
||
|
char *data;
|
||
|
char *color;
|
||
|
void *userdata;
|
||
|
+ int flags;
|
||
|
};
|
||
|
|
||
|
+extern int scols_line_move_cells(struct libscols_line *ln, size_t newn, size_t oldn);
|
||
|
|
||
|
/*
|
||
|
* Table column
|
||
|
@@ -86,19 +85,36 @@ struct libscols_column {
|
||
|
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 */
|
||
|
+ size_t width_treeart; /* size of the tree ascii art */
|
||
|
double width_hint; /* hint (N < 1 is in percent of termwidth) */
|
||
|
|
||
|
+ int json_type; /* SCOLS_JSON_* */
|
||
|
+
|
||
|
int flags;
|
||
|
int is_extreme;
|
||
|
char *color; /* default column color */
|
||
|
+ char *safechars; /* do not encode this bytes */
|
||
|
+
|
||
|
+ char *pending_data;
|
||
|
+ size_t pending_data_sz;
|
||
|
+ char *pending_data_buf;
|
||
|
|
||
|
int (*cmpfunc)(struct libscols_cell *,
|
||
|
struct libscols_cell *,
|
||
|
void *); /* cells comparison function */
|
||
|
void *cmpfunc_data;
|
||
|
|
||
|
+ size_t (*wrap_chunksize)(const struct libscols_column *,
|
||
|
+ const char *, void *);
|
||
|
+ char *(*wrap_nextchunk)(const struct libscols_column *,
|
||
|
+ char *, void *);
|
||
|
+ void *wrapfunc_data;
|
||
|
+
|
||
|
+
|
||
|
struct libscols_cell header;
|
||
|
struct list_head cl_columns;
|
||
|
+
|
||
|
+ struct libscols_table *table;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
@@ -124,7 +140,8 @@ struct libscols_line {
|
||
|
enum {
|
||
|
SCOLS_FMT_HUMAN = 0, /* default, human readable */
|
||
|
SCOLS_FMT_RAW, /* space separated */
|
||
|
- SCOLS_FMT_EXPORT /* COLNAME="data" ... */
|
||
|
+ SCOLS_FMT_EXPORT, /* COLNAME="data" ... */
|
||
|
+ SCOLS_FMT_JSON /* http://en.wikipedia.org/wiki/JSON */
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
@@ -132,11 +149,14 @@ enum {
|
||
|
*/
|
||
|
struct libscols_table {
|
||
|
int refcount;
|
||
|
+ char *name; /* optional table name (for JSON) */
|
||
|
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 termwidth; /* terminal width (number of columns) */
|
||
|
+ size_t termheight; /* terminal height (number of lines) */
|
||
|
size_t termreduce; /* extra blank space */
|
||
|
+ int termforce; /* SCOLS_TERMFORCE_* */
|
||
|
FILE *out; /* output stream */
|
||
|
|
||
|
char *colsep; /* column separator */
|
||
|
@@ -145,15 +165,28 @@ struct libscols_table {
|
||
|
struct list_head tb_columns;
|
||
|
struct list_head tb_lines;
|
||
|
struct libscols_symbols *symbols;
|
||
|
+ struct libscols_cell title; /* optional table title (for humans) */
|
||
|
|
||
|
+ int indent; /* indention counter */
|
||
|
+ int indent_last_sep;/* last printed has been line separator */
|
||
|
int format; /* SCOLS_FMT_* */
|
||
|
|
||
|
+ size_t termlines_used; /* printed line counter */
|
||
|
+ size_t header_next; /* where repeat header */
|
||
|
+
|
||
|
/* 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 */
|
||
|
+ padding_debug :1, /* output visible padding chars */
|
||
|
+ maxout :1, /* maximize output */
|
||
|
+ header_repeat :1, /* print header after libscols_table->termheight */
|
||
|
+ header_printed :1, /* header already printed */
|
||
|
+ priv_symbols :1, /* default private symbols */
|
||
|
+ no_headings :1, /* don't print header */
|
||
|
+ no_encode :1, /* don't care about control and non-printable chars */
|
||
|
+ no_linesep :1, /* don't print line separator */
|
||
|
+ no_wrap :1; /* never wrap lines */
|
||
|
};
|
||
|
|
||
|
#define IS_ITER_FORWARD(_i) ((_i)->direction == SCOLS_ITER_FORWARD)
|
||
|
@@ -173,4 +206,13 @@ struct libscols_table {
|
||
|
(itr)->p->next : (itr)->p->prev; \
|
||
|
} while(0)
|
||
|
|
||
|
+
|
||
|
+static inline int scols_iter_is_last(const struct libscols_iter *itr)
|
||
|
+{
|
||
|
+ if (!itr || !itr->head || !itr->p)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ return itr->p == itr->head;
|
||
|
+}
|
||
|
+
|
||
|
#endif /* _LIBSMARTCOLS_PRIVATE_H */
|
||
|
diff --git a/libsmartcols/src/symbols.c b/libsmartcols/src/symbols.c
|
||
|
index 2b8f81dc9..6ddf1869b 100644
|
||
|
--- a/libsmartcols/src/symbols.c
|
||
|
+++ b/libsmartcols/src/symbols.c
|
||
|
@@ -2,6 +2,7 @@
|
||
|
* symbols.c - routines for symbol handling
|
||
|
*
|
||
|
* Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
|
||
|
+ * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
|
||
|
*
|
||
|
* This file may be redistributed under the terms of the
|
||
|
* GNU Lesser General Public License.
|
||
|
@@ -10,7 +11,7 @@
|
||
|
/**
|
||
|
* SECTION: symbols
|
||
|
* @title: Symbols
|
||
|
- * @short_description: symbols API
|
||
|
+ * @short_description: allows to overwrite default output chars (for ascii art)
|
||
|
*
|
||
|
* An API to access and modify data and information per symbol/symbol group.
|
||
|
*/
|
||
|
@@ -61,115 +62,112 @@ void scols_unref_symbols(struct libscols_symbols *sy)
|
||
|
free(sy->branch);
|
||
|
free(sy->vert);
|
||
|
free(sy->right);
|
||
|
+ free(sy->title_padding);
|
||
|
+ free(sy->cell_padding);
|
||
|
free(sy);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_symbols_set_branch:
|
||
|
- * @sb: a pointer to a struct libscols_symbols instance
|
||
|
+ * @sy: 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)
|
||
|
+int scols_symbols_set_branch(struct libscols_symbols *sy, 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;
|
||
|
+ return strdup_to_struct_member(sy, branch, str);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_symbols_set_vertical:
|
||
|
- * @sb: a pointer to a struct libscols_symbols instance
|
||
|
+ * @sy: 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)
|
||
|
+int scols_symbols_set_vertical(struct libscols_symbols *sy, 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;
|
||
|
+ return strdup_to_struct_member(sy, vert, str);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_symbols_set_right:
|
||
|
- * @sb: a pointer to a struct libscols_symbols instance
|
||
|
+ * @sy: 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)
|
||
|
+int scols_symbols_set_right(struct libscols_symbols *sy, const char *str)
|
||
|
{
|
||
|
- char *p = NULL;
|
||
|
+ return strdup_to_struct_member(sy, right, str);
|
||
|
+}
|
||
|
|
||
|
- assert(sb);
|
||
|
+/**
|
||
|
+ * scols_symbols_set_title_padding:
|
||
|
+ * @sy: a pointer to a struct libscols_symbols instance
|
||
|
+ * @str: a string which will represent the symbols which fill title output
|
||
|
+ *
|
||
|
+ * The current implementation uses only the first byte from the padding string.
|
||
|
+ * A multibyte chars are not supported yet.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.28
|
||
|
+ */
|
||
|
+int scols_symbols_set_title_padding(struct libscols_symbols *sy, const char *str)
|
||
|
+{
|
||
|
+ return strdup_to_struct_member(sy, title_padding, str);
|
||
|
+}
|
||
|
|
||
|
- if (!sb)
|
||
|
- return -EINVAL;
|
||
|
- if (str) {
|
||
|
- p = strdup(str);
|
||
|
- if (!p)
|
||
|
- return -ENOMEM;
|
||
|
- }
|
||
|
- free(sb->right);
|
||
|
- sb->right = p;
|
||
|
- return 0;
|
||
|
+/**
|
||
|
+ * scols_symbols_set_cell_padding:
|
||
|
+ * @sy: a pointer to a struct libscols_symbols instance
|
||
|
+ * @str: a string which will represent the symbols which fill cells
|
||
|
+ *
|
||
|
+ * The padding char has to take up just one cell on the terminal.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_symbols_set_cell_padding(struct libscols_symbols *sy, const char *str)
|
||
|
+{
|
||
|
+ return strdup_to_struct_member(sy, cell_padding, str);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_copy_symbols:
|
||
|
- * @sb: a pointer to a struct libscols_symbols instance
|
||
|
+ * @sy: 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.
|
||
|
+ * Returns: a newly allocated copy of the @sy symbol group or NULL in case of an error.
|
||
|
*/
|
||
|
-struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sb)
|
||
|
+struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sy)
|
||
|
{
|
||
|
struct libscols_symbols *ret;
|
||
|
int rc;
|
||
|
|
||
|
- assert(sb);
|
||
|
- if (!sb)
|
||
|
+ assert(sy);
|
||
|
+ if (!sy)
|
||
|
return NULL;
|
||
|
|
||
|
ret = scols_new_symbols();
|
||
|
if (!ret)
|
||
|
return NULL;
|
||
|
|
||
|
- rc = scols_symbols_set_branch(ret, sb->branch);
|
||
|
+ rc = scols_symbols_set_branch(ret, sy->branch);
|
||
|
+ if (!rc)
|
||
|
+ rc = scols_symbols_set_vertical(ret, sy->vert);
|
||
|
if (!rc)
|
||
|
- rc = scols_symbols_set_vertical(ret, sb->vert);
|
||
|
+ rc = scols_symbols_set_right(ret, sy->right);
|
||
|
if (!rc)
|
||
|
- rc = scols_symbols_set_right(ret, sb->right);
|
||
|
+ rc = scols_symbols_set_title_padding(ret, sy->title_padding);
|
||
|
+ if (!rc)
|
||
|
+ rc = scols_symbols_set_cell_padding(ret, sy->cell_padding);
|
||
|
if (!rc)
|
||
|
return ret;
|
||
|
|
||
|
scols_unref_symbols(ret);
|
||
|
return NULL;
|
||
|
-
|
||
|
}
|
||
|
-
|
||
|
-
|
||
|
diff --git a/libsmartcols/src/table.c b/libsmartcols/src/table.c
|
||
|
index 8c404f858..979a09a39 100644
|
||
|
--- a/libsmartcols/src/table.c
|
||
|
+++ b/libsmartcols/src/table.c
|
||
|
@@ -3,6 +3,7 @@
|
||
|
*
|
||
|
* Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
|
||
|
* Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
|
||
|
+ * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
|
||
|
*
|
||
|
* This file may be redistributed under the terms of the
|
||
|
* GNU Lesser General Public License.
|
||
|
@@ -11,7 +12,7 @@
|
||
|
/**
|
||
|
* SECTION: table
|
||
|
* @title: Table
|
||
|
- * @short_description: table data API
|
||
|
+ * @short_description: container for rows and columns
|
||
|
*
|
||
|
* Table data manipulation API.
|
||
|
*/
|
||
|
@@ -24,7 +25,7 @@
|
||
|
#include <ctype.h>
|
||
|
|
||
|
#include "nls.h"
|
||
|
-#include "widechar.h"
|
||
|
+#include "ttyutils.h"
|
||
|
#include "smartcolsP.h"
|
||
|
|
||
|
#ifdef HAVE_WIDECHAR
|
||
|
@@ -38,6 +39,20 @@
|
||
|
list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
|
||
|
|
||
|
|
||
|
+static void check_padding_debug(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ const char *str;
|
||
|
+
|
||
|
+ assert(libsmartcols_debug_mask); /* debug has to be enabled! */
|
||
|
+
|
||
|
+ str = getenv("LIBSMARTCOLS_DEBUG_PADDING");
|
||
|
+ if (!str || (strcmp(str, "on") != 0 && strcmp(str, "1") != 0))
|
||
|
+ return;
|
||
|
+
|
||
|
+ DBG(INIT, ul_debugobj(tb, "padding debug: ENABLE"));
|
||
|
+ tb->padding_debug = 1;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_new_table:
|
||
|
*
|
||
|
@@ -46,6 +61,7 @@
|
||
|
struct libscols_table *scols_new_table(void)
|
||
|
{
|
||
|
struct libscols_table *tb;
|
||
|
+ int c, l;
|
||
|
|
||
|
tb = calloc(1, sizeof(struct libscols_table));
|
||
|
if (!tb)
|
||
|
@@ -54,10 +70,16 @@ struct libscols_table *scols_new_table(void)
|
||
|
tb->refcount = 1;
|
||
|
tb->out = stdout;
|
||
|
|
||
|
+ get_terminal_dimension(&c, &l);
|
||
|
+ tb->termwidth = c > 0 ? c : 80;
|
||
|
+ tb->termheight = l > 0 ? l : 24;
|
||
|
+
|
||
|
INIT_LIST_HEAD(&tb->tb_lines);
|
||
|
INIT_LIST_HEAD(&tb->tb_columns);
|
||
|
|
||
|
DBG(TAB, ul_debugobj(tb, "alloc"));
|
||
|
+ ON_DBG(INIT, check_padding_debug(tb));
|
||
|
+
|
||
|
return tb;
|
||
|
}
|
||
|
|
||
|
@@ -87,44 +109,102 @@ void scols_unref_table(struct libscols_table *tb)
|
||
|
scols_table_remove_lines(tb);
|
||
|
scols_table_remove_columns(tb);
|
||
|
scols_unref_symbols(tb->symbols);
|
||
|
+ scols_reset_cell(&tb->title);
|
||
|
free(tb->linesep);
|
||
|
free(tb->colsep);
|
||
|
+ free(tb->name);
|
||
|
free(tb);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_table_set_name:
|
||
|
+ * @tb: a pointer to a struct libscols_table instance
|
||
|
+ * @name: a name
|
||
|
+ *
|
||
|
+ * The table name is used for example for JSON top level object name.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative number in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.27
|
||
|
+ */
|
||
|
+int scols_table_set_name(struct libscols_table *tb, const char *name)
|
||
|
+{
|
||
|
+ return strdup_to_struct_member(tb, name, name);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_get_name:
|
||
|
+ * @tb: a pointer to a struct libscols_table instance
|
||
|
+ *
|
||
|
+ * Returns: The current name setting of the table @tb
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+const char *scols_table_get_name(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->name;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_get_title:
|
||
|
+ * @tb: a pointer to a struct libscols_table instance
|
||
|
+ *
|
||
|
+ * The returned pointer is possible to modify by cell functions. Note that
|
||
|
+ * title output alignment on non-tty is hardcoded to 80 output chars. For the
|
||
|
+ * regular terminal it's based on terminal width.
|
||
|
+ *
|
||
|
+ * Returns: Title of the table, or NULL in case of blank title.
|
||
|
+ *
|
||
|
+ * Since: 2.28
|
||
|
+ */
|
||
|
+struct libscols_cell *scols_table_get_title(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return &tb->title;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* 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.
|
||
|
+ * Adds @cl to @tb's column list. The column cannot be shared between more
|
||
|
+ * tables.
|
||
|
*
|
||
|
* 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);
|
||
|
+ struct libscols_iter itr;
|
||
|
+ struct libscols_line *ln;
|
||
|
+ int rc = 0;
|
||
|
|
||
|
- if (!tb || !cl || !list_empty(&tb->tb_lines))
|
||
|
+ if (!tb || !cl || cl->table)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (cl->flags & SCOLS_FL_TREE)
|
||
|
tb->ntreecols++;
|
||
|
|
||
|
- DBG(TAB, ul_debugobj(tb, "add column %p", cl));
|
||
|
+ DBG(TAB, ul_debugobj(tb, "add column"));
|
||
|
list_add_tail(&cl->cl_columns, &tb->tb_columns);
|
||
|
cl->seqnum = tb->ncols++;
|
||
|
+ cl->table = tb;
|
||
|
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.
|
||
|
+ if (list_empty(&tb->tb_lines))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+
|
||
|
+ /* Realloc line cell arrays
|
||
|
*/
|
||
|
- return 0;
|
||
|
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
|
||
|
+ rc = scols_line_alloc_cells(ln, tb->ncols);
|
||
|
+ if (rc)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return rc;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -139,18 +219,16 @@ int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl
|
||
|
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));
|
||
|
+ DBG(TAB, ul_debugobj(tb, "remove column"));
|
||
|
list_del_init(&cl->cl_columns);
|
||
|
tb->ncols--;
|
||
|
+ cl->table = NULL;
|
||
|
scols_unref_column(cl);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -165,8 +243,6 @@ int scols_table_remove_column(struct libscols_table *tb,
|
||
|
*/
|
||
|
int scols_table_remove_columns(struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
-
|
||
|
if (!tb || !list_empty(&tb->tb_lines))
|
||
|
return -EINVAL;
|
||
|
|
||
|
@@ -179,12 +255,64 @@ int scols_table_remove_columns(struct libscols_table *tb)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_table_move_column:
|
||
|
+ * @tb: table
|
||
|
+ * @pre: column before the column
|
||
|
+ * @cl: column to move
|
||
|
+ *
|
||
|
+ * Move the @cl behind @pre. If the @pre is NULL then the @col is the first
|
||
|
+ * column in the table.
|
||
|
+ *
|
||
|
+ * Since: 2.30
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative number in case of an error.
|
||
|
+ */
|
||
|
+int scols_table_move_column(struct libscols_table *tb,
|
||
|
+ struct libscols_column *pre,
|
||
|
+ struct libscols_column *cl)
|
||
|
+{
|
||
|
+ struct list_head *head;
|
||
|
+ struct libscols_iter itr;
|
||
|
+ struct libscols_column *p;
|
||
|
+ struct libscols_line *ln;
|
||
|
+ size_t n = 0, oldseq;
|
||
|
+
|
||
|
+ if (!tb || !cl)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ if (pre && pre->seqnum + 1 == cl->seqnum)
|
||
|
+ return 0;
|
||
|
+ if (pre == NULL && cl->seqnum == 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, "move column %zu behind %zu",
|
||
|
+ cl->seqnum, pre? pre->seqnum : 0));
|
||
|
+
|
||
|
+ list_del_init(&cl->cl_columns); /* remove from old position */
|
||
|
+
|
||
|
+ head = pre ? &pre->cl_columns : &tb->tb_columns;
|
||
|
+ list_add(&cl->cl_columns, head); /* add to the new place */
|
||
|
+
|
||
|
+ oldseq = cl->seqnum;
|
||
|
+
|
||
|
+ /* fix seq. numbers */
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+ while (scols_table_next_column(tb, &itr, &p) == 0)
|
||
|
+ p->seqnum = n++;
|
||
|
+
|
||
|
+ /* move data in lines */
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+ while (scols_table_next_line(tb, &itr, &ln) == 0)
|
||
|
+ scols_line_move_cells(ln, cl->seqnum, oldseq);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
|
||
|
/**
|
||
|
* scols_table_new_column:
|
||
|
* @tb: table
|
||
|
* @name: column header
|
||
|
- * @whint: column width hint (absolute width: N > 1; relative width: N < 1)
|
||
|
+ * @whint: column width hint (absolute width: N > 1; relative width: 0 < N < 1)
|
||
|
* @flags: flags integer
|
||
|
*
|
||
|
* This is shortcut for
|
||
|
@@ -193,17 +321,36 @@ int scols_table_remove_columns(struct libscols_table *tb)
|
||
|
* scols_column_set_....(cl, ...);
|
||
|
* scols_table_add_column(tb, cl);
|
||
|
*
|
||
|
- * The column width is possible to define by three ways:
|
||
|
+ * The column width is possible to define by:
|
||
|
+ *
|
||
|
+ * @whint: 0 < N < 1 : relative width, percent of terminal width
|
||
|
+ *
|
||
|
+ * @whint: N >= 1 : absolute width, empty column will be truncated to
|
||
|
+ * the column header width if no specified STRICTWIDTH flag
|
||
|
*
|
||
|
- * @whint = 0..1 : relative width, percent of terminal width
|
||
|
+ * Note that if table has disabled "maxout" flag (disabled by default) than
|
||
|
+ * relative width is used as a hint only. It's possible that column will be
|
||
|
+ * narrow if the specified size is too large for column data.
|
||
|
*
|
||
|
- * @whint = 1..N : absolute width, empty colum will be truncated to
|
||
|
- * the column header width
|
||
|
*
|
||
|
- * @whint = 1..N
|
||
|
+ * If the width of all columns is greater than terminal width then library
|
||
|
+ * tries to reduce width of the individual columns. It's done in three stages:
|
||
|
*
|
||
|
- * The column is necessary to address by
|
||
|
- * sequential number. The first defined column has the colnum = 0. For example:
|
||
|
+ * #1 reduce columns with SCOLS_FL_TRUNC flag and with relative width if the
|
||
|
+ * width is greater than width defined by @whint (@whint * terminal_width)
|
||
|
+ *
|
||
|
+ * #2 reduce all columns with SCOLS_FL_TRUNC flag
|
||
|
+ *
|
||
|
+ * #3 reduce all columns with relative width
|
||
|
+ *
|
||
|
+ * The next stage is always used if the previous stage is unsuccessful. Note
|
||
|
+ * that SCOLS_FL_WRAP is interpreted as SCOLS_FL_TRUNC when calculate column
|
||
|
+ * width (if custom wrap function is not specified), but the final text is not
|
||
|
+ * truncated, but wrapped to multi-line cell.
|
||
|
+ *
|
||
|
+ *
|
||
|
+ * 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
|
||
|
@@ -222,7 +369,6 @@ struct libscols_column *scols_table_new_column(struct libscols_table *tb,
|
||
|
struct libscols_column *cl;
|
||
|
struct libscols_cell *hr;
|
||
|
|
||
|
- assert (tb);
|
||
|
if (!tb)
|
||
|
return NULL;
|
||
|
|
||
|
@@ -282,29 +428,26 @@ int scols_table_next_column(struct libscols_table *tb,
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
-
|
||
|
/**
|
||
|
* scols_table_get_ncols:
|
||
|
* @tb: table
|
||
|
*
|
||
|
- * Returns: the ncols table member, a negative number in case of an error.
|
||
|
+ * Returns: the ncols table member.
|
||
|
*/
|
||
|
-int scols_table_get_ncols(struct libscols_table *tb)
|
||
|
+size_t scols_table_get_ncols(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb ? tb->ncols : -EINVAL;
|
||
|
+ return tb->ncols;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_table_get_nlines:
|
||
|
* @tb: table
|
||
|
*
|
||
|
- * Returns: the nlines table member, a negative number in case of an error.
|
||
|
+ * Returns: the nlines table member.
|
||
|
*/
|
||
|
-int scols_table_get_nlines(struct libscols_table *tb)
|
||
|
+size_t scols_table_get_nlines(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb ? tb->nlines : -EINVAL;
|
||
|
+ return tb->nlines;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -335,10 +478,9 @@ int scols_table_set_stream(struct libscols_table *tb, FILE *stream)
|
||
|
*
|
||
|
* Returns: stream pointer, NULL in case of an error or an unset stream.
|
||
|
*/
|
||
|
-FILE *scols_table_get_stream(struct libscols_table *tb)
|
||
|
+FILE *scols_table_get_stream(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb ? tb->out: NULL;
|
||
|
+ return tb->out;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -346,13 +488,20 @@ FILE *scols_table_get_stream(struct libscols_table *tb)
|
||
|
* @tb: table
|
||
|
* @reduce: width
|
||
|
*
|
||
|
- * Reduce the output width to @reduce.
|
||
|
+ * If necessary then libsmartcols use all terminal width, the @reduce setting
|
||
|
+ * provides extra space (for example for borders in ncurses applications).
|
||
|
+ *
|
||
|
+ * The @reduce must be smaller than terminal width, otherwise it's silently
|
||
|
+ * ignored. The reduction is not applied when STDOUT_FILENO is not terminal.
|
||
|
+ *
|
||
|
+ * Note that after output initialization (scols_table_print_* calls) the width
|
||
|
+ * will be reduced, this behavior affects subsequenced scols_table_get_termwidth()
|
||
|
+ * calls.
|
||
|
*
|
||
|
* 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;
|
||
|
|
||
|
@@ -374,7 +523,6 @@ struct libscols_column *scols_table_get_column(struct libscols_table *tb,
|
||
|
struct libscols_iter itr;
|
||
|
struct libscols_column *cl;
|
||
|
|
||
|
- assert(tb);
|
||
|
if (!tb)
|
||
|
return NULL;
|
||
|
if (n >= tb->ncols)
|
||
|
@@ -400,11 +548,7 @@ struct libscols_column *scols_table_get_column(struct libscols_table *tb,
|
||
|
*/
|
||
|
int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
|
||
|
{
|
||
|
-
|
||
|
- assert(tb);
|
||
|
- assert(ln);
|
||
|
-
|
||
|
- if (!tb || !ln)
|
||
|
+ if (!tb || !ln || tb->ncols == 0)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (tb->ncols > ln->ncells) {
|
||
|
@@ -413,7 +557,7 @@ int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
- DBG(TAB, ul_debugobj(tb, "add line %p", ln));
|
||
|
+ DBG(TAB, ul_debugobj(tb, "add line"));
|
||
|
list_add_tail(&ln->ln_lines, &tb->tb_lines);
|
||
|
ln->seqnum = tb->nlines++;
|
||
|
scols_ref_line(ln);
|
||
|
@@ -433,13 +577,10 @@ int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
|
||
|
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));
|
||
|
+ DBG(TAB, ul_debugobj(tb, "remove line"));
|
||
|
list_del_init(&ln->ln_lines);
|
||
|
tb->nlines--;
|
||
|
scols_unref_line(ln);
|
||
|
@@ -454,7 +595,6 @@ int scols_table_remove_line(struct libscols_table *tb,
|
||
|
*/
|
||
|
void scols_table_remove_lines(struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
if (!tb)
|
||
|
return;
|
||
|
|
||
|
@@ -517,9 +657,6 @@ struct libscols_line *scols_table_new_line(struct libscols_table *tb,
|
||
|
{
|
||
|
struct libscols_line *ln;
|
||
|
|
||
|
- assert(tb);
|
||
|
- assert(tb->ncols);
|
||
|
-
|
||
|
if (!tb || !tb->ncols)
|
||
|
return NULL;
|
||
|
|
||
|
@@ -544,13 +681,7 @@ err:
|
||
|
* @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
|
||
|
+ * Returns: a line or NULL
|
||
|
*/
|
||
|
struct libscols_line *scols_table_get_line(struct libscols_table *tb,
|
||
|
size_t n)
|
||
|
@@ -558,7 +689,6 @@ struct libscols_line *scols_table_get_line(struct libscols_table *tb,
|
||
|
struct libscols_iter itr;
|
||
|
struct libscols_line *ln;
|
||
|
|
||
|
- assert(tb);
|
||
|
if (!tb)
|
||
|
return NULL;
|
||
|
if (n >= tb->nlines)
|
||
|
@@ -588,14 +718,13 @@ struct libscols_table *scols_copy_table(struct libscols_table *tb)
|
||
|
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));
|
||
|
+ DBG(TAB, ul_debugobj(tb, "copy"));
|
||
|
|
||
|
if (tb->symbols)
|
||
|
scols_table_set_symbols(ret, tb->symbols);
|
||
|
@@ -639,54 +768,141 @@ err:
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_table_set_default_symbols:
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * The library check the current environment to select ASCII or UTF8 symbols.
|
||
|
+ * This default behavior could be controlled by scols_table_enable_ascii().
|
||
|
+ *
|
||
|
+ * Use scols_table_set_symbols() to unset symbols or use your own setting.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_table_set_default_symbols(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ struct libscols_symbols *sy;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, "setting default symbols"));
|
||
|
+
|
||
|
+ sy = scols_new_symbols();
|
||
|
+ if (!sy)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+#if defined(HAVE_WIDECHAR)
|
||
|
+ if (!scols_table_is_ascii(tb) &&
|
||
|
+ !strcmp(nl_langinfo(CODESET), "UTF-8")) {
|
||
|
+ scols_symbols_set_branch(sy, UTF_VR UTF_H);
|
||
|
+ scols_symbols_set_vertical(sy, UTF_V " ");
|
||
|
+ scols_symbols_set_right(sy, UTF_UR UTF_H);
|
||
|
+ } else
|
||
|
+#endif
|
||
|
+ {
|
||
|
+ scols_symbols_set_branch(sy, "|-");
|
||
|
+ scols_symbols_set_vertical(sy, "| ");
|
||
|
+ scols_symbols_set_right(sy, "`-");
|
||
|
+ }
|
||
|
+ scols_symbols_set_title_padding(sy, " ");
|
||
|
+ scols_symbols_set_cell_padding(sy, " ");
|
||
|
+
|
||
|
+ rc = scols_table_set_symbols(tb, sy);
|
||
|
+ scols_unref_symbols(sy);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
/**
|
||
|
* 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().
|
||
|
+ * draw tree output. If no symbols are used for the table then library creates
|
||
|
+ * default temporary symbols to draw output by scols_table_set_default_symbols().
|
||
|
+ *
|
||
|
+ * If @sy is NULL then remove reference from the currently used symbols.
|
||
|
*
|
||
|
* 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 */
|
||
|
+ /* remove old */
|
||
|
+ if (tb->symbols) {
|
||
|
+ DBG(TAB, ul_debugobj(tb, "remove symbols reference"));
|
||
|
scols_unref_symbols(tb->symbols);
|
||
|
+ tb->symbols = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* set new */
|
||
|
if (sy) { /* ref user defined */
|
||
|
+ DBG(TAB, ul_debugobj(tb, "set symbols"));
|
||
|
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_get_symbols:
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * Returns: pointer to symbols table.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+struct libscols_symbols *scols_table_get_symbols(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->symbols;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_enable_nolinesep:
|
||
|
+ * @tb: table
|
||
|
+ * @enable: 1 or 0
|
||
|
+ *
|
||
|
+ * Enable/disable line separator printing. This is useful if you want to
|
||
|
+ * re-printing the same line more than once (e.g. progress bar). Don't use it
|
||
|
+ * if you're not sure.
|
||
|
+ *
|
||
|
+ * Note that for the last line in the table the separator is disabled at all.
|
||
|
+ * The library differentiate between table terminator and line terminator
|
||
|
+ * (although for standard output \n byte is used in both cases).
|
||
|
+ *
|
||
|
+ * Returns: 0 on success, negative number in case of an error.
|
||
|
+ */
|
||
|
+int scols_table_enable_nolinesep(struct libscols_table *tb, int enable)
|
||
|
+{
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
|
||
|
+ DBG(TAB, ul_debugobj(tb, "nolinesep: %s", enable ? "ENABLE" : "DISABLE"));
|
||
|
+ tb->no_linesep = enable ? 1 : 0;
|
||
|
return 0;
|
||
|
}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_is_nolinesep:
|
||
|
+ * @tb: a pointer to a struct libscols_table instance
|
||
|
+ *
|
||
|
+ * Returns: 1 if line separator printing is disabled.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_table_is_nolinesep(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->no_linesep;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_table_enable_colors:
|
||
|
* @tb: table
|
||
|
@@ -698,7 +914,6 @@ int scols_table_set_symbols(struct libscols_table *tb,
|
||
|
*/
|
||
|
int scols_table_enable_colors(struct libscols_table *tb, int enable)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
if (!tb)
|
||
|
return -EINVAL;
|
||
|
|
||
|
@@ -706,19 +921,19 @@ int scols_table_enable_colors(struct libscols_table *tb, int enable)
|
||
|
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.
|
||
|
+ * (export, raw, JSON, ...) 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;
|
||
|
|
||
|
@@ -730,6 +945,31 @@ int scols_table_enable_raw(struct libscols_table *tb, int enable)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_table_enable_json:
|
||
|
+ * @tb: table
|
||
|
+ * @enable: 1 or 0
|
||
|
+ *
|
||
|
+ * Enable/disable JSON output format. The parsable output formats
|
||
|
+ * (export, raw, JSON, ...) are mutually exclusive.
|
||
|
+ *
|
||
|
+ * Returns: 0 on success, negative number in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.27
|
||
|
+ */
|
||
|
+int scols_table_enable_json(struct libscols_table *tb, int enable)
|
||
|
+{
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, "json: %s", enable ? "ENABLE" : "DISABLE"));
|
||
|
+ if (enable)
|
||
|
+ tb->format = SCOLS_FMT_JSON;
|
||
|
+ else if (tb->format == SCOLS_FMT_JSON)
|
||
|
+ tb->format = 0;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_table_enable_export:
|
||
|
* @tb: table
|
||
|
@@ -742,7 +982,6 @@ int scols_table_enable_raw(struct libscols_table *tb, int enable)
|
||
|
*/
|
||
|
int scols_table_enable_export(struct libscols_table *tb, int enable)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
if (!tb)
|
||
|
return -EINVAL;
|
||
|
|
||
|
@@ -771,7 +1010,6 @@ int scols_table_enable_export(struct libscols_table *tb, int enable)
|
||
|
*/
|
||
|
int scols_table_enable_ascii(struct libscols_table *tb, int enable)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
if (!tb)
|
||
|
return -EINVAL;
|
||
|
|
||
|
@@ -791,7 +1029,6 @@ int scols_table_enable_ascii(struct libscols_table *tb, int enable)
|
||
|
*/
|
||
|
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"));
|
||
|
@@ -799,6 +1036,28 @@ int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_table_enable_header_repeat:
|
||
|
+ * @tb: table
|
||
|
+ * @enable: 1 or 0
|
||
|
+ *
|
||
|
+ * Enable/disable header line repeat. The header line is printed only once by
|
||
|
+ * default. Note that the flag will be silently ignored and disabled if the
|
||
|
+ * output is not on terminal or output format is JSON, raw, etc.
|
||
|
+ *
|
||
|
+ * Returns: 0 on success, negative number in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.31
|
||
|
+ */
|
||
|
+int scols_table_enable_header_repeat(struct libscols_table *tb, int enable)
|
||
|
+{
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+ DBG(TAB, ul_debugobj(tb, "header-repeat: %s", enable ? "ENABLE" : "DISABLE"));
|
||
|
+ tb->header_repeat = enable ? 1 : 0;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_table_enable_maxout:
|
||
|
* @tb: table
|
||
|
@@ -811,7 +1070,6 @@ int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
|
||
|
*/
|
||
|
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"));
|
||
|
@@ -819,28 +1077,92 @@ int scols_table_enable_maxout(struct libscols_table *tb, int enable)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_table_enable_nowrap:
|
||
|
+ * @tb: table
|
||
|
+ * @enable: 1 or 0
|
||
|
+ *
|
||
|
+ * Never continue on next line, remove last column(s) when too large, truncate last column.
|
||
|
+ *
|
||
|
+ * Returns: 0 on success, negative number in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.28
|
||
|
+ */
|
||
|
+int scols_table_enable_nowrap(struct libscols_table *tb, int enable)
|
||
|
+{
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+ DBG(TAB, ul_debugobj(tb, "nowrap: %s", enable ? "ENABLE" : "DISABLE"));
|
||
|
+ tb->no_wrap = enable ? 1 : 0;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_is_nowrap:
|
||
|
+ * @tb: a pointer to a struct libscols_table instance
|
||
|
+ *
|
||
|
+ * Returns: 1 if nowrap is enabled.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_table_is_nowrap(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->no_wrap;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_enable_noencoding:
|
||
|
+ * @tb: table
|
||
|
+ * @enable: 1 or 0
|
||
|
+ *
|
||
|
+ * The library encode non-printable and control chars by \xHEX by default.
|
||
|
+ *
|
||
|
+ * Returns: 0 on success, negative number in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.31
|
||
|
+ */
|
||
|
+int scols_table_enable_noencoding(struct libscols_table *tb, int enable)
|
||
|
+{
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+ DBG(TAB, ul_debugobj(tb, "encoding: %s", enable ? "ENABLE" : "DISABLE"));
|
||
|
+ tb->no_encode = enable ? 1 : 0;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_is_noencoding:
|
||
|
+ * @tb: a pointer to a struct libscols_table instance
|
||
|
+ *
|
||
|
+ * Returns: 1 if encoding is disabled.
|
||
|
+ *
|
||
|
+ * Since: 2.31
|
||
|
+ */
|
||
|
+int scols_table_is_noencoding(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->no_encode;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_table_colors_wanted:
|
||
|
* @tb: table
|
||
|
*
|
||
|
* Returns: 1 if colors are enabled.
|
||
|
*/
|
||
|
-int scols_table_colors_wanted(struct libscols_table *tb)
|
||
|
+int scols_table_colors_wanted(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb && tb->colors_wanted;
|
||
|
+ return tb->colors_wanted;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* scols_table_is_empty:
|
||
|
* @tb: table
|
||
|
*
|
||
|
- * Returns: 1 if the table is empty.
|
||
|
+ * Returns: 1 if the table is empty.
|
||
|
*/
|
||
|
-int scols_table_is_empty(struct libscols_table *tb)
|
||
|
+int scols_table_is_empty(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return !tb || !tb->nlines;
|
||
|
+ return !tb->nlines;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -849,10 +1171,9 @@ int scols_table_is_empty(struct libscols_table *tb)
|
||
|
*
|
||
|
* Returns: 1 if ASCII tree is enabled.
|
||
|
*/
|
||
|
-int scols_table_is_ascii(struct libscols_table *tb)
|
||
|
+int scols_table_is_ascii(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb && tb->ascii;
|
||
|
+ return tb->ascii;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -861,10 +1182,22 @@ int scols_table_is_ascii(struct libscols_table *tb)
|
||
|
*
|
||
|
* Returns: 1 if header output is disabled.
|
||
|
*/
|
||
|
-int scols_table_is_noheadings(struct libscols_table *tb)
|
||
|
+int scols_table_is_noheadings(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb && tb->no_headings;
|
||
|
+ return tb->no_headings;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_is_header_repeat
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * Returns: 1 if header repeat is enabled.
|
||
|
+ *
|
||
|
+ * Since: 2.31
|
||
|
+ */
|
||
|
+int scols_table_is_header_repeat(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->header_repeat;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -873,10 +1206,9 @@ int scols_table_is_noheadings(struct libscols_table *tb)
|
||
|
*
|
||
|
* Returns: 1 if export output format is enabled.
|
||
|
*/
|
||
|
-int scols_table_is_export(struct libscols_table *tb)
|
||
|
+int scols_table_is_export(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb && tb->format == SCOLS_FMT_EXPORT;
|
||
|
+ return tb->format == SCOLS_FMT_EXPORT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -885,23 +1217,33 @@ int scols_table_is_export(struct libscols_table *tb)
|
||
|
*
|
||
|
* Returns: 1 if raw output format is enabled.
|
||
|
*/
|
||
|
-int scols_table_is_raw(struct libscols_table *tb)
|
||
|
+int scols_table_is_raw(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb && tb->format == SCOLS_FMT_RAW;
|
||
|
+ return tb->format == SCOLS_FMT_RAW;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * scols_table_is_json:
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * Returns: 1 if JSON output format is enabled.
|
||
|
+ *
|
||
|
+ * Since: 2.27
|
||
|
+ */
|
||
|
+int scols_table_is_json(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->format == SCOLS_FMT_JSON;
|
||
|
+}
|
||
|
|
||
|
/**
|
||
|
* scols_table_is_maxout
|
||
|
* @tb: table
|
||
|
*
|
||
|
- * Returns: 1 if output maximization is enabled, negative value in case of an error.
|
||
|
+ * Returns: 1 if output maximization is enabled or 0
|
||
|
*/
|
||
|
-int scols_table_is_maxout(struct libscols_table *tb)
|
||
|
+int scols_table_is_maxout(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb && tb->maxout;
|
||
|
+ return tb->maxout;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -910,10 +1252,9 @@ int scols_table_is_maxout(struct libscols_table *tb)
|
||
|
*
|
||
|
* Returns: returns 1 tree-like output is expected.
|
||
|
*/
|
||
|
-int scols_table_is_tree(struct libscols_table *tb)
|
||
|
+int scols_table_is_tree(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert(tb);
|
||
|
- return tb && tb->ntreecols > 0;
|
||
|
+ return tb->ntreecols > 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -922,29 +1263,12 @@ int scols_table_is_tree(struct libscols_table *tb)
|
||
|
* @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;
|
||
|
+ return strdup_to_struct_member(tb, colsep, sep);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -958,23 +1282,7 @@ int scols_table_set_column_separator(struct libscols_table *tb, const char *sep)
|
||
|
*/
|
||
|
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;
|
||
|
+ return strdup_to_struct_member(tb, linesep, sep);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -983,12 +1291,8 @@ int scols_table_set_line_separator(struct libscols_table *tb, const char *sep)
|
||
|
*
|
||
|
* Returns: @tb column separator, NULL in case of an error
|
||
|
*/
|
||
|
-char *scols_table_get_column_separator(struct libscols_table *tb)
|
||
|
+const char *scols_table_get_column_separator(const struct libscols_table *tb)
|
||
|
{
|
||
|
- assert (tb);
|
||
|
-
|
||
|
- if (!tb)
|
||
|
- return NULL;
|
||
|
return tb->colsep;
|
||
|
}
|
||
|
|
||
|
@@ -998,17 +1302,12 @@ char *scols_table_get_column_separator(struct libscols_table *tb)
|
||
|
*
|
||
|
* Returns: @tb line separator, NULL in case of an error
|
||
|
*/
|
||
|
-char *scols_table_get_line_separator(struct libscols_table *tb)
|
||
|
+const char *scols_table_get_line_separator(const 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)
|
||
|
+/* for lines in the struct libscols_line->ln_lines list */
|
||
|
+static int cells_cmp_wrapper_lines(struct list_head *a, struct list_head *b, void *data)
|
||
|
{
|
||
|
struct libscols_column *cl = (struct libscols_column *) data;
|
||
|
struct libscols_line *ra, *rb;
|
||
|
@@ -1026,24 +1325,218 @@ static int cells_cmp_wrapper(struct list_head *a, struct list_head *b, void *dat
|
||
|
return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
|
||
|
}
|
||
|
|
||
|
+/* for lines in the struct libscols_line->ln_children list */
|
||
|
+static int cells_cmp_wrapper_children(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_children);
|
||
|
+ rb = list_entry(b, struct libscols_line, ln_children);
|
||
|
+ ca = scols_line_get_cell(ra, cl->seqnum);
|
||
|
+ cb = scols_line_get_cell(rb, cl->seqnum);
|
||
|
+
|
||
|
+ return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int sort_line_children(struct libscols_line *ln, struct libscols_column *cl)
|
||
|
+{
|
||
|
+ struct list_head *p;
|
||
|
+
|
||
|
+ if (list_empty(&ln->ln_branch))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ list_for_each(p, &ln->ln_branch) {
|
||
|
+ struct libscols_line *chld =
|
||
|
+ list_entry(p, struct libscols_line, ln_children);
|
||
|
+ sort_line_children(chld, cl);
|
||
|
+ }
|
||
|
+
|
||
|
+ list_sort(&ln->ln_branch, cells_cmp_wrapper_children, cl);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
* scols_sort_table:
|
||
|
* @tb: table
|
||
|
* @cl: order by this column
|
||
|
*
|
||
|
- * Orders the table by the column. See also scols_column_set_cmpfunc().
|
||
|
+ * Orders the table by the column. See also scols_column_set_cmpfunc(). If the
|
||
|
+ * tree output is enabled then children in the tree are recursively sorted too.
|
||
|
*
|
||
|
* 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)
|
||
|
+ if (!tb || !cl || !cl->cmpfunc)
|
||
|
return -EINVAL;
|
||
|
|
||
|
DBG(TAB, ul_debugobj(tb, "sorting table"));
|
||
|
- list_sort(&tb->tb_lines, cells_cmp_wrapper, cl);
|
||
|
+ list_sort(&tb->tb_lines, cells_cmp_wrapper_lines, cl);
|
||
|
+
|
||
|
+ if (scols_table_is_tree(tb)) {
|
||
|
+ struct libscols_line *ln;
|
||
|
+ struct libscols_iter itr;
|
||
|
+
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+ while (scols_table_next_line(tb, &itr, &ln) == 0)
|
||
|
+ sort_line_children(ln, cl);
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static struct libscols_line *move_line_and_children(struct libscols_line *ln, struct libscols_line *pre)
|
||
|
+{
|
||
|
+ if (pre) {
|
||
|
+ list_del_init(&ln->ln_lines); /* remove from old position */
|
||
|
+ list_add(&ln->ln_lines, &pre->ln_lines); /* add to the new place (behind @pre) */
|
||
|
+ }
|
||
|
+ pre = ln;
|
||
|
+
|
||
|
+ if (!list_empty(&ln->ln_branch)) {
|
||
|
+ struct list_head *p;
|
||
|
+
|
||
|
+ list_for_each(p, &ln->ln_branch) {
|
||
|
+ struct libscols_line *chld =
|
||
|
+ list_entry(p, struct libscols_line, ln_children);
|
||
|
+ pre = move_line_and_children(chld, pre);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return pre;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_sort_table_by_tree:
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * Reorders lines in the table by parent->child relation. Note that order of
|
||
|
+ * the lines in the table is independent on the tree hierarchy.
|
||
|
+ *
|
||
|
+ * Since: 2.30
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ */
|
||
|
+int scols_sort_table_by_tree(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ struct libscols_line *ln;
|
||
|
+ struct libscols_iter itr;
|
||
|
+
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, "sorting table by tree"));
|
||
|
+
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
|
||
|
+ if (ln->parent)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ move_line_and_children(ln, NULL);
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_set_termforce:
|
||
|
+ * @tb: table
|
||
|
+ * @force: SCOLS_TERMFORCE_{NEVER,ALWAYS,AUTO}
|
||
|
+ *
|
||
|
+ * Forces library to use stdout as terminal, non-terminal or use automatic
|
||
|
+ * detection (default).
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_table_set_termforce(struct libscols_table *tb, int force)
|
||
|
+{
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+ tb->termforce = force;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_get_termforce:
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * Returns: SCOLS_TERMFORCE_{NEVER,ALWAYS,AUTO} or a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_table_get_termforce(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->termforce;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_set_termwidth
|
||
|
+ * @tb: table
|
||
|
+ * @width: terminal width
|
||
|
+ *
|
||
|
+ * The library automatically detects terminal width or defaults to 80 chars if
|
||
|
+ * detections is unsuccessful. This function override this behaviour.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.29
|
||
|
+ */
|
||
|
+int scols_table_set_termwidth(struct libscols_table *tb, size_t width)
|
||
|
+{
|
||
|
+ DBG(TAB, ul_debugobj(tb, "set terminatl width: %zu", width));
|
||
|
+ tb->termwidth = width;
|
||
|
return 0;
|
||
|
}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_get_termwidth
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * Returns: terminal width.
|
||
|
+ */
|
||
|
+size_t scols_table_get_termwidth(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->termwidth;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_set_termheight
|
||
|
+ * @tb: table
|
||
|
+ * @height: terminal height (number of lines)
|
||
|
+ *
|
||
|
+ * The library automatically detects terminal height or defaults to 24 lines if
|
||
|
+ * detections is unsuccessful. This function override this behaviour.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ *
|
||
|
+ * Since: 2.31
|
||
|
+ */
|
||
|
+int scols_table_set_termheight(struct libscols_table *tb, size_t height)
|
||
|
+{
|
||
|
+ DBG(TAB, ul_debugobj(tb, "set terminatl height: %zu", height));
|
||
|
+ tb->termheight = height;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_get_termheight
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * Returns: terminal height (number of lines).
|
||
|
+ *
|
||
|
+ * Since: 2.31
|
||
|
+ */
|
||
|
+size_t scols_table_get_termheight(const struct libscols_table *tb)
|
||
|
+{
|
||
|
+ return tb->termheight;
|
||
|
+}
|
||
|
diff --git a/libsmartcols/src/table_print.c b/libsmartcols/src/table_print.c
|
||
|
index c9f3d8f4b..10126fd79 100644
|
||
|
--- a/libsmartcols/src/table_print.c
|
||
|
+++ b/libsmartcols/src/table_print.c
|
||
|
@@ -2,6 +2,7 @@
|
||
|
* table.c - functions handling the data at the table level
|
||
|
*
|
||
|
* Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
|
||
|
+ * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
|
||
|
*
|
||
|
* This file may be redistributed under the terms of the
|
||
|
* GNU Lesser General Public License.
|
||
|
@@ -10,7 +11,7 @@
|
||
|
/**
|
||
|
* SECTION: table_print
|
||
|
* @title: Table print
|
||
|
- * @short_description: table print API
|
||
|
+ * @short_description: output functions
|
||
|
*
|
||
|
* Table output API.
|
||
|
*/
|
||
|
@@ -21,13 +22,30 @@
|
||
|
#include <termios.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
-#include "nls.h"
|
||
|
#include "mbsalign.h"
|
||
|
-#include "widechar.h"
|
||
|
-#include "ttyutils.h"
|
||
|
#include "carefulputc.h"
|
||
|
#include "smartcolsP.h"
|
||
|
|
||
|
+#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ")
|
||
|
+#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n")
|
||
|
+
|
||
|
+/* Fallback for symbols
|
||
|
+ *
|
||
|
+ * Note that by default library define all the symbols, but in case user does
|
||
|
+ * not define all symbols or if we extended the symbols struct then we need
|
||
|
+ * fallback to be more robust and backwardly compatible.
|
||
|
+ */
|
||
|
+#define titlepadding_symbol(tb) ((tb)->symbols->title_padding ? (tb)->symbols->title_padding : " ")
|
||
|
+#define branch_symbol(tb) ((tb)->symbols->branch ? (tb)->symbols->branch : "|-")
|
||
|
+#define vertical_symbol(tb) ((tb)->symbols->vert ? (tb)->symbols->vert : "| ")
|
||
|
+#define right_symbol(tb) ((tb)->symbols->right ? (tb)->symbols->right : "`-")
|
||
|
+
|
||
|
+#define cellpadding_symbol(tb) ((tb)->padding_debug ? "." : \
|
||
|
+ ((tb)->symbols->cell_padding ? (tb)->symbols->cell_padding: " "))
|
||
|
+
|
||
|
+#define want_repeat_header(tb) (!(tb)->header_repeat || (tb)->header_next <= (tb)->termlines_used)
|
||
|
+
|
||
|
+
|
||
|
/* This is private struct to work with output data */
|
||
|
struct libscols_buffer {
|
||
|
char *begin; /* begin of the buffer */
|
||
|
@@ -88,7 +106,6 @@ static int buffer_append_data(struct libscols_buffer *buf, const char *str)
|
||
|
|
||
|
if (maxsz <= sz)
|
||
|
return -EINVAL;
|
||
|
-
|
||
|
memcpy(buf->cur, str, sz + 1);
|
||
|
buf->cur += sz;
|
||
|
return 0;
|
||
|
@@ -100,7 +117,7 @@ static int buffer_set_data(struct libscols_buffer *buf, const char *str)
|
||
|
return rc ? rc : buffer_append_data(buf, str);
|
||
|
}
|
||
|
|
||
|
-/* save the current buffer possition to art_idx */
|
||
|
+/* save the current buffer position to art_idx */
|
||
|
static void buffer_set_art_index(struct libscols_buffer *buf)
|
||
|
{
|
||
|
if (buf) {
|
||
|
@@ -115,7 +132,10 @@ static char *buffer_get_data(struct libscols_buffer *buf)
|
||
|
}
|
||
|
|
||
|
/* 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)
|
||
|
+static char *buffer_get_safe_data(struct libscols_table *tb,
|
||
|
+ struct libscols_buffer *buf,
|
||
|
+ size_t *cells,
|
||
|
+ const char *safechars)
|
||
|
{
|
||
|
char *data = buffer_get_data(buf);
|
||
|
char *res = NULL;
|
||
|
@@ -129,7 +149,14 @@ static char *buffer_get_safe_data(struct libscols_buffer *buf, size_t *cells)
|
||
|
goto nothing;
|
||
|
}
|
||
|
|
||
|
- res = mbs_safe_encode_to_buffer(data, cells, buf->encdata);
|
||
|
+ if (tb->no_encode) {
|
||
|
+ *cells = mbs_safe_width(data);
|
||
|
+ strcpy(buf->encdata, data);
|
||
|
+ res = buf->encdata;
|
||
|
+ } else {
|
||
|
+ res = mbs_safe_encode_to_buffer(data, cells, buf->encdata, safechars);
|
||
|
+ }
|
||
|
+
|
||
|
if (!res || !*cells || *cells == (size_t) -1)
|
||
|
goto nothing;
|
||
|
return res;
|
||
|
@@ -151,11 +178,257 @@ static size_t buffer_get_safe_art_size(struct libscols_buffer *buf)
|
||
|
return bytes;
|
||
|
}
|
||
|
|
||
|
-#define is_last_column(_tb, _cl) \
|
||
|
- list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
|
||
|
+/* 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);
|
||
|
|
||
|
-#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ")
|
||
|
-#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n")
|
||
|
+ 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 = vertical_symbol(tb);
|
||
|
+
|
||
|
+ return buffer_append_data(buf, art);
|
||
|
+}
|
||
|
+
|
||
|
+static int is_last_column(struct libscols_column *cl)
|
||
|
+{
|
||
|
+ int rc = list_entry_is_last(&cl->cl_columns, &cl->table->tb_columns);
|
||
|
+ struct libscols_column *next;
|
||
|
+
|
||
|
+ if (rc)
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ next = list_entry(cl->cl_columns.next, struct libscols_column, cl_columns);
|
||
|
+ if (next && scols_column_is_hidden(next) && is_last_column(next))
|
||
|
+ return 1;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int has_pending_data(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ struct libscols_column *cl;
|
||
|
+ struct libscols_iter itr;
|
||
|
+
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
+ if (cl->pending_data)
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/* print padding or ASCII-art instead of data of @cl */
|
||
|
+static void print_empty_cell(struct libscols_table *tb,
|
||
|
+ struct libscols_column *cl,
|
||
|
+ struct libscols_line *ln, /* optional */
|
||
|
+ size_t bufsz)
|
||
|
+{
|
||
|
+ size_t len_pad = 0; /* in screen cells as opposed to bytes */
|
||
|
+
|
||
|
+ /* generate tree ASCII-art rather than padding */
|
||
|
+ if (ln && scols_column_is_tree(cl)) {
|
||
|
+ if (!ln->parent) {
|
||
|
+ /* only print symbols->vert if followed by child */
|
||
|
+ if (!list_empty(&ln->ln_branch)) {
|
||
|
+ fputs(vertical_symbol(tb), tb->out);
|
||
|
+ len_pad = mbs_safe_width(vertical_symbol(tb));
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ /* use the same draw function as though we were intending to draw an L-shape */
|
||
|
+ struct libscols_buffer *art = new_buffer(bufsz);
|
||
|
+ char *data;
|
||
|
+
|
||
|
+ if (art) {
|
||
|
+ /* whatever the rc, len_pad will be sensible */
|
||
|
+ line_ascii_art_to_buffer(tb, ln, art);
|
||
|
+ if (!list_empty(&ln->ln_branch) && has_pending_data(tb))
|
||
|
+ buffer_append_data(art, vertical_symbol(tb));
|
||
|
+ data = buffer_get_safe_data(tb, art, &len_pad, NULL);
|
||
|
+ if (data && len_pad)
|
||
|
+ fputs(data, tb->out);
|
||
|
+ free_buffer(art);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (is_last_column(cl))
|
||
|
+ return;
|
||
|
+
|
||
|
+ /* fill rest of cell with space */
|
||
|
+ for(; len_pad < cl->width; ++len_pad)
|
||
|
+ fputs(cellpadding_symbol(tb), tb->out);
|
||
|
+
|
||
|
+ fputs(colsep(tb), tb->out);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static const char *get_cell_color(struct libscols_table *tb,
|
||
|
+ struct libscols_column *cl,
|
||
|
+ struct libscols_line *ln, /* optional */
|
||
|
+ struct libscols_cell *ce) /* optional */
|
||
|
+{
|
||
|
+ const char *color = NULL;
|
||
|
+
|
||
|
+ if (tb && tb->colors_wanted) {
|
||
|
+ if (ce)
|
||
|
+ color = ce->color;
|
||
|
+ if (ln && !color)
|
||
|
+ color = ln->color;
|
||
|
+ if (!color)
|
||
|
+ color = cl->color;
|
||
|
+ }
|
||
|
+ return color;
|
||
|
+}
|
||
|
+
|
||
|
+/* Fill the start of a line with padding (or with tree ascii-art).
|
||
|
+ *
|
||
|
+ * This is necessary after a long non-truncated column, as this requires the
|
||
|
+ * next column to be printed on the next line. For example (see 'DDD'):
|
||
|
+ *
|
||
|
+ * aaa bbb ccc ddd eee
|
||
|
+ * AAA BBB CCCCCCC
|
||
|
+ * DDD EEE
|
||
|
+ * ^^^^^^^^^^^^
|
||
|
+ * new line padding
|
||
|
+ */
|
||
|
+static void print_newline_padding(struct libscols_table *tb,
|
||
|
+ struct libscols_column *cl,
|
||
|
+ struct libscols_line *ln, /* optional */
|
||
|
+ size_t bufsz)
|
||
|
+{
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ assert(tb);
|
||
|
+ assert(cl);
|
||
|
+
|
||
|
+ fputs(linesep(tb), tb->out); /* line break */
|
||
|
+ tb->termlines_used++;
|
||
|
+
|
||
|
+ /* fill cells after line break */
|
||
|
+ for (i = 0; i <= (size_t) cl->seqnum; i++)
|
||
|
+ print_empty_cell(tb, scols_table_get_column(tb, i), ln, bufsz);
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Pending data
|
||
|
+ *
|
||
|
+ * The first line in the multi-line cells (columns with SCOLS_FL_WRAP flag) is
|
||
|
+ * printed as usually and output is truncated to match column width.
|
||
|
+ *
|
||
|
+ * The rest of the long text is printed on next extra line(s). The extra lines
|
||
|
+ * don't exist in the table (not represented by libscols_line). The data for
|
||
|
+ * the extra lines are stored in libscols_column->pending_data_buf and the
|
||
|
+ * function print_line() adds extra lines until the buffer is not empty in all
|
||
|
+ * columns.
|
||
|
+ */
|
||
|
+
|
||
|
+/* set data that will be printed by extra lines */
|
||
|
+static int set_pending_data(struct libscols_column *cl, const char *data, size_t sz)
|
||
|
+{
|
||
|
+ char *p = NULL;
|
||
|
+
|
||
|
+ if (data && *data) {
|
||
|
+ DBG(COL, ul_debugobj(cl, "setting pending data"));
|
||
|
+ assert(sz);
|
||
|
+ p = strdup(data);
|
||
|
+ if (!p)
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ free(cl->pending_data_buf);
|
||
|
+ cl->pending_data_buf = p;
|
||
|
+ cl->pending_data_sz = sz;
|
||
|
+ cl->pending_data = cl->pending_data_buf;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/* the next extra line has been printed, move pending data cursor */
|
||
|
+static int step_pending_data(struct libscols_column *cl, size_t bytes)
|
||
|
+{
|
||
|
+ DBG(COL, ul_debugobj(cl, "step pending data %zu -= %zu", cl->pending_data_sz, bytes));
|
||
|
+
|
||
|
+ if (bytes >= cl->pending_data_sz)
|
||
|
+ return set_pending_data(cl, NULL, 0);
|
||
|
+
|
||
|
+ cl->pending_data += bytes;
|
||
|
+ cl->pending_data_sz -= bytes;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/* print next pending data for the column @cl */
|
||
|
+static int print_pending_data(
|
||
|
+ struct libscols_table *tb,
|
||
|
+ struct libscols_column *cl,
|
||
|
+ struct libscols_line *ln, /* optional */
|
||
|
+ struct libscols_cell *ce)
|
||
|
+{
|
||
|
+ const char *color = get_cell_color(tb, cl, ln, ce);
|
||
|
+ size_t width = cl->width, bytes;
|
||
|
+ size_t len = width, i;
|
||
|
+ char *data;
|
||
|
+ char *nextchunk = NULL;
|
||
|
+
|
||
|
+ if (!cl->pending_data)
|
||
|
+ return 0;
|
||
|
+ if (!width)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ DBG(COL, ul_debugobj(cl, "printing pending data"));
|
||
|
+
|
||
|
+ data = strdup(cl->pending_data);
|
||
|
+ if (!data)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ if (scols_column_is_customwrap(cl)
|
||
|
+ && (nextchunk = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data))) {
|
||
|
+ bytes = nextchunk - data;
|
||
|
+
|
||
|
+ len = mbs_safe_nwidth(data, bytes, NULL);
|
||
|
+ } else
|
||
|
+ bytes = mbs_truncate(data, &len);
|
||
|
+
|
||
|
+ if (bytes == (size_t) -1)
|
||
|
+ goto err;
|
||
|
+
|
||
|
+ if (bytes)
|
||
|
+ step_pending_data(cl, bytes);
|
||
|
+
|
||
|
+ if (color)
|
||
|
+ fputs(color, tb->out);
|
||
|
+ fputs(data, tb->out);
|
||
|
+ if (color)
|
||
|
+ fputs(UL_COLOR_RESET, tb->out);
|
||
|
+ free(data);
|
||
|
+
|
||
|
+ if (is_last_column(cl))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ for (i = len; i < width; i++)
|
||
|
+ fputs(cellpadding_symbol(tb), tb->out); /* padding */
|
||
|
+
|
||
|
+ fputs(colsep(tb), tb->out); /* columns separator */
|
||
|
+ return 0;
|
||
|
+err:
|
||
|
+ free(data);
|
||
|
+ return -errno;
|
||
|
+}
|
||
|
|
||
|
static int print_data(struct libscols_table *tb,
|
||
|
struct libscols_column *cl,
|
||
|
@@ -165,76 +438,120 @@ static int print_data(struct libscols_table *tb,
|
||
|
{
|
||
|
size_t len = 0, i, width, bytes;
|
||
|
const char *color = NULL;
|
||
|
- char *data;
|
||
|
+ char *data, *nextchunk;
|
||
|
+ int is_last;
|
||
|
|
||
|
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)) {
|
||
|
+ is_last = is_last_column(cl);
|
||
|
+
|
||
|
+ switch (tb->format) {
|
||
|
+ case SCOLS_FMT_RAW:
|
||
|
fputs_nonblank(data, tb->out);
|
||
|
- if (!is_last_column(tb, cl))
|
||
|
+ if (!is_last)
|
||
|
fputs(colsep(tb), tb->out);
|
||
|
return 0;
|
||
|
- }
|
||
|
|
||
|
- /* NAME=value mode */
|
||
|
- if (scols_table_is_export(tb)) {
|
||
|
+ case SCOLS_FMT_EXPORT:
|
||
|
fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header));
|
||
|
fputs_quoted(data, tb->out);
|
||
|
- if (!is_last_column(tb, cl))
|
||
|
+ if (!is_last)
|
||
|
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;
|
||
|
+ case SCOLS_FMT_JSON:
|
||
|
+ fputs_quoted_json_lower(scols_cell_get_data(&cl->header), tb->out);
|
||
|
+ fputs(":", tb->out);
|
||
|
+ switch (cl->json_type) {
|
||
|
+ case SCOLS_JSON_STRING:
|
||
|
+ if (!*data)
|
||
|
+ fputs("null", tb->out);
|
||
|
+ else
|
||
|
+ fputs_quoted_json(data, tb->out);
|
||
|
+ break;
|
||
|
+ case SCOLS_JSON_NUMBER:
|
||
|
+ if (!*data)
|
||
|
+ fputs("null", tb->out);
|
||
|
+ else
|
||
|
+ fputs(data, tb->out);
|
||
|
+ break;
|
||
|
+ case SCOLS_JSON_BOOLEAN:
|
||
|
+ fputs(!*data ? "false" :
|
||
|
+ *data == '0' ? "false" :
|
||
|
+ *data == 'N' || *data == 'n' ? "false" : "true",
|
||
|
+ tb->out);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (!is_last)
|
||
|
+ fputs(", ", tb->out);
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ case SCOLS_FMT_HUMAN:
|
||
|
+ break; /* continue below */
|
||
|
}
|
||
|
|
||
|
- /* encode, note that 'len' and 'width' are number of cells, not bytes */
|
||
|
- data = buffer_get_safe_data(buf, &len);
|
||
|
+ color = get_cell_color(tb, cl, ln, ce);
|
||
|
+
|
||
|
+ /* Encode. Note that 'len' and 'width' are number of cells, not bytes.
|
||
|
+ */
|
||
|
+ data = buffer_get_safe_data(tb, buf, &len, scols_column_get_safechars(cl));
|
||
|
if (!data)
|
||
|
data = "";
|
||
|
- width = cl->width;
|
||
|
bytes = strlen(data);
|
||
|
+ width = cl->width;
|
||
|
+
|
||
|
+ /* custom multi-line cell based */
|
||
|
+ if (*data && scols_column_is_customwrap(cl)
|
||
|
+ && (nextchunk = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data))) {
|
||
|
+ set_pending_data(cl, nextchunk, bytes - (nextchunk - data));
|
||
|
+ bytes = nextchunk - data;
|
||
|
+ len = mbs_safe_nwidth(data, bytes, NULL);
|
||
|
+ }
|
||
|
|
||
|
- if (is_last_column(tb, cl) && len < width && !scols_table_is_maxout(tb))
|
||
|
+ if (is_last
|
||
|
+ && len < width
|
||
|
+ && !scols_table_is_maxout(tb)
|
||
|
+ && !scols_column_is_right(cl))
|
||
|
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;
|
||
|
- }
|
||
|
+ /* standard multi-line cell */
|
||
|
+ if (len > width && scols_column_is_wrap(cl)
|
||
|
+ && !scols_column_is_customwrap(cl)) {
|
||
|
+ set_pending_data(cl, data, bytes);
|
||
|
+
|
||
|
+ len = width;
|
||
|
+ bytes = mbs_truncate(data, &len);
|
||
|
+ if (bytes != (size_t) -1 && bytes > 0)
|
||
|
+ step_pending_data(cl, bytes);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (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);
|
||
|
+ for (i = len; i < width; i++)
|
||
|
+ fputs(cellpadding_symbol(tb), tb->out);
|
||
|
+ fputs(data, tb->out);
|
||
|
if (color)
|
||
|
fputs(UL_COLOR_RESET, tb->out);
|
||
|
- if (len < xw)
|
||
|
- len = xw;
|
||
|
+ len = width;
|
||
|
+
|
||
|
} else if (color) {
|
||
|
char *p = data;
|
||
|
size_t art = buffer_get_safe_art_size(buf);
|
||
|
@@ -252,46 +569,17 @@ static int print_data(struct libscols_table *tb,
|
||
|
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;
|
||
|
+ fputs(cellpadding_symbol(tb), tb->out); /* padding */
|
||
|
|
||
|
- assert(ln);
|
||
|
- assert(buf);
|
||
|
-
|
||
|
- if (!ln->parent)
|
||
|
+ if (is_last)
|
||
|
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 = " ";
|
||
|
+ if (len > width && !scols_column_is_trunc(cl))
|
||
|
+ print_newline_padding(tb, cl, ln, buf->bufsz); /* next column starts on next line */
|
||
|
else
|
||
|
- art = tb->symbols->vert;
|
||
|
+ fputs(colsep(tb), tb->out); /* columns separator */
|
||
|
|
||
|
- return buffer_append_data(buf, art);
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
static int cell_to_buffer(struct libscols_table *tb,
|
||
|
@@ -322,13 +610,13 @@ static int cell_to_buffer(struct libscols_table *tb,
|
||
|
/*
|
||
|
* Tree stuff
|
||
|
*/
|
||
|
- if (ln->parent) {
|
||
|
+ if (ln->parent && !scols_table_is_json(tb)) {
|
||
|
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);
|
||
|
+ rc = buffer_append_data(buf, right_symbol(tb));
|
||
|
else if (!rc)
|
||
|
- rc = buffer_append_data(buf, tb->symbols->branch);
|
||
|
+ rc = buffer_append_data(buf, branch_symbol(tb));
|
||
|
if (!rc)
|
||
|
buffer_set_art_index(buf);
|
||
|
}
|
||
|
@@ -338,34 +626,252 @@ static int cell_to_buffer(struct libscols_table *tb,
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
+static void fput_indent(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i <= tb->indent; i++)
|
||
|
+ fputs(" ", tb->out);
|
||
|
+}
|
||
|
+
|
||
|
+static void fput_table_open(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ tb->indent = 0;
|
||
|
+
|
||
|
+ if (scols_table_is_json(tb)) {
|
||
|
+ fputc('{', tb->out);
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+
|
||
|
+ fput_indent(tb);
|
||
|
+ fputs_quoted(tb->name, tb->out);
|
||
|
+ fputs(": [", tb->out);
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+
|
||
|
+ tb->indent++;
|
||
|
+ tb->indent_last_sep = 1;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void fput_table_close(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ tb->indent--;
|
||
|
+
|
||
|
+ if (scols_table_is_json(tb)) {
|
||
|
+ fput_indent(tb);
|
||
|
+ fputc(']', tb->out);
|
||
|
+ tb->indent--;
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+ fputc('}', tb->out);
|
||
|
+ tb->indent_last_sep = 1;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void fput_children_open(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ if (scols_table_is_json(tb)) {
|
||
|
+ fputc(',', tb->out);
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+ fput_indent(tb);
|
||
|
+ fputs("\"children\": [", tb->out);
|
||
|
+ }
|
||
|
+ /* between parent and child is separator */
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+ tb->indent_last_sep = 1;
|
||
|
+ tb->indent++;
|
||
|
+ tb->termlines_used++;
|
||
|
+}
|
||
|
+
|
||
|
+static void fput_children_close(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ tb->indent--;
|
||
|
+
|
||
|
+ if (scols_table_is_json(tb)) {
|
||
|
+ fput_indent(tb);
|
||
|
+ fputc(']', tb->out);
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+ tb->indent_last_sep = 1;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void fput_line_open(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ if (scols_table_is_json(tb)) {
|
||
|
+ fput_indent(tb);
|
||
|
+ fputc('{', tb->out);
|
||
|
+ tb->indent_last_sep = 0;
|
||
|
+ }
|
||
|
+ tb->indent++;
|
||
|
+}
|
||
|
+
|
||
|
+static void fput_line_close(struct libscols_table *tb, int last, int last_in_table)
|
||
|
+{
|
||
|
+ tb->indent--;
|
||
|
+ if (scols_table_is_json(tb)) {
|
||
|
+ if (tb->indent_last_sep)
|
||
|
+ fput_indent(tb);
|
||
|
+ fputs(last ? "}" : "},", tb->out);
|
||
|
+ if (!tb->no_linesep)
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+
|
||
|
+ } else if (tb->no_linesep == 0 && last_in_table == 0) {
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+ tb->termlines_used++;
|
||
|
+ }
|
||
|
+
|
||
|
+ tb->indent_last_sep = 1;
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
- * 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.
|
||
|
+ * Prints data. Data can be printed in more formats (raw, NAME=xxx pairs), and
|
||
|
+ * control and non-printable characters can be encoded in the \x?? encoding.
|
||
|
*/
|
||
|
static int print_line(struct libscols_table *tb,
|
||
|
struct libscols_line *ln,
|
||
|
struct libscols_buffer *buf)
|
||
|
{
|
||
|
- int rc = 0;
|
||
|
+ int rc = 0, pending = 0;
|
||
|
struct libscols_column *cl;
|
||
|
struct libscols_iter itr;
|
||
|
|
||
|
assert(ln);
|
||
|
|
||
|
- DBG(TAB, ul_debugobj(tb, "printing line, line=%p, buff=%p", ln, buf));
|
||
|
+ DBG(TAB, ul_debugobj(tb, "printing line"));
|
||
|
|
||
|
+ /* regular line */
|
||
|
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
rc = cell_to_buffer(tb, ln, cl, buf);
|
||
|
- if (!rc)
|
||
|
+ if (rc == 0)
|
||
|
rc = print_data(tb, cl, ln,
|
||
|
scols_line_get_cell(ln, cl->seqnum),
|
||
|
buf);
|
||
|
+ if (rc == 0 && cl->pending_data)
|
||
|
+ pending = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* extra lines of the multi-line cells */
|
||
|
+ while (rc == 0 && pending) {
|
||
|
+ pending = 0;
|
||
|
+ fputs(linesep(tb), tb->out);
|
||
|
+ tb->termlines_used++;
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+ while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
+ if (cl->pending_data) {
|
||
|
+ rc = print_pending_data(tb, cl, ln, scols_line_get_cell(ln, cl->seqnum));
|
||
|
+ if (rc == 0 && cl->pending_data)
|
||
|
+ pending = 1;
|
||
|
+ } else
|
||
|
+ print_empty_cell(tb, cl, ln, buf->bufsz);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
- if (rc == 0)
|
||
|
- fputs(linesep(tb), tb->out);
|
||
|
- return 0;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int print_title(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ int rc, color = 0;
|
||
|
+ mbs_align_t align;
|
||
|
+ size_t width, len = 0, bufsz, titlesz;
|
||
|
+ char *title = NULL, *buf = NULL;
|
||
|
+
|
||
|
+ assert(tb);
|
||
|
+
|
||
|
+ if (!tb->title.data)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, "printing title"));
|
||
|
+
|
||
|
+ /* encode data */
|
||
|
+ if (tb->no_encode) {
|
||
|
+ len = bufsz = strlen(tb->title.data) + 1;
|
||
|
+ buf = strdup(tb->title.data);
|
||
|
+ if (!buf) {
|
||
|
+ rc = -ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ bufsz = mbs_safe_encode_size(strlen(tb->title.data)) + 1;
|
||
|
+ if (bufsz == 1) {
|
||
|
+ DBG(TAB, ul_debugobj(tb, "title is empty string -- ignore"));
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ buf = malloc(bufsz);
|
||
|
+ if (!buf) {
|
||
|
+ rc = -ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!mbs_safe_encode_to_buffer(tb->title.data, &len, buf, NULL) ||
|
||
|
+ !len || len == (size_t) -1) {
|
||
|
+ rc = -EINVAL;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* truncate and align */
|
||
|
+ width = tb->is_term ? tb->termwidth : 80;
|
||
|
+ titlesz = width + bufsz;
|
||
|
+
|
||
|
+ title = malloc(titlesz);
|
||
|
+ if (!title) {
|
||
|
+ rc = -EINVAL;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ switch (scols_cell_get_alignment(&tb->title)) {
|
||
|
+ case SCOLS_CELL_FL_RIGHT:
|
||
|
+ align = MBS_ALIGN_RIGHT;
|
||
|
+ break;
|
||
|
+ case SCOLS_CELL_FL_CENTER:
|
||
|
+ align = MBS_ALIGN_CENTER;
|
||
|
+ break;
|
||
|
+ case SCOLS_CELL_FL_LEFT:
|
||
|
+ default:
|
||
|
+ align = MBS_ALIGN_LEFT;
|
||
|
+ /*
|
||
|
+ * Don't print extra blank chars after the title if on left
|
||
|
+ * (that's same as we use for the last column in the table).
|
||
|
+ */
|
||
|
+ if (len < width
|
||
|
+ && !scols_table_is_maxout(tb)
|
||
|
+ && isblank(*titlepadding_symbol(tb)))
|
||
|
+ width = len;
|
||
|
+ break;
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+ /* copy from buf to title and align to width with title_padding */
|
||
|
+ rc = mbsalign_with_padding(buf, title, titlesz,
|
||
|
+ &width, align,
|
||
|
+ 0, (int) *titlepadding_symbol(tb));
|
||
|
+
|
||
|
+ if (rc == -1) {
|
||
|
+ rc = -EINVAL;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (tb->colors_wanted && tb->title.color)
|
||
|
+ color = 1;
|
||
|
+ if (color)
|
||
|
+ fputs(tb->title.color, tb->out);
|
||
|
+
|
||
|
+ fputs(title, tb->out);
|
||
|
+
|
||
|
+ if (color)
|
||
|
+ fputs(UL_COLOR_RESET, tb->out);
|
||
|
+
|
||
|
+ fputc('\n', tb->out);
|
||
|
+ rc = 0;
|
||
|
+done:
|
||
|
+ free(buf);
|
||
|
+ free(title);
|
||
|
+ DBG(TAB, ul_debugobj(tb, "printing title done [rc=%d]", rc));
|
||
|
+ return rc;
|
||
|
}
|
||
|
|
||
|
static int print_header(struct libscols_table *tb, struct libscols_buffer *buf)
|
||
|
@@ -376,86 +882,139 @@ static int print_header(struct libscols_table *tb, struct libscols_buffer *buf)
|
||
|
|
||
|
assert(tb);
|
||
|
|
||
|
- if (scols_table_is_noheadings(tb) ||
|
||
|
+ if ((tb->header_printed == 1 && tb->header_repeat == 0) ||
|
||
|
+ scols_table_is_noheadings(tb) ||
|
||
|
scols_table_is_export(tb) ||
|
||
|
+ scols_table_is_json(tb) ||
|
||
|
list_empty(&tb->tb_lines))
|
||
|
return 0;
|
||
|
|
||
|
DBG(TAB, ul_debugobj(tb, "printing header"));
|
||
|
|
||
|
- /* set width according to the size of data
|
||
|
- */
|
||
|
+ /* set the width according to the size of the data */
|
||
|
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
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)
|
||
|
+ if (rc == 0) {
|
||
|
fputs(linesep(tb), tb->out);
|
||
|
+ tb->termlines_used++;
|
||
|
+ }
|
||
|
+
|
||
|
+ tb->header_printed = 1;
|
||
|
+ tb->header_next = tb->termlines_used + tb->termheight;
|
||
|
+ if (tb->header_repeat)
|
||
|
+ DBG(TAB, ul_debugobj(tb, "\tnext header: %zu [current=%zu]",
|
||
|
+ tb->header_next, tb->termlines_used));
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
-static int print_table(struct libscols_table *tb, struct libscols_buffer *buf)
|
||
|
+
|
||
|
+static int print_range( struct libscols_table *tb,
|
||
|
+ struct libscols_buffer *buf,
|
||
|
+ struct libscols_iter *itr,
|
||
|
+ struct libscols_line *end)
|
||
|
{
|
||
|
- int rc;
|
||
|
+ int rc = 0;
|
||
|
struct libscols_line *ln;
|
||
|
- struct libscols_iter itr;
|
||
|
|
||
|
assert(tb);
|
||
|
+ DBG(TAB, ul_debugobj(tb, "printing range"));
|
||
|
|
||
|
- rc = print_header(tb, buf);
|
||
|
+ while (rc == 0 && scols_table_next_line(tb, itr, &ln) == 0) {
|
||
|
|
||
|
- scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
- while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0)
|
||
|
+ int last = scols_iter_is_last(itr);
|
||
|
+
|
||
|
+ fput_line_open(tb);
|
||
|
rc = print_line(tb, ln, buf);
|
||
|
+ fput_line_close(tb, last, last);
|
||
|
+
|
||
|
+ if (end && ln == end)
|
||
|
+ break;
|
||
|
+
|
||
|
+ if (!last && want_repeat_header(tb))
|
||
|
+ print_header(tb, buf);
|
||
|
+ }
|
||
|
|
||
|
return rc;
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static int print_table(struct libscols_table *tb, struct libscols_buffer *buf)
|
||
|
+{
|
||
|
+ struct libscols_iter itr;
|
||
|
+
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+ return print_range(tb, buf, &itr, NULL);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
static int print_tree_line(struct libscols_table *tb,
|
||
|
struct libscols_line *ln,
|
||
|
- struct libscols_buffer *buf)
|
||
|
+ struct libscols_buffer *buf,
|
||
|
+ int last,
|
||
|
+ int last_in_table)
|
||
|
{
|
||
|
int rc;
|
||
|
- struct list_head *p;
|
||
|
|
||
|
+ /* print the line */
|
||
|
+ fput_line_open(tb);
|
||
|
rc = print_line(tb, ln, buf);
|
||
|
if (rc)
|
||
|
- return rc;
|
||
|
- if (list_empty(&ln->ln_branch))
|
||
|
- return 0;
|
||
|
+ goto done;
|
||
|
|
||
|
- /* 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;
|
||
|
+ /* print children */
|
||
|
+ if (!list_empty(&ln->ln_branch)) {
|
||
|
+ struct list_head *p;
|
||
|
+
|
||
|
+ fput_children_open(tb);
|
||
|
+
|
||
|
+ /* print all children */
|
||
|
+ list_for_each(p, &ln->ln_branch) {
|
||
|
+ struct libscols_line *chld =
|
||
|
+ list_entry(p, struct libscols_line, ln_children);
|
||
|
+ int last_child = p->next == &ln->ln_branch;
|
||
|
+
|
||
|
+ rc = print_tree_line(tb, chld, buf, last_child, last_in_table && last_child);
|
||
|
+ if (rc)
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ fput_children_close(tb);
|
||
|
}
|
||
|
|
||
|
+ if (list_empty(&ln->ln_branch) || scols_table_is_json(tb))
|
||
|
+ fput_line_close(tb, last, last_in_table);
|
||
|
+done:
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf)
|
||
|
{
|
||
|
- int rc;
|
||
|
- struct libscols_line *ln;
|
||
|
+ int rc = 0;
|
||
|
+ struct libscols_line *ln, *last = NULL;
|
||
|
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 (scols_table_next_line(tb, &itr, &ln) == 0)
|
||
|
+ if (!last || !ln->parent)
|
||
|
+ last = ln;
|
||
|
|
||
|
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);
|
||
|
+ rc = print_tree_line(tb, ln, buf, ln == last, ln == last);
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
@@ -463,9 +1022,14 @@ static int print_tree(struct libscols_table *tb, struct libscols_buffer *buf)
|
||
|
|
||
|
static void dbg_column(struct libscols_table *tb, struct libscols_column *cl)
|
||
|
{
|
||
|
+ if (scols_column_is_hidden(cl)) {
|
||
|
+ DBG(COL, ul_debugobj(cl, "%s (hidden) ignored", cl->header.data));
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
DBG(COL, ul_debugobj(cl, "%15s seq=%zu, width=%zd, "
|
||
|
"hint=%d, avg=%zu, max=%zu, min=%zu, "
|
||
|
- "extreme=%s",
|
||
|
+ "extreme=%s %s",
|
||
|
|
||
|
cl->header.data, cl->seqnum, cl->width,
|
||
|
cl->width_hint > 1 ? (int) cl->width_hint :
|
||
|
@@ -473,7 +1037,8 @@ static void dbg_column(struct libscols_table *tb, struct libscols_column *cl)
|
||
|
cl->width_avg,
|
||
|
cl->width_max,
|
||
|
cl->width_min,
|
||
|
- cl->is_extreme ? "yes" : "not"));
|
||
|
+ cl->is_extreme ? "yes" : "not",
|
||
|
+ cl->flags & SCOLS_FL_TRUNC ? "trunc" : ""));
|
||
|
}
|
||
|
|
||
|
static void dbg_columns(struct libscols_table *tb)
|
||
|
@@ -486,14 +1051,15 @@ static void dbg_columns(struct libscols_table *tb)
|
||
|
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.
|
||
|
+ * For the SCOLS_FL_NOEXTREMES columns it is possible to call this function
|
||
|
+ * two times. The first pass counts the width and average width. If the column
|
||
|
+ * contains fields that are too large (a width greater than 2 * average) then
|
||
|
+ * the column is marked as "extreme". In the second pass all extreme fields
|
||
|
+ * are ignored and the column width is counted from non-extreme fields only.
|
||
|
*/
|
||
|
static int count_column_width(struct libscols_table *tb,
|
||
|
struct libscols_column *cl,
|
||
|
@@ -508,6 +1074,19 @@ static int count_column_width(struct libscols_table *tb,
|
||
|
assert(cl);
|
||
|
|
||
|
cl->width = 0;
|
||
|
+ if (!cl->width_min) {
|
||
|
+ if (cl->width_hint < 1 && scols_table_is_maxout(tb) && tb->is_term) {
|
||
|
+ cl->width_min = (size_t) (cl->width_hint * tb->termwidth);
|
||
|
+ if (cl->width_min && !is_last_column(cl))
|
||
|
+ cl->width_min--;
|
||
|
+ }
|
||
|
+ if (scols_cell_get_data(&cl->header)) {
|
||
|
+ size_t len = mbs_safe_width(scols_cell_get_data(&cl->header));
|
||
|
+ cl->width_min = max(cl->width_min, len);
|
||
|
+ }
|
||
|
+ if (!cl->width_min)
|
||
|
+ cl->width_min = 1;
|
||
|
+ }
|
||
|
|
||
|
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
while (scols_table_next_line(tb, &itr, &ln) == 0) {
|
||
|
@@ -516,15 +1095,20 @@ static int count_column_width(struct libscols_table *tb,
|
||
|
|
||
|
rc = cell_to_buffer(tb, ln, cl, buf);
|
||
|
if (rc)
|
||
|
- return rc;
|
||
|
+ goto done;
|
||
|
|
||
|
data = buffer_get_data(buf);
|
||
|
- len = data ? mbs_safe_width(data) : 0;
|
||
|
+
|
||
|
+ if (!data)
|
||
|
+ len = 0;
|
||
|
+ else if (scols_column_is_customwrap(cl))
|
||
|
+ len = cl->wrap_chunksize(cl, data, cl->wrapfunc_data);
|
||
|
+ else
|
||
|
+ len = mbs_safe_width(data);
|
||
|
|
||
|
if (len == (size_t) -1) /* ignore broken multibyte strings */
|
||
|
len = 0;
|
||
|
- if (len > cl->width_max)
|
||
|
- cl->width_max = len;
|
||
|
+ cl->width_max = max(len, cl->width_max);
|
||
|
|
||
|
if (cl->is_extreme && len > cl->width_avg * 2)
|
||
|
continue;
|
||
|
@@ -532,81 +1116,105 @@ static int count_column_width(struct libscols_table *tb,
|
||
|
sum += len;
|
||
|
count++;
|
||
|
}
|
||
|
- if (len > cl->width)
|
||
|
- cl->width = len;
|
||
|
+ cl->width = max(len, cl->width);
|
||
|
+ if (scols_column_is_tree(cl)) {
|
||
|
+ size_t treewidth = buffer_get_safe_art_size(buf);
|
||
|
+ cl->width_treeart = max(cl->width_treeart, treewidth);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
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 */
|
||
|
+ /* use absolute 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;
|
||
|
|
||
|
+done:
|
||
|
ON_DBG(COL, dbg_column(tb, cl));
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
-
|
||
|
/*
|
||
|
- * This is core of the scols_* voodo...
|
||
|
+ * This is core of the scols_* voodoo...
|
||
|
*/
|
||
|
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;
|
||
|
+ size_t width = 0, width_min = 0; /* output width */
|
||
|
+ int stage, rc = 0;
|
||
|
int extremes = 0;
|
||
|
+ size_t colsepsz;
|
||
|
|
||
|
|
||
|
DBG(TAB, ul_debugobj(tb, "recounting widths (termwidth=%zu)", tb->termwidth));
|
||
|
|
||
|
+ colsepsz = mbs_safe_width(colsep(tb));
|
||
|
+
|
||
|
/* set basic columns width
|
||
|
*/
|
||
|
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
while (scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+ int is_last;
|
||
|
+
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
rc = count_column_width(tb, cl, buf);
|
||
|
if (rc)
|
||
|
- return rc;
|
||
|
+ goto done;
|
||
|
+
|
||
|
+ is_last = is_last_column(cl);
|
||
|
|
||
|
- width += cl->width + (is_last_column(tb, cl) ? 0 : 1);
|
||
|
+ width += cl->width + (is_last ? 0 : colsepsz); /* separator for non-last column */
|
||
|
+ width_min += cl->width_min + (is_last ? 0 : colsepsz);
|
||
|
extremes += cl->is_extreme;
|
||
|
}
|
||
|
|
||
|
- if (!tb->is_term)
|
||
|
- return 0;
|
||
|
+ if (!tb->is_term) {
|
||
|
+ DBG(TAB, ul_debugobj(tb, " non-terminal output"));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
|
||
|
- /* reduce columns with extreme fields
|
||
|
- */
|
||
|
+ /* be paranoid */
|
||
|
+ if (width_min > tb->termwidth && scols_table_is_maxout(tb)) {
|
||
|
+ DBG(TAB, ul_debugobj(tb, " min width larger than terminal! [width=%zu, term=%zu]", width_min, tb->termwidth));
|
||
|
+
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+ while (width_min > tb->termwidth
|
||
|
+ && scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
+ width_min--;
|
||
|
+ cl->width_min--;
|
||
|
+ }
|
||
|
+ DBG(TAB, ul_debugobj(tb, " min width reduced to %zu", width_min));
|
||
|
+ }
|
||
|
+
|
||
|
+ /* reduce columns with extreme fields */
|
||
|
if (width > tb->termwidth && extremes) {
|
||
|
- DBG(TAB, ul_debugobj(tb, " reduce width (extreme columns)"));
|
||
|
+ 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)
|
||
|
+ if (!cl->is_extreme || scols_column_is_hidden(cl))
|
||
|
continue;
|
||
|
|
||
|
org_width = cl->width;
|
||
|
rc = count_column_width(tb, cl, buf);
|
||
|
if (rc)
|
||
|
- return rc;
|
||
|
+ goto done;
|
||
|
|
||
|
if (org_width > cl->width)
|
||
|
width -= org_width - cl->width;
|
||
|
@@ -617,17 +1225,17 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf
|
||
|
|
||
|
if (width < tb->termwidth) {
|
||
|
if (extremes) {
|
||
|
- DBG(TAB, ul_debugobj(tb, " enlarge width (extreme columns)"));
|
||
|
+ 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)
|
||
|
+ if (!cl->is_extreme || scols_column_is_hidden(cl))
|
||
|
continue;
|
||
|
|
||
|
- /* this column is tooo large, ignore?
|
||
|
+ /* this column is too large, ignore?
|
||
|
if (cl->width_max - cl->width >
|
||
|
(tb->termwidth - width))
|
||
|
continue;
|
||
|
@@ -646,12 +1254,14 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf
|
||
|
}
|
||
|
|
||
|
if (width < tb->termwidth && scols_table_is_maxout(tb)) {
|
||
|
- DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)"));
|
||
|
+ DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)"));
|
||
|
|
||
|
- /* try enlarge all columns */
|
||
|
+ /* try enlarging all columns */
|
||
|
while (width < tb->termwidth) {
|
||
|
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
while (scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
cl->width++;
|
||
|
width++;
|
||
|
if (width == tb->termwidth)
|
||
|
@@ -660,67 +1270,133 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf
|
||
|
}
|
||
|
} else if (width < tb->termwidth) {
|
||
|
/* enlarge the last column */
|
||
|
- struct libscols_column *cl = list_entry(
|
||
|
+ struct libscols_column *col = list_entry(
|
||
|
tb->tb_columns.prev, struct libscols_column, cl_columns);
|
||
|
|
||
|
- DBG(TAB, ul_debugobj(tb, " enlarge width (last column)"));
|
||
|
+ DBG(TAB, ul_debugobj(tb, " enlarge width (last column)"));
|
||
|
|
||
|
- if (!scols_column_is_right(cl) && tb->termwidth - width > 0) {
|
||
|
- cl->width += tb->termwidth - width;
|
||
|
+ if (!scols_column_is_right(col) && tb->termwidth - width > 0) {
|
||
|
+ col->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
|
||
|
+ /* bad, we have to reduce output width, this is done in three stages:
|
||
|
+ *
|
||
|
+ * 1) trunc relative with trunc flag if the column width is greater than
|
||
|
+ * expected column width (it means "width_hint * terminal_width").
|
||
|
+ *
|
||
|
+ * 2) trunc all with trunc flag
|
||
|
+ *
|
||
|
+ * 3) trunc relative without trunc flag
|
||
|
+ *
|
||
|
+ * Note that SCOLS_FL_WRAP (if no custom wrap function is specified) is
|
||
|
+ * interpreted as SCOLS_FL_TRUNC.
|
||
|
*/
|
||
|
- trunc_only = 1;
|
||
|
- while (width > tb->termwidth) {
|
||
|
- size_t org = width;
|
||
|
+ for (stage = 1; width > tb->termwidth && stage <= 3; ) {
|
||
|
+ size_t org_width = width;
|
||
|
|
||
|
- DBG(TAB, ul_debugobj(tb, " reduce width (current=%zu, "
|
||
|
- "wanted=%zu, mode=%s)",
|
||
|
- width, tb->termwidth,
|
||
|
- trunc_only ? "trunc-only" : "all-relative"));
|
||
|
+ DBG(TAB, ul_debugobj(tb, " reduce width - #%d stage (current=%zu, wanted=%zu)",
|
||
|
+ stage, width, tb->termwidth));
|
||
|
|
||
|
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
while (scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+
|
||
|
+ int trunc_flag = 0;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(cl, " checking %s (width=%zu, treeart=%zu)",
|
||
|
+ cl->header.data, cl->width, cl->width_treeart));
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
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;
|
||
|
+
|
||
|
+ /* never truncate if already minimal width */
|
||
|
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) {
|
||
|
+ /* never truncate the tree */
|
||
|
+ if (scols_column_is_tree(cl) && width <= cl->width_treeart)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ /* nothing to truncate */
|
||
|
+ if (cl->width == 0 || width == 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ trunc_flag = scols_column_is_trunc(cl)
|
||
|
+ || (scols_column_is_wrap(cl) && !scols_column_is_customwrap(cl));
|
||
|
+
|
||
|
+ switch (stage) {
|
||
|
+ /* #1 stage - trunc relative with TRUNC flag */
|
||
|
+ case 1:
|
||
|
+ if (!trunc_flag) /* ignore: missing flag */
|
||
|
+ break;
|
||
|
+ if (cl->width_hint <= 0 || cl->width_hint >= 1) /* ignore: no relative */
|
||
|
+ break;
|
||
|
+ if (cl->width < (size_t) (cl->width_hint * tb->termwidth)) /* ignore: smaller than expected width */
|
||
|
+ break;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, " reducing (relative with flag)"));
|
||
|
cl->width--;
|
||
|
width--;
|
||
|
- }
|
||
|
- /* truncate column with absolute size */
|
||
|
- if (cl->width_hint > 1 && cl->width > 0 && width > 0 &&
|
||
|
- !trunc_only) {
|
||
|
+ break;
|
||
|
+
|
||
|
+ /* #2 stage - trunc all with TRUNC flag */
|
||
|
+ case 2:
|
||
|
+ if (!trunc_flag) /* ignore: missing flag */
|
||
|
+ break;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, " reducing (all with flag)"));
|
||
|
cl->width--;
|
||
|
width--;
|
||
|
+ break;
|
||
|
+
|
||
|
+ /* #3 stage - trunc relative without flag */
|
||
|
+ case 3:
|
||
|
+ if (cl->width_hint <= 0 || cl->width_hint >= 1) /* ignore: no relative */
|
||
|
+ break;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, " reducing (relative without flag)"));
|
||
|
+ cl->width--;
|
||
|
+ width--;
|
||
|
+ break;
|
||
|
}
|
||
|
|
||
|
+ /* hide zero width columns */
|
||
|
+ if (cl->width == 0)
|
||
|
+ cl->flags |= SCOLS_FL_HIDDEN;
|
||
|
}
|
||
|
- if (org == width) {
|
||
|
- if (trunc_only)
|
||
|
- trunc_only = 0;
|
||
|
- else
|
||
|
+
|
||
|
+ /* the current stage is without effect, go to the next */
|
||
|
+ if (org_width == width)
|
||
|
+ stage++;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* ignore last column(s) or force last column to be truncated if
|
||
|
+ * nowrap mode enabled */
|
||
|
+ if (tb->no_wrap && width > tb->termwidth) {
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_BACKWARD);
|
||
|
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
+ if (width <= tb->termwidth)
|
||
|
break;
|
||
|
+ if (width - cl->width < tb->termwidth) {
|
||
|
+ size_t r = width - tb->termwidth;
|
||
|
+
|
||
|
+ cl->flags |= SCOLS_FL_TRUNC;
|
||
|
+ cl->width -= r;
|
||
|
+ width -= r;
|
||
|
+ } else {
|
||
|
+ cl->flags |= SCOLS_FL_HIDDEN;
|
||
|
+ width -= cl->width + colsepsz;
|
||
|
+ }
|
||
|
}
|
||
|
}
|
||
|
-
|
||
|
- DBG(TAB, ul_debugobj(tb, " result: %zu", width));
|
||
|
+done:
|
||
|
+ DBG(TAB, ul_debugobj(tb, " final width: %zu (rc=%d)", width, rc));
|
||
|
ON_DBG(TAB, dbg_columns(tb));
|
||
|
|
||
|
return rc;
|
||
|
@@ -742,64 +1418,281 @@ static size_t strlen_line(struct libscols_line *ln)
|
||
|
return sz;
|
||
|
}
|
||
|
|
||
|
+static void cleanup_printing(struct libscols_table *tb, struct libscols_buffer *buf)
|
||
|
+{
|
||
|
+ if (!tb)
|
||
|
+ return;
|
||
|
|
||
|
+ free_buffer(buf);
|
||
|
|
||
|
-/**
|
||
|
- * 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)
|
||
|
+ if (tb->priv_symbols) {
|
||
|
+ scols_table_set_symbols(tb, NULL);
|
||
|
+ tb->priv_symbols = 0;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static int initialize_printing(struct libscols_table *tb, struct libscols_buffer **buf)
|
||
|
{
|
||
|
- int rc = 0;
|
||
|
- size_t bufsz;
|
||
|
+ size_t bufsz, extra_bufsz = 0;
|
||
|
struct libscols_line *ln;
|
||
|
struct libscols_iter itr;
|
||
|
- struct libscols_buffer *buf;
|
||
|
+ int rc;
|
||
|
|
||
|
- assert(tb);
|
||
|
- if (!tb)
|
||
|
- return -1;
|
||
|
+ DBG(TAB, ul_debugobj(tb, "initialize printing"));
|
||
|
+ *buf = NULL;
|
||
|
|
||
|
- DBG(TAB, ul_debugobj(tb, "printing"));
|
||
|
- if (!tb->symbols)
|
||
|
- scols_table_set_symbols(tb, NULL); /* use default */
|
||
|
+ if (!tb->symbols) {
|
||
|
+ rc = scols_table_set_default_symbols(tb);
|
||
|
+ if (rc)
|
||
|
+ goto err;
|
||
|
+ tb->priv_symbols = 1;
|
||
|
+ } else
|
||
|
+ tb->priv_symbols = 0;
|
||
|
+
|
||
|
+ if (tb->format == SCOLS_FMT_HUMAN)
|
||
|
+ tb->is_term = tb->termforce == SCOLS_TERMFORCE_NEVER ? 0 :
|
||
|
+ tb->termforce == SCOLS_TERMFORCE_ALWAYS ? 1 :
|
||
|
+ isatty(STDOUT_FILENO);
|
||
|
+
|
||
|
+ if (tb->is_term) {
|
||
|
+ size_t width = (size_t) scols_table_get_termwidth(tb);
|
||
|
+
|
||
|
+ if (tb->termreduce > 0 && tb->termreduce < width) {
|
||
|
+ width -= tb->termreduce;
|
||
|
+ scols_table_set_termwidth(tb, width);
|
||
|
+ }
|
||
|
+ bufsz = width;
|
||
|
+ } else
|
||
|
+ bufsz = BUFSIZ;
|
||
|
|
||
|
- 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;
|
||
|
+ if (!tb->is_term || tb->format != SCOLS_FMT_HUMAN || scols_table_is_tree(tb))
|
||
|
+ tb->header_repeat = 0;
|
||
|
|
||
|
- bufsz = tb->termwidth;
|
||
|
+ /*
|
||
|
+ * Estimate extra space necessary for tree, JSON or another output
|
||
|
+ * decoration.
|
||
|
+ */
|
||
|
+ if (scols_table_is_tree(tb))
|
||
|
+ extra_bufsz += tb->nlines * strlen(vertical_symbol(tb));
|
||
|
+
|
||
|
+ switch (tb->format) {
|
||
|
+ case SCOLS_FMT_RAW:
|
||
|
+ extra_bufsz += tb->ncols; /* separator between columns */
|
||
|
+ break;
|
||
|
+ case SCOLS_FMT_JSON:
|
||
|
+ if (tb->format == SCOLS_FMT_JSON)
|
||
|
+ extra_bufsz += tb->nlines * 3; /* indention */
|
||
|
+ /* fallthrough */
|
||
|
+ case SCOLS_FMT_EXPORT:
|
||
|
+ {
|
||
|
+ struct libscols_column *cl;
|
||
|
+
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+
|
||
|
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
|
||
|
+ if (scols_column_is_hidden(cl))
|
||
|
+ continue;
|
||
|
+ extra_bufsz += strlen(scols_cell_get_data(&cl->header)); /* data */
|
||
|
+ extra_bufsz += 2; /* separators */
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case SCOLS_FMT_HUMAN:
|
||
|
+ break;
|
||
|
+ }
|
||
|
|
||
|
+ /*
|
||
|
+ * Enlarge buffer if necessary, the buffer should be large enough to
|
||
|
+ * store line data and tree ascii art (or another decoration).
|
||
|
+ */
|
||
|
scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
while (scols_table_next_line(tb, &itr, &ln) == 0) {
|
||
|
- size_t sz = strlen_line(ln);
|
||
|
+ size_t sz;
|
||
|
+
|
||
|
+ sz = strlen_line(ln) + extra_bufsz;
|
||
|
if (sz > bufsz)
|
||
|
bufsz = sz;
|
||
|
}
|
||
|
|
||
|
- buf = new_buffer(bufsz + 1); /* data + space for \0 */
|
||
|
- if (!buf)
|
||
|
- return -ENOMEM;
|
||
|
+ *buf = new_buffer(bufsz + 1); /* data + space for \0 */
|
||
|
+ if (!*buf) {
|
||
|
+ rc = -ENOMEM;
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
|
||
|
- if (!(scols_table_is_raw(tb) || scols_table_is_export(tb))) {
|
||
|
- rc = recount_widths(tb, buf);
|
||
|
+ if (tb->format == SCOLS_FMT_HUMAN) {
|
||
|
+ rc = recount_widths(tb, *buf);
|
||
|
if (rc != 0)
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+err:
|
||
|
+ cleanup_printing(tb, *buf);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scola_table_print_range:
|
||
|
+ * @tb: table
|
||
|
+ * @start: first printed line or NULL to print from the begin of the table
|
||
|
+ * @end: last printed line or NULL to print all from start.
|
||
|
+ *
|
||
|
+ * If the start is the first line in the table than prints table header too.
|
||
|
+ * The header is printed only once. This does not work for trees.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ */
|
||
|
+int scols_table_print_range( struct libscols_table *tb,
|
||
|
+ struct libscols_line *start,
|
||
|
+ struct libscols_line *end)
|
||
|
+{
|
||
|
+ struct libscols_buffer *buf = NULL;
|
||
|
+ struct libscols_iter itr;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ if (scols_table_is_tree(tb))
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, "printing range from API"));
|
||
|
+
|
||
|
+ rc = initialize_printing(tb, &buf);
|
||
|
+ if (rc)
|
||
|
+ return rc;
|
||
|
+
|
||
|
+ if (start) {
|
||
|
+ itr.direction = SCOLS_ITER_FORWARD;
|
||
|
+ itr.head = &tb->tb_lines;
|
||
|
+ itr.p = &start->ln_lines;
|
||
|
+ } else
|
||
|
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
|
||
|
+
|
||
|
+ if (!start || itr.p == tb->tb_lines.next) {
|
||
|
+ rc = print_header(tb, buf);
|
||
|
+ if (rc)
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
+ rc = print_range(tb, buf, &itr, end);
|
||
|
+done:
|
||
|
+ cleanup_printing(tb, buf);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_table_print_range_to_string:
|
||
|
+ * @tb: table
|
||
|
+ * @start: first printed line or NULL to print from the beginning of the table
|
||
|
+ * @end: last printed line or NULL to print all from start.
|
||
|
+ * @data: pointer to the beginning of a memory area to print to
|
||
|
+ *
|
||
|
+ * The same as scols_table_print_range(), but prints to @data instead of
|
||
|
+ * stream.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ */
|
||
|
+#ifdef HAVE_OPEN_MEMSTREAM
|
||
|
+int scols_table_print_range_to_string( struct libscols_table *tb,
|
||
|
+ struct libscols_line *start,
|
||
|
+ struct libscols_line *end,
|
||
|
+ char **data)
|
||
|
+{
|
||
|
+ FILE *stream, *old_stream;
|
||
|
+ size_t sz;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, "printing range to string"));
|
||
|
+
|
||
|
+ /* create a stream for output */
|
||
|
+ stream = open_memstream(data, &sz);
|
||
|
+ if (!stream)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ old_stream = scols_table_get_stream(tb);
|
||
|
+ scols_table_set_stream(tb, stream);
|
||
|
+ rc = scols_table_print_range(tb, start, end);
|
||
|
+ fclose(stream);
|
||
|
+ scols_table_set_stream(tb, old_stream);
|
||
|
+
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+#else
|
||
|
+int scols_table_print_range_to_string(
|
||
|
+ struct libscols_table *tb __attribute__((__unused__)),
|
||
|
+ struct libscols_line *start __attribute__((__unused__)),
|
||
|
+ struct libscols_line *end __attribute__((__unused__)),
|
||
|
+ char **data __attribute__((__unused__)))
|
||
|
+{
|
||
|
+ return -ENOSYS;
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
+static int __scols_print_table(struct libscols_table *tb, int *is_empty)
|
||
|
+{
|
||
|
+ int rc = 0;
|
||
|
+ struct libscols_buffer *buf = NULL;
|
||
|
+
|
||
|
+ if (!tb)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ DBG(TAB, ul_debugobj(tb, "printing"));
|
||
|
+ if (is_empty)
|
||
|
+ *is_empty = 0;
|
||
|
+
|
||
|
+ if (list_empty(&tb->tb_columns)) {
|
||
|
+ DBG(TAB, ul_debugobj(tb, "error -- no columns"));
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+ if (list_empty(&tb->tb_lines)) {
|
||
|
+ DBG(TAB, ul_debugobj(tb, "ignore -- no lines"));
|
||
|
+ if (is_empty)
|
||
|
+ *is_empty = 1;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ tb->header_printed = 0;
|
||
|
+ rc = initialize_printing(tb, &buf);
|
||
|
+ if (rc)
|
||
|
+ return rc;
|
||
|
+
|
||
|
+ fput_table_open(tb);
|
||
|
+
|
||
|
+ if (tb->format == SCOLS_FMT_HUMAN)
|
||
|
+ print_title(tb);
|
||
|
+
|
||
|
+ rc = print_header(tb, buf);
|
||
|
+ if (rc)
|
||
|
+ goto done;
|
||
|
+
|
||
|
if (scols_table_is_tree(tb))
|
||
|
rc = print_tree(tb, buf);
|
||
|
else
|
||
|
rc = print_table(tb, buf);
|
||
|
|
||
|
+ fput_table_close(tb);
|
||
|
done:
|
||
|
- free_buffer(buf);
|
||
|
+ cleanup_printing(tb, buf);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * scols_print_table:
|
||
|
+ * @tb: table
|
||
|
+ *
|
||
|
+ * Prints the table to the output stream and terminate by \n.
|
||
|
+ *
|
||
|
+ * Returns: 0, a negative value in case of an error.
|
||
|
+ */
|
||
|
+int scols_print_table(struct libscols_table *tb)
|
||
|
+{
|
||
|
+ int empty = 0;
|
||
|
+ int rc = __scols_print_table(tb, &empty);
|
||
|
+
|
||
|
+ if (rc == 0 && !empty)
|
||
|
+ fputc('\n', tb->out);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
@@ -812,10 +1705,10 @@ done:
|
||
|
*
|
||
|
* Returns: 0, a negative value in case of an error.
|
||
|
*/
|
||
|
+#ifdef HAVE_OPEN_MEMSTREAM
|
||
|
int scols_print_table_to_string(struct libscols_table *tb, char **data)
|
||
|
{
|
||
|
-#ifdef HAVE_OPEN_MEMSTREAM
|
||
|
- FILE *stream;
|
||
|
+ FILE *stream, *old_stream;
|
||
|
size_t sz;
|
||
|
int rc;
|
||
|
|
||
|
@@ -829,13 +1722,20 @@ int scols_print_table_to_string(struct libscols_table *tb, char **data)
|
||
|
if (!stream)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
+ old_stream = scols_table_get_stream(tb);
|
||
|
scols_table_set_stream(tb, stream);
|
||
|
- rc = scols_print_table(tb);
|
||
|
+ rc = __scols_print_table(tb, NULL);
|
||
|
fclose(stream);
|
||
|
+ scols_table_set_stream(tb, old_stream);
|
||
|
|
||
|
return rc;
|
||
|
+}
|
||
|
#else
|
||
|
+int scols_print_table_to_string(
|
||
|
+ struct libscols_table *tb __attribute__((__unused__)),
|
||
|
+ char **data __attribute__((__unused__)))
|
||
|
+{
|
||
|
return -ENOSYS;
|
||
|
-#endif
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
--
|
||
|
2.14.4
|
||
|
|