(root)/
util-linux-2.39/
libsmartcols/
src/
table.c
       1  /*
       2   * table.c - functions handling the data at the table level
       3   *
       4   * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
       5   * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
       6   * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
       7   *
       8   * This file may be redistributed under the terms of the
       9   * GNU Lesser General Public License.
      10   */
      11  
      12  /**
      13   * SECTION: table
      14   * @title: Table
      15   * @short_description: container for rows and columns
      16   *
      17   * Table data manipulation API.
      18   */
      19  
      20  
      21  #include <stdlib.h>
      22  #include <unistd.h>
      23  #include <string.h>
      24  #include <termios.h>
      25  #include <ctype.h>
      26  
      27  #include "nls.h"
      28  #include "ttyutils.h"
      29  #include "smartcolsP.h"
      30  
      31  #ifdef HAVE_WIDECHAR
      32  #define UTF_V	"\342\224\202"	/* U+2502, Vertical line drawing char  |   */
      33  #define UTF_VR	"\342\224\234"	/* U+251C, Vertical and right          |-  */
      34  #define UTF_H	"\342\224\200"	/* U+2500, Horizontal                  -   */
      35  #define UTF_UR	"\342\224\224"	/* U+2514, Up and right                '-  */
      36  
      37  #define UTF_V3  "\342\224\206"  /* U+2506 Triple Dash Vertical          |  */
      38  #define UTF_H3  "\342\224\210"  /* U+2504 Triple Dash Horizontal        -  */
      39  #define UTF_DR  "\342\224\214"  /* U+250C Down and Right                ,- */
      40  #define UTF_DH  "\342\224\254"  /* U+252C Down and Horizontal           |' */
      41  
      42  #define UTF_TR  "\342\226\266"  /* U+25B6 Black Right-Pointing Triangle  >  */
      43  #endif /* !HAVE_WIDECHAR */
      44  
      45  #define is_last_column(_tb, _cl) \
      46  		list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
      47  
      48  
      49  static void check_padding_debug(struct libscols_table *tb)
      50  {
      51  	const char *str;
      52  
      53  	assert(libsmartcols_debug_mask);	/* debug has to be already initialized! */
      54  
      55  	str = getenv("LIBSMARTCOLS_DEBUG_PADDING");
      56  	if (!str || (strcmp(str, "on") != 0 && strcmp(str, "1") != 0))
      57  		return;
      58  
      59  	DBG(INIT, ul_debugobj(tb, "padding debug: ENABLE"));
      60  	tb->padding_debug = 1;
      61  }
      62  
      63  /**
      64   * scols_new_table:
      65   *
      66   * Returns: A newly allocated table.
      67   */
      68  struct libscols_table *scols_new_table(void)
      69  {
      70  	struct libscols_table *tb;
      71  	int c, l;
      72  
      73  	tb = calloc(1, sizeof(struct libscols_table));
      74  	if (!tb)
      75  		return NULL;
      76  
      77  	tb->refcount = 1;
      78  	tb->out = stdout;
      79  
      80  	get_terminal_dimension(&c, &l);
      81  	tb->termwidth  = c > 0 ? c : 80;
      82  	tb->termheight = l > 0 ? l : 24;
      83  
      84  	INIT_LIST_HEAD(&tb->tb_lines);
      85  	INIT_LIST_HEAD(&tb->tb_columns);
      86  	INIT_LIST_HEAD(&tb->tb_groups);
      87  
      88  	DBG(TAB, ul_debugobj(tb, "alloc"));
      89  	ON_DBG(INIT, check_padding_debug(tb));
      90  
      91  	return tb;
      92  }
      93  
      94  /**
      95   * scols_ref_table:
      96   * @tb: a pointer to a struct libscols_table instance
      97   *
      98   * Increases the refcount of @tb.
      99   */
     100  void scols_ref_table(struct libscols_table *tb)
     101  {
     102  	if (tb)
     103  		tb->refcount++;
     104  }
     105  
     106  static void scols_table_remove_groups(struct libscols_table *tb)
     107  {
     108  	while (!list_empty(&tb->tb_groups)) {
     109  		struct libscols_group *gr = list_entry(tb->tb_groups.next,
     110  							struct libscols_group, gr_groups);
     111  		scols_group_remove_children(gr);
     112  		scols_group_remove_members(gr);
     113  		scols_unref_group(gr);
     114  	}
     115  }
     116  
     117  /**
     118   * scols_unref_table:
     119   * @tb: a pointer to a struct libscols_table instance
     120   *
     121   * Decreases the refcount of @tb. When the count falls to zero, the instance
     122   * is automatically deallocated.
     123   */
     124  void scols_unref_table(struct libscols_table *tb)
     125  {
     126  	if (tb && (--tb->refcount <= 0)) {
     127  		DBG(TAB, ul_debugobj(tb, "dealloc <-"));
     128  		scols_table_remove_groups(tb);
     129  		scols_table_remove_lines(tb);
     130  		scols_table_remove_columns(tb);
     131  		scols_unref_symbols(tb->symbols);
     132  		scols_reset_cell(&tb->title);
     133  		free(tb->grpset);
     134  		free(tb->linesep);
     135  		free(tb->colsep);
     136  		free(tb->name);
     137  		free(tb);
     138  		DBG(TAB, ul_debug("<- done"));
     139  	}
     140  }
     141  
     142  /* Private API */
     143  int scols_table_next_group(struct libscols_table *tb,
     144  			  struct libscols_iter *itr,
     145  			  struct libscols_group **gr)
     146  {
     147  	int rc = 1;
     148  
     149  	if (!tb || !itr || !gr)
     150  		return -EINVAL;
     151  	*gr = NULL;
     152  
     153  	if (!itr->head)
     154  		SCOLS_ITER_INIT(itr, &tb->tb_groups);
     155  	if (itr->p != itr->head) {
     156  		SCOLS_ITER_ITERATE(itr, *gr, struct libscols_group, gr_groups);
     157  		rc = 0;
     158  	}
     159  
     160  	return rc;
     161  }
     162  
     163  /**
     164   * scols_table_set_name:
     165   * @tb: a pointer to a struct libscols_table instance
     166   * @name: a name
     167   *
     168   * The table name is used for example for JSON top level object name.
     169   *
     170   * Returns: 0, a negative number in case of an error.
     171   *
     172   * Since: 2.27
     173   */
     174  int scols_table_set_name(struct libscols_table *tb, const char *name)
     175  {
     176  	return strdup_to_struct_member(tb, name, name);
     177  }
     178  
     179  /**
     180   * scols_table_get_name:
     181   * @tb: a pointer to a struct libscols_table instance
     182   *
     183   * Returns: The current name setting of the table @tb
     184   *
     185   * Since: 2.29
     186   */
     187  const char *scols_table_get_name(const struct libscols_table *tb)
     188  {
     189  	return tb->name;
     190  }
     191  
     192  /**
     193   * scols_table_get_title:
     194   * @tb: a pointer to a struct libscols_table instance
     195   *
     196   * The returned pointer is possible to modify by cell functions. Note that
     197   * title output alignment on non-tty is hardcoded to 80 output chars. For the
     198   * regular terminal it's based on terminal width.
     199   *
     200   * Returns: Title of the table, or NULL in case of blank title.
     201   *
     202   * Since: 2.28
     203   */
     204  struct libscols_cell *scols_table_get_title(struct libscols_table *tb)
     205  {
     206  	return &tb->title;
     207  }
     208  
     209  /**
     210   * scols_table_add_column:
     211   * @tb: a pointer to a struct libscols_table instance
     212   * @cl: a pointer to a struct libscols_column instance
     213   *
     214   * Adds @cl to @tb's column list. The column cannot be shared between more
     215   * tables.
     216   *
     217   * Returns: 0, a negative number in case of an error.
     218   */
     219  int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl)
     220  {
     221  	struct libscols_iter itr;
     222  	struct libscols_line *ln;
     223  	int rc = 0;
     224  
     225  	if (!tb || !cl || cl->table)
     226  		return -EINVAL;
     227  
     228  	if (!list_empty(&cl->cl_columns))
     229  		return -EINVAL;
     230  
     231  	if (cl->flags & SCOLS_FL_TREE)
     232  		tb->ntreecols++;
     233  
     234  	DBG(TAB, ul_debugobj(tb, "add column"));
     235  	list_add_tail(&cl->cl_columns, &tb->tb_columns);
     236  	cl->seqnum = tb->ncols++;
     237  	cl->table = tb;
     238  	scols_ref_column(cl);
     239  
     240  	if (list_empty(&tb->tb_lines))
     241  		return 0;
     242  
     243  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
     244  
     245  	/* Realloc line cell arrays
     246  	 */
     247  	while (scols_table_next_line(tb, &itr, &ln) == 0) {
     248  		rc = scols_line_alloc_cells(ln, tb->ncols);
     249  		if (rc)
     250  			break;
     251  	}
     252  
     253  	return rc;
     254  }
     255  
     256  /**
     257   * scols_table_remove_column:
     258   * @tb: a pointer to a struct libscols_table instance
     259   * @cl: a pointer to a struct libscols_column instance
     260   *
     261   * Removes @cl from @tb.
     262   *
     263   * Returns: 0, a negative number in case of an error.
     264   */
     265  int scols_table_remove_column(struct libscols_table *tb,
     266  			      struct libscols_column *cl)
     267  {
     268  	if (!tb || !cl || !list_empty(&tb->tb_lines))
     269  		return -EINVAL;
     270  
     271  	if (cl->flags & SCOLS_FL_TREE)
     272  		tb->ntreecols--;
     273  	if (tb->dflt_sort_column == cl)
     274  		tb->dflt_sort_column = NULL;
     275  
     276  	DBG(TAB, ul_debugobj(tb, "remove column"));
     277  	list_del_init(&cl->cl_columns);
     278  	tb->ncols--;
     279  	cl->table = NULL;
     280  	scols_unref_column(cl);
     281  	return 0;
     282  }
     283  
     284  /**
     285   * scols_table_remove_columns:
     286   * @tb: a pointer to a struct libscols_table instance
     287   *
     288   * Removes all of @tb's columns.
     289   *
     290   * Returns: 0, a negative number in case of an error.
     291   */
     292  int scols_table_remove_columns(struct libscols_table *tb)
     293  {
     294  	if (!tb || !list_empty(&tb->tb_lines))
     295  		return -EINVAL;
     296  
     297  	DBG(TAB, ul_debugobj(tb, "remove all columns"));
     298  	while (!list_empty(&tb->tb_columns)) {
     299  		struct libscols_column *cl = list_entry(tb->tb_columns.next,
     300  					struct libscols_column, cl_columns);
     301  		scols_table_remove_column(tb, cl);
     302  	}
     303  	return 0;
     304  }
     305  
     306  /**
     307   * scols_table_move_column:
     308   * @tb: table
     309   * @pre: column before the column
     310   * @cl: column to move
     311   *
     312   * Move the @cl behind @pre. If the @pre is NULL then the @col is the first
     313   * column in the table.
     314   *
     315   * Since: 2.30
     316   *
     317   * Returns: 0, a negative number in case of an error.
     318   */
     319  int scols_table_move_column(struct libscols_table *tb,
     320  			    struct libscols_column *pre,
     321  			    struct libscols_column *cl)
     322  {
     323  	struct list_head *head;
     324  	struct libscols_iter itr;
     325  	struct libscols_column *p;
     326  	struct libscols_line *ln;
     327  	size_t n = 0, oldseq;
     328  
     329  	if (!tb || !cl)
     330  		return -EINVAL;
     331  
     332  	if (pre && pre->seqnum + 1 == cl->seqnum)
     333  		return 0;
     334  	if (pre == NULL && cl->seqnum == 0)
     335  		return 0;
     336  
     337  	DBG(TAB, ul_debugobj(tb, "move column %zu behind %zu",
     338  				cl->seqnum, pre? pre->seqnum : 0));
     339  
     340  	list_del_init(&cl->cl_columns);		/* remove from old position */
     341  
     342  	head = pre ? &pre->cl_columns : &tb->tb_columns;
     343  	list_add(&cl->cl_columns, head);	/* add to the new place */
     344  
     345  	oldseq = cl->seqnum;
     346  
     347  	/* fix seq. numbers */
     348  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
     349  	while (scols_table_next_column(tb, &itr, &p) == 0)
     350  		p->seqnum = n++;
     351  
     352  	/* move data in lines */
     353  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
     354  	while (scols_table_next_line(tb, &itr, &ln) == 0)
     355  		scols_line_move_cells(ln, cl->seqnum, oldseq);
     356  	return 0;
     357  }
     358  
     359  /**
     360   * scols_table_new_column:
     361   * @tb: table
     362   * @name: column header
     363   * @whint: column width hint (absolute width: N > 1; relative width: 0 < N < 1)
     364   * @flags: flags integer
     365   *
     366   * This is shortcut for
     367   *
     368   *   cl = scols_new_column();
     369   *   scols_column_set_....(cl, ...);
     370   *   scols_table_add_column(tb, cl);
     371   *
     372   * The column width is possible to define by:
     373   *
     374   *  @whint: 0 < N < 1  : relative width, percent of terminal width
     375   *
     376   *  @whint: N >= 1     : absolute width, empty column will be truncated to
     377   *                     the column header width if no specified STRICTWIDTH flag
     378   *
     379   * Note that if table has disabled "maxout" flag (disabled by default) than
     380   * relative width is used as a hint only. It's possible that column will be
     381   * narrow if the specified size is too large for column data.
     382   *
     383   *
     384   * If the width of all columns is greater than terminal width then library
     385   * tries to reduce width of the individual columns. It's done in three stages:
     386   *
     387   * #1 reduce columns with SCOLS_FL_TRUNC flag and with relative width if the
     388   *    width is greater than width defined by @whint (@whint * terminal_width)
     389   *
     390   * #2 reduce all columns with SCOLS_FL_TRUNC flag
     391   *
     392   * #3 reduce all columns with relative width
     393   *
     394   * The next stage is always used if the previous stage is unsuccessful. Note
     395   * that SCOLS_FL_WRAP is interpreted as SCOLS_FL_TRUNC when calculate column
     396   * width (if custom wrap function is not specified), but the final text is not
     397   * truncated, but wrapped to multi-line cell.
     398   *
     399   *
     400   * The column is necessary to address by sequential number. The first defined
     401   * column has the colnum = 0. For example:
     402   *
     403   *	scols_table_new_column(tab, "FOO", 0.5, 0);		// colnum = 0
     404   *	scols_table_new_column(tab, "BAR", 0.5, 0);		// colnum = 1
     405   *      .
     406   *      .
     407   *	scols_line_get_cell(line, 0);				// FOO column
     408   *	scols_line_get_cell(line, 1);				// BAR column
     409   *
     410   * Returns: newly allocated column
     411   */
     412  struct libscols_column *scols_table_new_column(struct libscols_table *tb,
     413  					       const char *name,
     414  					       double whint,
     415  					       int flags)
     416  {
     417  	struct libscols_column *cl;
     418  
     419  	if (!tb)
     420  		return NULL;
     421  
     422  	DBG(TAB, ul_debugobj(tb, "new column name=%s, whint=%g, flags=0x%04x",
     423  				name, whint, flags));
     424  	cl = scols_new_column();
     425  	if (!cl)
     426  		return NULL;
     427  
     428  	if (name && scols_column_set_name(cl, name))
     429  		goto err;
     430  	scols_column_set_whint(cl, whint);
     431  	scols_column_set_flags(cl, flags);
     432  
     433  	if (scols_table_add_column(tb, cl))	/* this increments column ref-counter */
     434  		goto err;
     435  
     436  	scols_unref_column(cl);
     437  	return cl;
     438  err:
     439  	scols_unref_column(cl);
     440  	return NULL;
     441  }
     442  
     443  /**
     444   * scols_table_next_column:
     445   * @tb: a pointer to a struct libscols_table instance
     446   * @itr: a pointer to a struct libscols_iter instance
     447   * @cl: a pointer to a pointer to a struct libscols_column instance
     448   *
     449   * Returns the next column of @tb via @cl.
     450   *
     451   * Returns: 0, a negative value in case of an error.
     452   */
     453  int scols_table_next_column(struct libscols_table *tb,
     454  			    struct libscols_iter *itr,
     455  			    struct libscols_column **cl)
     456  {
     457  	int rc = 1;
     458  
     459  	if (!tb || !itr || !cl)
     460  		return -EINVAL;
     461  	*cl = NULL;
     462  
     463  	if (!itr->head)
     464  		SCOLS_ITER_INIT(itr, &tb->tb_columns);
     465  	if (itr->p != itr->head) {
     466  		SCOLS_ITER_ITERATE(itr, *cl, struct libscols_column, cl_columns);
     467  		rc = 0;
     468  	}
     469  
     470  	return rc;
     471  }
     472  
     473  /**
     474   * scols_table_set_columns_iter:
     475   * @tb: tab pointer
     476   * @itr: iterator
     477   * @cl: tab entry
     478   *
     479   * Sets @iter to the position of @cl in the file @tb.
     480   *
     481   * Returns: 0 on success, negative number in case of error.
     482   *
     483   * Since: 2.35
     484   */
     485  int scols_table_set_columns_iter(
     486  			struct libscols_table *tb,
     487  			struct libscols_iter *itr,
     488  			struct libscols_column *cl)
     489  {
     490  	if (!tb || !itr || !cl)
     491  		return -EINVAL;
     492  
     493  	if (cl->table != tb)
     494  		return -EINVAL;
     495  
     496  	SCOLS_ITER_INIT(itr, &tb->tb_columns);
     497  	itr->p = &cl->cl_columns;
     498  
     499  	return 0;
     500  }
     501  
     502  /**
     503   * scols_table_get_ncols:
     504   * @tb: table
     505   *
     506   * Returns: the ncols table member.
     507   */
     508  size_t scols_table_get_ncols(const struct libscols_table *tb)
     509  {
     510  	return tb->ncols;
     511  }
     512  
     513  /**
     514   * scols_table_get_nlines:
     515   * @tb: table
     516   *
     517   * Returns: the nlines table member.
     518   */
     519  size_t scols_table_get_nlines(const struct libscols_table *tb)
     520  {
     521  	return tb->nlines;
     522  }
     523  
     524  /**
     525   * scols_table_set_stream:
     526   * @tb: table
     527   * @stream: output stream
     528   *
     529   * Sets the output stream for table @tb.
     530   *
     531   * Returns: 0, a negative number in case of an error.
     532   */
     533  int scols_table_set_stream(struct libscols_table *tb, FILE *stream)
     534  {
     535  	assert(tb);
     536  	if (!tb)
     537  		return -EINVAL;
     538  
     539  	DBG(TAB, ul_debugobj(tb, "setting alternative stream"));
     540  	tb->out = stream;
     541  	return 0;
     542  }
     543  
     544  /**
     545   * scols_table_get_stream:
     546   * @tb: table
     547   *
     548   * Gets the output stream for table @tb.
     549   *
     550   * Returns: stream pointer, NULL in case of an error or an unset stream.
     551   */
     552  FILE *scols_table_get_stream(const struct libscols_table *tb)
     553  {
     554  	return tb->out;
     555  }
     556  
     557  /**
     558   * scols_table_reduce_termwidth:
     559   * @tb: table
     560   * @reduce: width
     561   *
     562   * If necessary then libsmartcols use all terminal width, the @reduce setting
     563   * provides extra space (for example for borders in ncurses applications).
     564   *
     565   * The @reduce must be smaller than terminal width, otherwise it's silently
     566   * ignored. The reduction is not applied when STDOUT_FILENO is not terminal.
     567   *
     568   * Note that after output initialization (scols_table_print_* calls) the width
     569   * will be reduced, this behavior affects subsequenced scols_table_get_termwidth()
     570   * calls.
     571   *
     572   * Returns: 0, a negative value in case of an error.
     573   */
     574  int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce)
     575  {
     576  	if (!tb)
     577  		return -EINVAL;
     578  
     579  	DBG(TAB, ul_debugobj(tb, "reduce terminal width: %zu", reduce));
     580  	tb->termreduce = reduce;
     581  	return 0;
     582  }
     583  
     584  /**
     585   * scols_table_get_column:
     586   * @tb: table
     587   * @n: number of column (0..N)
     588   *
     589   * Returns: pointer to column or NULL
     590   */
     591  struct libscols_column *scols_table_get_column(struct libscols_table *tb,
     592  					       size_t n)
     593  {
     594  	struct libscols_iter itr;
     595  	struct libscols_column *cl;
     596  
     597  	if (!tb)
     598  		return NULL;
     599  	if (n >= tb->ncols)
     600  		return NULL;
     601  
     602  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
     603  	while (scols_table_next_column(tb, &itr, &cl) == 0) {
     604  		if (cl->seqnum == n)
     605  			return cl;
     606  	}
     607  	return NULL;
     608  }
     609  
     610  /**
     611   * scols_table_get_column_ny_name
     612   * @tb: table
     613   * @name: column name
     614   *
     615   * Returns: pointer to column or NULL
     616   *
     617   * Since: 2.39
     618   */
     619  struct libscols_column *scols_table_get_column_by_name(
     620  				struct libscols_table *tb, const char *name)
     621  {
     622  	struct libscols_iter itr;
     623  	struct libscols_column *cl;
     624  
     625  	if (!tb || !name)
     626  		return NULL;
     627  
     628  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
     629  	while (scols_table_next_column(tb, &itr, &cl) == 0) {
     630  		const char *cn = scols_column_get_name(cl);
     631  
     632  		if (cn && strcmp(cn, name) == 0)
     633  			return cl;
     634  	}
     635  	return NULL;
     636  }
     637  
     638  
     639  /**
     640   * scols_table_add_line:
     641   * @tb: table
     642   * @ln: line
     643   *
     644   * Note that this function calls scols_line_alloc_cells() if number
     645   * of the cells in the line is too small for @tb.
     646   *
     647   * Returns: 0, a negative value in case of an error.
     648   */
     649  int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
     650  {
     651  	if (!tb || !ln)
     652  		return -EINVAL;
     653  
     654  	if (!list_empty(&ln->ln_lines))
     655  		return -EINVAL;
     656  
     657  	if (tb->ncols > ln->ncells) {
     658  		int rc = scols_line_alloc_cells(ln, tb->ncols);
     659  		if (rc)
     660  			return rc;
     661  	}
     662  
     663  	DBG(TAB, ul_debugobj(tb, "add line"));
     664  	list_add_tail(&ln->ln_lines, &tb->tb_lines);
     665  	ln->seqnum = tb->nlines++;
     666  	scols_ref_line(ln);
     667  	return 0;
     668  }
     669  
     670  /**
     671   * scols_table_remove_line:
     672   * @tb: table
     673   * @ln: line
     674   *
     675   * Note that this function does not destroy the parent<->child relationship between lines.
     676   * You have to call scols_line_remove_child()
     677   *
     678   * Returns: 0, a negative value in case of an error.
     679   */
     680  int scols_table_remove_line(struct libscols_table *tb,
     681  			    struct libscols_line *ln)
     682  {
     683  	if (!tb || !ln)
     684  		return -EINVAL;
     685  
     686  	DBG(TAB, ul_debugobj(tb, "remove line"));
     687  	list_del_init(&ln->ln_lines);
     688  	tb->nlines--;
     689  	scols_unref_line(ln);
     690  	return 0;
     691  }
     692  
     693  /**
     694   * scols_table_remove_lines:
     695   * @tb: table
     696   *
     697   * This empties the table and also destroys all the parent<->child relationships.
     698   */
     699  void scols_table_remove_lines(struct libscols_table *tb)
     700  {
     701  	if (!tb)
     702  		return;
     703  
     704  	DBG(TAB, ul_debugobj(tb, "remove all lines"));
     705  	while (!list_empty(&tb->tb_lines)) {
     706  		struct libscols_line *ln = list_entry(tb->tb_lines.next,
     707  						struct libscols_line, ln_lines);
     708  		if (ln->parent)
     709  			scols_line_remove_child(ln->parent, ln);
     710  		scols_table_remove_line(tb, ln);
     711  	}
     712  }
     713  
     714  /**
     715   * scols_table_next_line:
     716   * @tb: a pointer to a struct libscols_table instance
     717   * @itr: a pointer to a struct libscols_iter instance
     718   * @ln: a pointer to a pointer to a struct libscols_line instance
     719   *
     720   * Finds the next line and returns a pointer to it via @ln.
     721   *
     722   * Returns: 0, a negative value in case of an error.
     723   */
     724  int scols_table_next_line(struct libscols_table *tb,
     725  			  struct libscols_iter *itr,
     726  			  struct libscols_line **ln)
     727  {
     728  	int rc = 1;
     729  
     730  	if (!tb || !itr || !ln)
     731  		return -EINVAL;
     732  	*ln = NULL;
     733  
     734  	if (!itr->head)
     735  		SCOLS_ITER_INIT(itr, &tb->tb_lines);
     736  	if (itr->p != itr->head) {
     737  		SCOLS_ITER_ITERATE(itr, *ln, struct libscols_line, ln_lines);
     738  		rc = 0;
     739  	}
     740  
     741  	return rc;
     742  }
     743  
     744  /**
     745   * scols_table_new_line:
     746   * @tb: table
     747   * @parent: parental line or NULL
     748   *
     749   * This is shortcut for
     750   *
     751   *   ln = scols_new_line();
     752   *   scols_table_add_line(tb, ln);
     753   *   scols_line_add_child(parent, ln);
     754   *
     755   *
     756   * Returns: newly allocate line
     757   */
     758  struct libscols_line *scols_table_new_line(struct libscols_table *tb,
     759  					   struct libscols_line *parent)
     760  {
     761  	struct libscols_line *ln;
     762  
     763  	if (!tb)
     764  		return NULL;
     765  
     766  	ln = scols_new_line();
     767  	if (!ln)
     768  		return NULL;
     769  
     770  	if (scols_table_add_line(tb, ln))
     771  		goto err;
     772  	if (parent)
     773  		scols_line_add_child(parent, ln);
     774  
     775  	scols_unref_line(ln);	/* ref-counter incremented by scols_table_add_line() */
     776  	return ln;
     777  err:
     778  	scols_unref_line(ln);
     779  	return NULL;
     780  }
     781  
     782  /**
     783   * scols_table_get_line:
     784   * @tb: table
     785   * @n: column number (0..N)
     786   *
     787   * Returns: a line or NULL
     788   */
     789  struct libscols_line *scols_table_get_line(struct libscols_table *tb,
     790  					   size_t n)
     791  {
     792  	struct libscols_iter itr;
     793  	struct libscols_line *ln;
     794  
     795  	if (!tb)
     796  		return NULL;
     797  	if (n >= tb->nlines)
     798  		return NULL;
     799  
     800  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
     801  	while (scols_table_next_line(tb, &itr, &ln) == 0) {
     802  		if (ln->seqnum == n)
     803  			return ln;
     804  	}
     805  	return NULL;
     806  }
     807  
     808  /**
     809   * scols_copy_table:
     810   * @tb: table
     811   *
     812   * Creates a new independent table copy, except struct libscols_symbols that
     813   * are shared between the tables.
     814   *
     815   * Returns: a newly allocated copy of @tb
     816   */
     817  struct libscols_table *scols_copy_table(struct libscols_table *tb)
     818  {
     819  	struct libscols_table *ret;
     820  	struct libscols_line *ln;
     821  	struct libscols_column *cl;
     822  	struct libscols_iter itr;
     823  
     824  	if (!tb)
     825  		return NULL;
     826  	ret = scols_new_table();
     827  	if (!ret)
     828  		return NULL;
     829  
     830  	DBG(TAB, ul_debugobj(tb, "copy"));
     831  
     832  	if (tb->symbols)
     833  		scols_table_set_symbols(ret, tb->symbols);
     834  
     835  	/* columns */
     836  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
     837  	while (scols_table_next_column(tb, &itr, &cl) == 0) {
     838  		cl = scols_copy_column(cl);
     839  		if (!cl)
     840  			goto err;
     841  		if (scols_table_add_column(ret, cl))
     842  			goto err;
     843  		scols_unref_column(cl);
     844  	}
     845  
     846  	/* lines */
     847  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
     848  	while (scols_table_next_line(tb, &itr, &ln) == 0) {
     849  		struct libscols_line *newln = scols_copy_line(ln);
     850  		if (!newln)
     851  			goto err;
     852  		if (scols_table_add_line(ret, newln))
     853  			goto err;
     854  		if (ln->parent) {
     855  			struct libscols_line *p =
     856  				scols_table_get_line(ret, ln->parent->seqnum);
     857  			if (p)
     858  				scols_line_add_child(p, newln);
     859  		}
     860  		scols_unref_line(newln);
     861  	}
     862  
     863  	/* separators */
     864  	if (scols_table_set_column_separator(ret, tb->colsep) ||
     865  	    scols_table_set_line_separator(ret, tb->linesep))
     866  		goto err;
     867  
     868  	return ret;
     869  err:
     870  	scols_unref_table(ret);
     871  	return NULL;
     872  }
     873  
     874  /**
     875   * scols_table_set_default_symbols:
     876   * @tb: table
     877   *
     878   * The library check the current environment to select ASCII or UTF8 symbols.
     879   * This default behavior could be controlled by scols_table_enable_ascii().
     880   *
     881   * Use scols_table_set_symbols() to unset symbols or use your own setting.
     882   *
     883   * Returns: 0, a negative value in case of an error.
     884   *
     885   * Since: 2.29
     886   */
     887  int scols_table_set_default_symbols(struct libscols_table *tb)
     888  {
     889  	struct libscols_symbols *sy;
     890  	int rc;
     891  
     892  	if (!tb)
     893  		return -EINVAL;
     894  
     895  	DBG(TAB, ul_debugobj(tb, "setting default symbols"));
     896  
     897  	sy = scols_new_symbols();
     898  	if (!sy)
     899  		return -ENOMEM;
     900  
     901  #if defined(HAVE_WIDECHAR)
     902  	if (!scols_table_is_ascii(tb) &&
     903  	    !strcmp(nl_langinfo(CODESET), "UTF-8")) {
     904  		/* tree chart */
     905  		scols_symbols_set_branch(sy, UTF_VR UTF_H);
     906  		scols_symbols_set_vertical(sy, UTF_V " ");
     907  		scols_symbols_set_right(sy, UTF_UR UTF_H);
     908  		/* groups chart */
     909  		scols_symbols_set_group_horizontal(sy, UTF_H3);
     910  		scols_symbols_set_group_vertical(sy, UTF_V3);
     911  
     912  		scols_symbols_set_group_first_member(sy,  UTF_DR UTF_H3 UTF_TR);
     913  		scols_symbols_set_group_last_member(sy,   UTF_UR UTF_DH UTF_TR);
     914  		scols_symbols_set_group_middle_member(sy, UTF_VR UTF_H3 UTF_TR);
     915  		scols_symbols_set_group_last_child(sy,    UTF_UR UTF_H3);
     916  		scols_symbols_set_group_middle_child(sy,  UTF_VR UTF_H3);
     917  	} else
     918  #endif
     919  	{
     920  		/* tree chart */
     921  		scols_symbols_set_branch(sy, "|-");
     922  		scols_symbols_set_vertical(sy, "| ");
     923  		scols_symbols_set_right(sy, "`-");
     924  		/* groups chart */
     925  		scols_symbols_set_group_horizontal(sy, "-");
     926  		scols_symbols_set_group_vertical(sy, "|");
     927  
     928  		scols_symbols_set_group_first_member(sy, ",->");
     929  		scols_symbols_set_group_last_member(sy, "'->");
     930  		scols_symbols_set_group_middle_member(sy, "|->");
     931  		scols_symbols_set_group_last_child(sy, "`-");
     932  		scols_symbols_set_group_middle_child(sy, "|-");
     933  	}
     934  	scols_symbols_set_title_padding(sy, " ");
     935  	scols_symbols_set_cell_padding(sy, " ");
     936  
     937  	rc = scols_table_set_symbols(tb, sy);
     938  	scols_unref_symbols(sy);
     939  	return rc;
     940  }
     941  
     942  
     943  /**
     944   * scols_table_set_symbols:
     945   * @tb: table
     946   * @sy: symbols or NULL
     947   *
     948   * Add a reference to @sy from the table. The symbols are used by library to
     949   * draw tree output. If no symbols are used for the table then library creates
     950   * default temporary symbols to draw output by scols_table_set_default_symbols().
     951   *
     952   * If @sy is NULL then remove reference from the currently used symbols.
     953   *
     954   * Returns: 0, a negative value in case of an error.
     955   */
     956  int scols_table_set_symbols(struct libscols_table *tb,
     957  			    struct libscols_symbols *sy)
     958  {
     959  	if (!tb)
     960  		return -EINVAL;
     961  
     962  	/* remove old */
     963  	if (tb->symbols) {
     964  		DBG(TAB, ul_debugobj(tb, "remove symbols reference"));
     965  		scols_unref_symbols(tb->symbols);
     966  		tb->symbols = NULL;
     967  	}
     968  
     969  	/* set new */
     970  	if (sy) {					/* ref user defined */
     971  		DBG(TAB, ul_debugobj(tb, "set symbols"));
     972  		tb->symbols = sy;
     973  		scols_ref_symbols(sy);
     974  	}
     975  	return 0;
     976  }
     977  
     978  /**
     979   * scols_table_get_symbols:
     980   * @tb: table
     981   *
     982   * Returns: pointer to symbols table.
     983   *
     984   * Since: 2.29
     985   */
     986  struct libscols_symbols *scols_table_get_symbols(const struct libscols_table *tb)
     987  {
     988  	return tb->symbols;
     989  }
     990  
     991  /**
     992   * scols_table_enable_nolinesep:
     993   * @tb: table
     994   * @enable: 1 or 0
     995   *
     996   * Enable/disable line separator printing. This is useful if you want to
     997   * re-printing the same line more than once (e.g. progress bar). Don't use it
     998   * if you're not sure.
     999   *
    1000   * Note that for the last line in the table the separator is disabled at all.
    1001   * The library differentiate between table terminator and line terminator
    1002   * (although for standard output \n byte is used in both cases).
    1003   *
    1004   * Returns: 0 on success, negative number in case of an error.
    1005   */
    1006  int scols_table_enable_nolinesep(struct libscols_table *tb, int enable)
    1007  {
    1008  	if (!tb)
    1009  		return -EINVAL;
    1010  
    1011  	DBG(TAB, ul_debugobj(tb, "nolinesep: %s", enable ? "ENABLE" : "DISABLE"));
    1012  	tb->no_linesep = enable ? 1 : 0;
    1013  	return 0;
    1014  }
    1015  
    1016  /**
    1017   * scols_table_is_nolinesep:
    1018   * @tb: a pointer to a struct libscols_table instance
    1019   *
    1020   * Returns: 1 if line separator printing is disabled.
    1021   *
    1022   * Since: 2.29
    1023   */
    1024  int scols_table_is_nolinesep(const struct libscols_table *tb)
    1025  {
    1026  	return tb->no_linesep;
    1027  }
    1028  
    1029  /**
    1030   * scols_table_enable_colors:
    1031   * @tb: table
    1032   * @enable: 1 or 0
    1033   *
    1034   * Enable/disable colors.
    1035   *
    1036   * Returns: 0 on success, negative number in case of an error.
    1037   */
    1038  int scols_table_enable_colors(struct libscols_table *tb, int enable)
    1039  {
    1040  	if (!tb)
    1041  		return -EINVAL;
    1042  
    1043  	DBG(TAB, ul_debugobj(tb, "colors: %s", enable ? "ENABLE" : "DISABLE"));
    1044  	tb->colors_wanted = enable;
    1045  	return 0;
    1046  }
    1047  
    1048  /**
    1049   * scols_table_enable_raw:
    1050   * @tb: table
    1051   * @enable: 1 or 0
    1052   *
    1053   * Enable/disable raw output format. The parsable output formats
    1054   * (export, raw, JSON, ...) are mutually exclusive.
    1055   *
    1056   * Returns: 0 on success, negative number in case of an error.
    1057   */
    1058  int scols_table_enable_raw(struct libscols_table *tb, int enable)
    1059  {
    1060  	if (!tb)
    1061  		return -EINVAL;
    1062  
    1063  	DBG(TAB, ul_debugobj(tb, "raw: %s", enable ? "ENABLE" : "DISABLE"));
    1064  	if (enable)
    1065  		tb->format = SCOLS_FMT_RAW;
    1066  	else if (tb->format == SCOLS_FMT_RAW)
    1067  		tb->format = 0;
    1068  	return 0;
    1069  }
    1070  
    1071  /**
    1072   * scols_table_enable_json:
    1073   * @tb: table
    1074   * @enable: 1 or 0
    1075   *
    1076   * Enable/disable JSON output format. The parsable output formats
    1077   * (export, raw, JSON, ...) are mutually exclusive.
    1078   *
    1079   * Returns: 0 on success, negative number in case of an error.
    1080   *
    1081   * Since: 2.27
    1082   */
    1083  int scols_table_enable_json(struct libscols_table *tb, int enable)
    1084  {
    1085  	if (!tb)
    1086  		return -EINVAL;
    1087  
    1088  	DBG(TAB, ul_debugobj(tb, "json: %s", enable ? "ENABLE" : "DISABLE"));
    1089  	if (enable)
    1090  		tb->format = SCOLS_FMT_JSON;
    1091  	else if (tb->format == SCOLS_FMT_JSON)
    1092  		tb->format = 0;
    1093  	return 0;
    1094  }
    1095  
    1096  /**
    1097   * scols_table_enable_export:
    1098   * @tb: table
    1099   * @enable: 1 or 0
    1100   *
    1101   * Enable/disable export output format (COLUMNAME="value" ...).
    1102   * The parsable output formats (export and raw) are mutually exclusive.
    1103   *
    1104   * See also scols_table_enable_shellvar(). Note that in version 2.37 (and only
    1105   * in this version) scols_table_enable_shellvar() functionality has been
    1106   * automatically enabled  for "export" format. This behavior has been reverted
    1107   * in version 2.38 due to backward compatibility issues. Now it's necessary to
    1108   * explicitly call scols_table_enable_shellvar().
    1109   *
    1110   * Returns: 0 on success, negative number in case of an error.
    1111   */
    1112  int scols_table_enable_export(struct libscols_table *tb, int enable)
    1113  {
    1114  	if (!tb)
    1115  		return -EINVAL;
    1116  
    1117  	DBG(TAB, ul_debugobj(tb, "export: %s", enable ? "ENABLE" : "DISABLE"));
    1118  	if (enable)
    1119  		tb->format = SCOLS_FMT_EXPORT;
    1120  	else if (tb->format == SCOLS_FMT_EXPORT)
    1121  		tb->format = 0;
    1122  	return 0;
    1123  }
    1124  
    1125  /**
    1126   * scols_table_enable_shellvar:
    1127   * @tb: table
    1128   * @enable: 1 or 0
    1129   *
    1130   * Force library to print column names to be compatible with shell requirements
    1131   * to variable names.  For example "1FOO%" will be printed as "_1FOO_PCT".
    1132   *
    1133   * Returns: 0 on success, negative number in case of an error.
    1134   *
    1135   * Since: 2.38
    1136   */
    1137  int scols_table_enable_shellvar(struct libscols_table *tb, int enable)
    1138  {
    1139  	if (!tb)
    1140  		return -EINVAL;
    1141  
    1142  	DBG(TAB, ul_debugobj(tb, "shellvar: %s", enable ? "ENABLE" : "DISABLE"));
    1143  	tb->is_shellvar = enable ? 1 : 0;
    1144  	return 0;
    1145  }
    1146  
    1147  
    1148  /**
    1149   * scols_table_enable_ascii:
    1150   * @tb: table
    1151   * @enable: 1 or 0
    1152   *
    1153   * The ASCII-only output is relevant for tree-like outputs. The library
    1154   * checks if the current environment is UTF8 compatible by default. This
    1155   * function overrides this check and force the library to use ASCII chars
    1156   * for the tree.
    1157   *
    1158   * If a custom libcols_symbols are specified (see scols_table_set_symbols()
    1159   * then ASCII flag setting is ignored.
    1160   *
    1161   * Returns: 0 on success, negative number in case of an error.
    1162   */
    1163  int scols_table_enable_ascii(struct libscols_table *tb, int enable)
    1164  {
    1165  	if (!tb)
    1166  		return -EINVAL;
    1167  
    1168  	DBG(TAB, ul_debugobj(tb, "ascii: %s", enable ? "ENABLE" : "DISABLE"));
    1169  	tb->ascii = enable ? 1 : 0;
    1170  	return 0;
    1171  }
    1172  
    1173  /**
    1174   * scols_table_enable_noheadings:
    1175   * @tb: table
    1176   * @enable: 1 or 0
    1177   *
    1178   * Enable/disable header line.
    1179   *
    1180   * Returns: 0 on success, negative number in case of an error.
    1181   */
    1182  int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
    1183  {
    1184  	if (!tb)
    1185  		return -EINVAL;
    1186  	DBG(TAB, ul_debugobj(tb, "noheading: %s", enable ? "ENABLE" : "DISABLE"));
    1187  	tb->no_headings = enable ? 1 : 0;
    1188  	return 0;
    1189  }
    1190  
    1191  /**
    1192   * scols_table_enable_header_repeat:
    1193   * @tb: table
    1194   * @enable: 1 or 0
    1195   *
    1196   * Enable/disable header line repeat. The header line is printed only once by
    1197   * default.  Note that the flag will be silently ignored and disabled if the
    1198   * output is not on terminal or output format is JSON, raw, etc.
    1199   *
    1200   * Returns: 0 on success, negative number in case of an error.
    1201   *
    1202   * Since: 2.31
    1203   */
    1204  int scols_table_enable_header_repeat(struct libscols_table *tb, int enable)
    1205  {
    1206  	if (!tb)
    1207  		return -EINVAL;
    1208  	DBG(TAB, ul_debugobj(tb, "header-repeat: %s", enable ? "ENABLE" : "DISABLE"));
    1209  	tb->header_repeat = enable ? 1 : 0;
    1210  	return 0;
    1211  }
    1212  
    1213  /**
    1214   * scols_table_enable_maxout:
    1215   * @tb: table
    1216   * @enable: 1 or 0
    1217   *
    1218   * The extra space after last column is ignored by default. The output
    1219   * maximization add padding for all columns.
    1220   *
    1221   * This setting is mutually exclusive to scols_table_enable_minout().
    1222   *
    1223   * Returns: 0 on success, negative number in case of an error.
    1224   */
    1225  int scols_table_enable_maxout(struct libscols_table *tb, int enable)
    1226  {
    1227  	if (!tb || tb->minout)
    1228  		return -EINVAL;
    1229  
    1230  	DBG(TAB, ul_debugobj(tb, "maxout: %s", enable ? "ENABLE" : "DISABLE"));
    1231  	tb->maxout = enable ? 1 : 0;
    1232  	return 0;
    1233  }
    1234  
    1235  /**
    1236   * scols_table_enable_minout:
    1237   * @tb: table
    1238   * @enable: 1 or 0
    1239   *
    1240   * Force library to terminate line after last column with data. The extra
    1241   * padding is not added to the empty cells at the end of the line. The default is fill
    1242   * tailing empty cells except the last line cell.
    1243   *
    1244   * This setting is mutually exclusive to scols_table_enable_maxout().
    1245   *
    1246   * Returns: 0 on success, negative number in case of an error.
    1247   *
    1248   * Since: 2.35
    1249   */
    1250  int scols_table_enable_minout(struct libscols_table *tb, int enable)
    1251  {
    1252  	if (!tb || tb->maxout)
    1253  		return -EINVAL;
    1254  
    1255  	DBG(TAB, ul_debugobj(tb, "minout: %s", enable ? "ENABLE" : "DISABLE"));
    1256  	tb->minout = enable ? 1 : 0;
    1257  	return 0;
    1258  }
    1259  
    1260  /**
    1261   * scols_table_enable_nowrap:
    1262   * @tb: table
    1263   * @enable: 1 or 0
    1264   *
    1265   * Never continue on next line, remove last column(s) when too large, truncate last column.
    1266   *
    1267   * Returns: 0 on success, negative number in case of an error.
    1268   *
    1269   * Since: 2.28
    1270   */
    1271  int scols_table_enable_nowrap(struct libscols_table *tb, int enable)
    1272  {
    1273  	if (!tb)
    1274  		return -EINVAL;
    1275  	DBG(TAB, ul_debugobj(tb, "nowrap: %s", enable ? "ENABLE" : "DISABLE"));
    1276  	tb->no_wrap = enable ? 1 : 0;
    1277  	return 0;
    1278  }
    1279  
    1280  /**
    1281   * scols_table_is_nowrap:
    1282   * @tb: a pointer to a struct libscols_table instance
    1283   *
    1284   * Returns: 1 if nowrap is enabled.
    1285   *
    1286   * Since: 2.29
    1287   */
    1288  int scols_table_is_nowrap(const struct libscols_table *tb)
    1289  {
    1290  	return tb->no_wrap;
    1291  }
    1292  
    1293  /**
    1294   * scols_table_enable_noencoding:
    1295   * @tb: table
    1296   * @enable: 1 or 0
    1297   *
    1298   * The library encode non-printable and control chars by \xHEX by default.
    1299   *
    1300   * Returns: 0 on success, negative number in case of an error.
    1301   *
    1302   * Since: 2.31
    1303   */
    1304  int scols_table_enable_noencoding(struct libscols_table *tb, int enable)
    1305  {
    1306  	if (!tb)
    1307  		return -EINVAL;
    1308  	DBG(TAB, ul_debugobj(tb, "encoding: %s", enable ? "ENABLE" : "DISABLE"));
    1309  	tb->no_encode = enable ? 1 : 0;
    1310  	return 0;
    1311  }
    1312  
    1313  /**
    1314   * scols_table_is_noencoding:
    1315   * @tb: a pointer to a struct libscols_table instance
    1316   *
    1317   * Returns: 1 if encoding is disabled.
    1318   *
    1319   * Since: 2.31
    1320   */
    1321  int scols_table_is_noencoding(const struct libscols_table *tb)
    1322  {
    1323  	return tb->no_encode;
    1324  }
    1325  
    1326  /**
    1327   * scols_table_colors_wanted:
    1328   * @tb: table
    1329   *
    1330   * Returns: 1 if colors are enabled.
    1331   */
    1332  int scols_table_colors_wanted(const struct libscols_table *tb)
    1333  {
    1334  	return tb->colors_wanted;
    1335  }
    1336  
    1337  /**
    1338   * scols_table_is_empty:
    1339   * @tb: table
    1340   *
    1341   * Returns: 1 if the table is empty.
    1342   */
    1343  int scols_table_is_empty(const struct libscols_table *tb)
    1344  {
    1345  	return !tb->nlines;
    1346  }
    1347  
    1348  /**
    1349   * scols_table_is_ascii:
    1350   * @tb: table
    1351   *
    1352   * Returns: 1 if ASCII tree is enabled.
    1353   */
    1354  int scols_table_is_ascii(const struct libscols_table *tb)
    1355  {
    1356  	return tb->ascii;
    1357  }
    1358  
    1359  /**
    1360   * scols_table_is_noheadings:
    1361   * @tb: table
    1362   *
    1363   * Returns: 1 if header output is disabled.
    1364   */
    1365  int scols_table_is_noheadings(const struct libscols_table *tb)
    1366  {
    1367  	return tb->no_headings;
    1368  }
    1369  
    1370  /**
    1371   * scols_table_is_header_repeat
    1372   * @tb: table
    1373   *
    1374   * Returns: 1 if header repeat is enabled.
    1375   *
    1376   * Since: 2.31
    1377   */
    1378  int scols_table_is_header_repeat(const struct libscols_table *tb)
    1379  {
    1380  	return tb->header_repeat;
    1381  }
    1382  
    1383  /**
    1384   * scols_table_is_export:
    1385   * @tb: table
    1386   *
    1387   * Returns: 1 if export output format is enabled.
    1388   */
    1389  int scols_table_is_export(const struct libscols_table *tb)
    1390  {
    1391  	return tb->format == SCOLS_FMT_EXPORT;
    1392  }
    1393  
    1394  /**
    1395   * scols_table_is_shellvar:
    1396   * @tb: table
    1397   *
    1398   * Returns: 1 if column names has to be compatible with shell requirements
    1399   *          to variable names
    1400   *
    1401   * Since: 2.38
    1402   */
    1403  int scols_table_is_shellvar(const struct libscols_table *tb)
    1404  {
    1405  	return tb->is_shellvar;
    1406  }
    1407  
    1408  /**
    1409   * scols_table_is_raw:
    1410   * @tb: table
    1411   *
    1412   * Returns: 1 if raw output format is enabled.
    1413   */
    1414  int scols_table_is_raw(const struct libscols_table *tb)
    1415  {
    1416  	return tb->format == SCOLS_FMT_RAW;
    1417  }
    1418  
    1419  /**
    1420   * scols_table_is_json:
    1421   * @tb: table
    1422   *
    1423   * Returns: 1 if JSON output format is enabled.
    1424   *
    1425   * Since: 2.27
    1426   */
    1427  int scols_table_is_json(const struct libscols_table *tb)
    1428  {
    1429  	return tb->format == SCOLS_FMT_JSON;
    1430  }
    1431  
    1432  /**
    1433   * scols_table_is_maxout
    1434   * @tb: table
    1435   *
    1436   * Returns: 1 if output maximization is enabled or 0
    1437   */
    1438  int scols_table_is_maxout(const struct libscols_table *tb)
    1439  {
    1440  	return tb->maxout;
    1441  }
    1442  
    1443  /**
    1444   * scols_table_is_minout
    1445   * @tb: table
    1446   *
    1447   * Returns: 1 if output minimization is enabled or 0
    1448   *
    1449   * Since: 2.35
    1450   */
    1451  int scols_table_is_minout(const struct libscols_table *tb)
    1452  {
    1453  	return tb->minout;
    1454  }
    1455  
    1456  /**
    1457   * scols_table_is_tree:
    1458   * @tb: table
    1459   *
    1460   * Returns: returns 1 tree-like output is expected.
    1461   */
    1462  int scols_table_is_tree(const struct libscols_table *tb)
    1463  {
    1464  	return tb->ntreecols > 0;
    1465  }
    1466  
    1467  /**
    1468   * scols_table_set_column_separator:
    1469   * @tb: table
    1470   * @sep: separator
    1471   *
    1472   * Sets the column separator of @tb to @sep.
    1473   *
    1474   * Returns: 0, a negative value in case of an error.
    1475   */
    1476  int scols_table_set_column_separator(struct libscols_table *tb, const char *sep)
    1477  {
    1478  	return strdup_to_struct_member(tb, colsep, sep);
    1479  }
    1480  
    1481  /**
    1482   * scols_table_set_line_separator:
    1483   * @tb: table
    1484   * @sep: separator
    1485   *
    1486   * Sets the line separator of @tb to @sep.
    1487   *
    1488   * Returns: 0, a negative value in case of an error.
    1489   */
    1490  int scols_table_set_line_separator(struct libscols_table *tb, const char *sep)
    1491  {
    1492  	return strdup_to_struct_member(tb, linesep, sep);
    1493  }
    1494  
    1495  /**
    1496   * scols_table_get_column_separator:
    1497   * @tb: table
    1498   *
    1499   * Returns: @tb column separator, NULL in case of an error
    1500   */
    1501  const char *scols_table_get_column_separator(const struct libscols_table *tb)
    1502  {
    1503  	return tb->colsep;
    1504  }
    1505  
    1506  /**
    1507   * scols_table_get_line_separator:
    1508   * @tb: table
    1509   *
    1510   * Returns: @tb line separator, NULL in case of an error
    1511   */
    1512  const char *scols_table_get_line_separator(const struct libscols_table *tb)
    1513  {
    1514  	return tb->linesep;
    1515  }
    1516  /* for lines in the struct libscols_line->ln_lines list */
    1517  static int cells_cmp_wrapper_lines(struct list_head *a, struct list_head *b, void *data)
    1518  {
    1519  	struct libscols_column *cl = (struct libscols_column *) data;
    1520  	struct libscols_line *ra, *rb;
    1521  	struct libscols_cell *ca, *cb;
    1522  
    1523  	assert(a);
    1524  	assert(b);
    1525  	assert(cl);
    1526  
    1527  	ra = list_entry(a, struct libscols_line, ln_lines);
    1528  	rb = list_entry(b, struct libscols_line, ln_lines);
    1529  	ca = scols_line_get_cell(ra, cl->seqnum);
    1530  	cb = scols_line_get_cell(rb, cl->seqnum);
    1531  
    1532  	return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
    1533  }
    1534  
    1535  /* for lines in the struct libscols_line->ln_children list */
    1536  static int cells_cmp_wrapper_children(struct list_head *a, struct list_head *b, void *data)
    1537  {
    1538  	struct libscols_column *cl = (struct libscols_column *) data;
    1539  	struct libscols_line *ra, *rb;
    1540  	struct libscols_cell *ca, *cb;
    1541  
    1542  	assert(a);
    1543  	assert(b);
    1544  	assert(cl);
    1545  
    1546  	ra = list_entry(a, struct libscols_line, ln_children);
    1547  	rb = list_entry(b, struct libscols_line, ln_children);
    1548  	ca = scols_line_get_cell(ra, cl->seqnum);
    1549  	cb = scols_line_get_cell(rb, cl->seqnum);
    1550  
    1551  	return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
    1552  }
    1553  
    1554  
    1555  static int sort_line_children(struct libscols_line *ln, struct libscols_column *cl)
    1556  {
    1557  	struct list_head *p;
    1558  
    1559  	if (!list_empty(&ln->ln_branch)) {
    1560  		list_for_each(p, &ln->ln_branch) {
    1561  			struct libscols_line *chld =
    1562  					list_entry(p, struct libscols_line, ln_children);
    1563  			sort_line_children(chld, cl);
    1564  		}
    1565  
    1566  		list_sort(&ln->ln_branch, cells_cmp_wrapper_children, cl);
    1567  	}
    1568  
    1569  	if (is_first_group_member(ln)) {
    1570  		list_for_each(p, &ln->group->gr_children) {
    1571  			struct libscols_line *chld =
    1572  					list_entry(p, struct libscols_line, ln_children);
    1573  			sort_line_children(chld, cl);
    1574  		}
    1575  
    1576  		list_sort(&ln->group->gr_children, cells_cmp_wrapper_children, cl);
    1577  	}
    1578  
    1579  	return 0;
    1580  }
    1581  
    1582  static int  __scols_sort_tree(struct libscols_table *tb, struct libscols_column *cl)
    1583  {
    1584  	struct libscols_line *ln;
    1585  	struct libscols_iter itr;
    1586  
    1587  	if (!tb || !cl || !cl->cmpfunc)
    1588  		return -EINVAL;
    1589  
    1590  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
    1591  	while (scols_table_next_line(tb, &itr, &ln) == 0)
    1592  		sort_line_children(ln, cl);
    1593  	return 0;
    1594  }
    1595  
    1596  /**
    1597   * scols_sort_table:
    1598   * @tb: table
    1599   * @cl: order by this column or NULL
    1600   *
    1601   * Orders the table by the column. See also scols_column_set_cmpfunc(). If the
    1602   * tree output is enabled then children in the tree are recursively sorted too.
    1603   *
    1604   * The column @cl is saved as the default sort column to the @tb and the next time
    1605   * is possible to call scols_sort_table(tb, NULL). The saved column is also used by
    1606   * scols_sort_table_by_tree().
    1607   *
    1608   * Returns: 0, a negative value in case of an error.
    1609   */
    1610  int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl)
    1611  {
    1612  	if (!tb)
    1613  		return -EINVAL;
    1614  	if (!cl)
    1615  		cl = tb->dflt_sort_column;
    1616  	if (!cl || !cl->cmpfunc)
    1617  		return -EINVAL;
    1618  
    1619  	DBG(TAB, ul_debugobj(tb, "sorting table by %zu column", cl->seqnum));
    1620  	list_sort(&tb->tb_lines, cells_cmp_wrapper_lines, cl);
    1621  
    1622  	if (scols_table_is_tree(tb))
    1623  		__scols_sort_tree(tb, cl);
    1624  
    1625  	if (cl && cl != tb->dflt_sort_column)
    1626  		tb->dflt_sort_column = cl;
    1627  
    1628  	return 0;
    1629  }
    1630  
    1631  /*
    1632   * Move all @ln's children after @ln in the table.
    1633   */
    1634  static struct libscols_line *move_line_and_children(struct libscols_line *ln, struct libscols_line *pre)
    1635  {
    1636  	if (pre) {
    1637  		list_del_init(&ln->ln_lines);			/* remove from old position */
    1638  	        list_add(&ln->ln_lines, &pre->ln_lines);        /* add to the new place (after @pre) */
    1639  	}
    1640  	pre = ln;
    1641  
    1642  	if (!list_empty(&ln->ln_branch)) {
    1643  		struct list_head *p;
    1644  
    1645  		list_for_each(p, &ln->ln_branch) {
    1646  			struct libscols_line *chld =
    1647  					list_entry(p, struct libscols_line, ln_children);
    1648  			pre = move_line_and_children(chld, pre);
    1649  		}
    1650  	}
    1651  
    1652  	return pre;
    1653  }
    1654  
    1655  /**
    1656   * scols_sort_table_by_tree:
    1657   * @tb: table
    1658   *
    1659   * Reorders lines in the table by parent->child relation. Note that order of
    1660   * the lines in the table is independent on the tree hierarchy by default.
    1661   *
    1662   * The children of the lines are sorted according to the default sort column
    1663   * if scols_sort_table() has been previously called.
    1664   *
    1665   * Since: 2.30
    1666   *
    1667   * Returns: 0, a negative value in case of an error.
    1668   */
    1669  int scols_sort_table_by_tree(struct libscols_table *tb)
    1670  {
    1671  	struct libscols_line *ln;
    1672  	struct libscols_iter itr;
    1673  
    1674  	if (!tb)
    1675  		return -EINVAL;
    1676  
    1677  	DBG(TAB, ul_debugobj(tb, "sorting table by tree"));
    1678  
    1679  	if (tb->dflt_sort_column)
    1680  		__scols_sort_tree(tb, tb->dflt_sort_column);
    1681  
    1682  	scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
    1683  	while (scols_table_next_line(tb, &itr, &ln) == 0)
    1684  		move_line_and_children(ln, NULL);
    1685  
    1686  	return 0;
    1687  }
    1688  
    1689  
    1690  /**
    1691   * scols_table_set_termforce:
    1692   * @tb: table
    1693   * @force: SCOLS_TERMFORCE_{NEVER,ALWAYS,AUTO}
    1694   *
    1695   * Forces library to use stdout as terminal, non-terminal or use automatic
    1696   * detection (default).
    1697   *
    1698   * Returns: 0, a negative value in case of an error.
    1699   *
    1700   * Since: 2.29
    1701   */
    1702  int scols_table_set_termforce(struct libscols_table *tb, int force)
    1703  {
    1704  	if (!tb)
    1705  		return -EINVAL;
    1706  	tb->termforce = force;
    1707  	return 0;
    1708  }
    1709  
    1710  /**
    1711   * scols_table_get_termforce:
    1712   * @tb: table
    1713   *
    1714   * Returns: SCOLS_TERMFORCE_{NEVER,ALWAYS,AUTO} or a negative value in case of an error.
    1715   *
    1716   * Since: 2.29
    1717   */
    1718  int scols_table_get_termforce(const struct libscols_table *tb)
    1719  {
    1720  	return tb->termforce;
    1721  }
    1722  
    1723  /**
    1724   * scols_table_set_termwidth
    1725   * @tb: table
    1726   * @width: terminal width
    1727   *
    1728   * The library automatically detects terminal width or defaults to 80 chars if
    1729   * detections is unsuccessful. This function override this behaviour.
    1730   *
    1731   * Returns: 0, a negative value in case of an error.
    1732   *
    1733   * Since: 2.29
    1734   */
    1735  int scols_table_set_termwidth(struct libscols_table *tb, size_t width)
    1736  {
    1737  	DBG(TAB, ul_debugobj(tb, "set terminatl width: %zu", width));
    1738  	tb->termwidth = width;
    1739  	return 0;
    1740  }
    1741  
    1742  /**
    1743   * scols_table_get_termwidth
    1744   * @tb: table
    1745   *
    1746   * Returns: terminal width.
    1747   */
    1748  size_t scols_table_get_termwidth(const struct libscols_table *tb)
    1749  {
    1750  	return tb->termwidth;
    1751  }
    1752  
    1753  /**
    1754   * scols_table_set_termheight
    1755   * @tb: table
    1756   * @height: terminal height (number of lines)
    1757   *
    1758   * The library automatically detects terminal height or defaults to 24 lines if
    1759   * detections is unsuccessful. This function override this behaviour.
    1760   *
    1761   * Returns: 0, a negative value in case of an error.
    1762   *
    1763   * Since: 2.31
    1764   */
    1765  int scols_table_set_termheight(struct libscols_table *tb, size_t height)
    1766  {
    1767  	DBG(TAB, ul_debugobj(tb, "set terminatl height: %zu", height));
    1768  	tb->termheight = height;
    1769  	return 0;
    1770  }
    1771  
    1772  /**
    1773   * scols_table_get_termheight
    1774   * @tb: table
    1775   *
    1776   * Returns: terminal height (number of lines).
    1777   *
    1778   * Since: 2.31
    1779   */
    1780  size_t scols_table_get_termheight(const struct libscols_table *tb)
    1781  {
    1782  	return tb->termheight;
    1783  }