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