]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libsmartcols/src/table.c
fstrim shouldn't run inside a container
[thirdparty/util-linux.git] / 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 enabled! */
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
274 DBG(TAB, ul_debugobj(tb, "remove column"));
275 list_del_init(&cl->cl_columns);
276 tb->ncols--;
277 cl->table = NULL;
278 scols_unref_column(cl);
279 return 0;
280 }
281
282 /**
283 * scols_table_remove_columns:
284 * @tb: a pointer to a struct libscols_table instance
285 *
286 * Removes all of @tb's columns.
287 *
288 * Returns: 0, a negative number in case of an error.
289 */
290 int scols_table_remove_columns(struct libscols_table *tb)
291 {
292 if (!tb || !list_empty(&tb->tb_lines))
293 return -EINVAL;
294
295 DBG(TAB, ul_debugobj(tb, "remove all columns"));
296 while (!list_empty(&tb->tb_columns)) {
297 struct libscols_column *cl = list_entry(tb->tb_columns.next,
298 struct libscols_column, cl_columns);
299 scols_table_remove_column(tb, cl);
300 }
301 return 0;
302 }
303
304 /**
305 * scols_table_move_column:
306 * @tb: table
307 * @pre: column before the column
308 * @cl: column to move
309 *
310 * Move the @cl behind @pre. If the @pre is NULL then the @col is the first
311 * column in the table.
312 *
313 * Since: 2.30
314 *
315 * Returns: 0, a negative number in case of an error.
316 */
317 int scols_table_move_column(struct libscols_table *tb,
318 struct libscols_column *pre,
319 struct libscols_column *cl)
320 {
321 struct list_head *head;
322 struct libscols_iter itr;
323 struct libscols_column *p;
324 struct libscols_line *ln;
325 size_t n = 0, oldseq;
326
327 if (!tb || !cl)
328 return -EINVAL;
329
330 if (pre && pre->seqnum + 1 == cl->seqnum)
331 return 0;
332 if (pre == NULL && cl->seqnum == 0)
333 return 0;
334
335 DBG(TAB, ul_debugobj(tb, "move column %zu behind %zu",
336 cl->seqnum, pre? pre->seqnum : 0));
337
338 list_del_init(&cl->cl_columns); /* remove from old position */
339
340 head = pre ? &pre->cl_columns : &tb->tb_columns;
341 list_add(&cl->cl_columns, head); /* add to the new place */
342
343 oldseq = cl->seqnum;
344
345 /* fix seq. numbers */
346 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
347 while (scols_table_next_column(tb, &itr, &p) == 0)
348 p->seqnum = n++;
349
350 /* move data in lines */
351 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
352 while (scols_table_next_line(tb, &itr, &ln) == 0)
353 scols_line_move_cells(ln, cl->seqnum, oldseq);
354 return 0;
355 }
356
357 /**
358 * scols_table_new_column:
359 * @tb: table
360 * @name: column header
361 * @whint: column width hint (absolute width: N > 1; relative width: 0 < N < 1)
362 * @flags: flags integer
363 *
364 * This is shortcut for
365 *
366 * cl = scols_new_column();
367 * scols_column_set_....(cl, ...);
368 * scols_table_add_column(tb, cl);
369 *
370 * The column width is possible to define by:
371 *
372 * @whint: 0 < N < 1 : relative width, percent of terminal width
373 *
374 * @whint: N >= 1 : absolute width, empty column will be truncated to
375 * the column header width if no specified STRICTWIDTH flag
376 *
377 * Note that if table has disabled "maxout" flag (disabled by default) than
378 * relative width is used as a hint only. It's possible that column will be
379 * narrow if the specified size is too large for column data.
380 *
381 *
382 * If the width of all columns is greater than terminal width then library
383 * tries to reduce width of the individual columns. It's done in three stages:
384 *
385 * #1 reduce columns with SCOLS_FL_TRUNC flag and with relative width if the
386 * width is greater than width defined by @whint (@whint * terminal_width)
387 *
388 * #2 reduce all columns with SCOLS_FL_TRUNC flag
389 *
390 * #3 reduce all columns with relative width
391 *
392 * The next stage is always used if the previous stage is unsuccessful. Note
393 * that SCOLS_FL_WRAP is interpreted as SCOLS_FL_TRUNC when calculate column
394 * width (if custom wrap function is not specified), but the final text is not
395 * truncated, but wrapped to multi-line cell.
396 *
397 *
398 * The column is necessary to address by sequential number. The first defined
399 * column has the colnum = 0. For example:
400 *
401 * scols_table_new_column(tab, "FOO", 0.5, 0); // colnum = 0
402 * scols_table_new_column(tab, "BAR", 0.5, 0); // colnum = 1
403 * .
404 * .
405 * scols_line_get_cell(line, 0); // FOO column
406 * scols_line_get_cell(line, 1); // BAR column
407 *
408 * Returns: newly allocated column
409 */
410 struct libscols_column *scols_table_new_column(struct libscols_table *tb,
411 const char *name,
412 double whint,
413 int flags)
414 {
415 struct libscols_column *cl;
416 struct libscols_cell *hr;
417
418 if (!tb)
419 return NULL;
420
421 DBG(TAB, ul_debugobj(tb, "new column name=%s, whint=%g, flags=%d",
422 name, whint, flags));
423 cl = scols_new_column();
424 if (!cl)
425 return NULL;
426
427 /* set column name */
428 hr = scols_column_get_header(cl);
429 if (!hr)
430 goto err;
431 if (scols_cell_set_data(hr, name))
432 goto err;
433
434 scols_column_set_whint(cl, whint);
435 scols_column_set_flags(cl, flags);
436
437 if (scols_table_add_column(tb, cl)) /* this increments column ref-counter */
438 goto err;
439
440 scols_unref_column(cl);
441 return cl;
442 err:
443 scols_unref_column(cl);
444 return NULL;
445 }
446
447 /**
448 * scols_table_next_column:
449 * @tb: a pointer to a struct libscols_table instance
450 * @itr: a pointer to a struct libscols_iter instance
451 * @cl: a pointer to a pointer to a struct libscols_column instance
452 *
453 * Returns the next column of @tb via @cl.
454 *
455 * Returns: 0, a negative value in case of an error.
456 */
457 int scols_table_next_column(struct libscols_table *tb,
458 struct libscols_iter *itr,
459 struct libscols_column **cl)
460 {
461 int rc = 1;
462
463 if (!tb || !itr || !cl)
464 return -EINVAL;
465 *cl = NULL;
466
467 if (!itr->head)
468 SCOLS_ITER_INIT(itr, &tb->tb_columns);
469 if (itr->p != itr->head) {
470 SCOLS_ITER_ITERATE(itr, *cl, struct libscols_column, cl_columns);
471 rc = 0;
472 }
473
474 return rc;
475 }
476
477 /**
478 * scols_table_set_columns_iter:
479 * @tb: tab pointer
480 * @itr: iterator
481 * @cl: tab entry
482 *
483 * Sets @iter to the position of @cl in the file @tb.
484 *
485 * Returns: 0 on success, negative number in case of error.
486 */
487 int scols_table_set_columns_iter(
488 struct libscols_table *tb,
489 struct libscols_iter *itr,
490 struct libscols_column *cl)
491 {
492 if (!tb || !itr || !cl)
493 return -EINVAL;
494
495 if (cl->table != tb)
496 return -EINVAL;
497
498 SCOLS_ITER_INIT(itr, &tb->tb_columns);
499 itr->p = &cl->cl_columns;
500
501 return 0;
502 }
503
504 /**
505 * scols_table_get_ncols:
506 * @tb: table
507 *
508 * Returns: the ncols table member.
509 */
510 size_t scols_table_get_ncols(const struct libscols_table *tb)
511 {
512 return tb->ncols;
513 }
514
515 /**
516 * scols_table_get_nlines:
517 * @tb: table
518 *
519 * Returns: the nlines table member.
520 */
521 size_t scols_table_get_nlines(const struct libscols_table *tb)
522 {
523 return tb->nlines;
524 }
525
526 /**
527 * scols_table_set_stream:
528 * @tb: table
529 * @stream: output stream
530 *
531 * Sets the output stream for table @tb.
532 *
533 * Returns: 0, a negative number in case of an error.
534 */
535 int scols_table_set_stream(struct libscols_table *tb, FILE *stream)
536 {
537 assert(tb);
538 if (!tb)
539 return -EINVAL;
540
541 DBG(TAB, ul_debugobj(tb, "setting alternative stream"));
542 tb->out = stream;
543 return 0;
544 }
545
546 /**
547 * scols_table_get_stream:
548 * @tb: table
549 *
550 * Gets the output stream for table @tb.
551 *
552 * Returns: stream pointer, NULL in case of an error or an unset stream.
553 */
554 FILE *scols_table_get_stream(const struct libscols_table *tb)
555 {
556 return tb->out;
557 }
558
559 /**
560 * scols_table_reduce_termwidth:
561 * @tb: table
562 * @reduce: width
563 *
564 * If necessary then libsmartcols use all terminal width, the @reduce setting
565 * provides extra space (for example for borders in ncurses applications).
566 *
567 * The @reduce must be smaller than terminal width, otherwise it's silently
568 * ignored. The reduction is not applied when STDOUT_FILENO is not terminal.
569 *
570 * Note that after output initialization (scols_table_print_* calls) the width
571 * will be reduced, this behavior affects subsequenced scols_table_get_termwidth()
572 * calls.
573 *
574 * Returns: 0, a negative value in case of an error.
575 */
576 int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce)
577 {
578 if (!tb)
579 return -EINVAL;
580
581 DBG(TAB, ul_debugobj(tb, "reduce terminal width: %zu", reduce));
582 tb->termreduce = reduce;
583 return 0;
584 }
585
586 /**
587 * scols_table_get_column:
588 * @tb: table
589 * @n: number of column (0..N)
590 *
591 * Returns: pointer to column or NULL
592 */
593 struct libscols_column *scols_table_get_column(struct libscols_table *tb,
594 size_t n)
595 {
596 struct libscols_iter itr;
597 struct libscols_column *cl;
598
599 if (!tb)
600 return NULL;
601 if (n >= tb->ncols)
602 return NULL;
603
604 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
605 while (scols_table_next_column(tb, &itr, &cl) == 0) {
606 if (cl->seqnum == n)
607 return cl;
608 }
609 return NULL;
610 }
611
612 /**
613 * scols_table_add_line:
614 * @tb: table
615 * @ln: line
616 *
617 * Note that this function calls scols_line_alloc_cells() if number
618 * of the cells in the line is too small for @tb.
619 *
620 * Returns: 0, a negative value in case of an error.
621 */
622 int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
623 {
624 if (!tb || !ln)
625 return -EINVAL;
626
627 if (!list_empty(&ln->ln_lines))
628 return -EINVAL;
629
630 if (tb->ncols > ln->ncells) {
631 int rc = scols_line_alloc_cells(ln, tb->ncols);
632 if (rc)
633 return rc;
634 }
635
636 DBG(TAB, ul_debugobj(tb, "add line"));
637 list_add_tail(&ln->ln_lines, &tb->tb_lines);
638 ln->seqnum = tb->nlines++;
639 scols_ref_line(ln);
640 return 0;
641 }
642
643 /**
644 * scols_table_remove_line:
645 * @tb: table
646 * @ln: line
647 *
648 * Note that this function does not destroy the parent<->child relationship between lines.
649 * You have to call scols_line_remove_child()
650 *
651 * Returns: 0, a negative value in case of an error.
652 */
653 int scols_table_remove_line(struct libscols_table *tb,
654 struct libscols_line *ln)
655 {
656 if (!tb || !ln)
657 return -EINVAL;
658
659 DBG(TAB, ul_debugobj(tb, "remove line"));
660 list_del_init(&ln->ln_lines);
661 tb->nlines--;
662 scols_unref_line(ln);
663 return 0;
664 }
665
666 /**
667 * scols_table_remove_lines:
668 * @tb: table
669 *
670 * This empties the table and also destroys all the parent<->child relationships.
671 */
672 void scols_table_remove_lines(struct libscols_table *tb)
673 {
674 if (!tb)
675 return;
676
677 DBG(TAB, ul_debugobj(tb, "remove all lines"));
678 while (!list_empty(&tb->tb_lines)) {
679 struct libscols_line *ln = list_entry(tb->tb_lines.next,
680 struct libscols_line, ln_lines);
681 if (ln->parent)
682 scols_line_remove_child(ln->parent, ln);
683 scols_table_remove_line(tb, ln);
684 }
685 }
686
687 /**
688 * scols_table_next_line:
689 * @tb: a pointer to a struct libscols_table instance
690 * @itr: a pointer to a struct libscols_iter instance
691 * @ln: a pointer to a pointer to a struct libscols_line instance
692 *
693 * Finds the next line and returns a pointer to it via @ln.
694 *
695 * Returns: 0, a negative value in case of an error.
696 */
697 int scols_table_next_line(struct libscols_table *tb,
698 struct libscols_iter *itr,
699 struct libscols_line **ln)
700 {
701 int rc = 1;
702
703 if (!tb || !itr || !ln)
704 return -EINVAL;
705 *ln = NULL;
706
707 if (!itr->head)
708 SCOLS_ITER_INIT(itr, &tb->tb_lines);
709 if (itr->p != itr->head) {
710 SCOLS_ITER_ITERATE(itr, *ln, struct libscols_line, ln_lines);
711 rc = 0;
712 }
713
714 return rc;
715 }
716
717 /**
718 * scols_table_new_line:
719 * @tb: table
720 * @parent: parental line or NULL
721 *
722 * This is shortcut for
723 *
724 * ln = scols_new_line();
725 * scols_table_add_line(tb, ln);
726 * scols_line_add_child(parent, ln);
727 *
728 *
729 * Returns: newly allocate line
730 */
731 struct libscols_line *scols_table_new_line(struct libscols_table *tb,
732 struct libscols_line *parent)
733 {
734 struct libscols_line *ln;
735
736 if (!tb)
737 return NULL;
738
739 ln = scols_new_line();
740 if (!ln)
741 return NULL;
742
743 if (scols_table_add_line(tb, ln))
744 goto err;
745 if (parent)
746 scols_line_add_child(parent, ln);
747
748 scols_unref_line(ln); /* ref-counter incremented by scols_table_add_line() */
749 return ln;
750 err:
751 scols_unref_line(ln);
752 return NULL;
753 }
754
755 /**
756 * scols_table_get_line:
757 * @tb: table
758 * @n: column number (0..N)
759 *
760 * Returns: a line or NULL
761 */
762 struct libscols_line *scols_table_get_line(struct libscols_table *tb,
763 size_t n)
764 {
765 struct libscols_iter itr;
766 struct libscols_line *ln;
767
768 if (!tb)
769 return NULL;
770 if (n >= tb->nlines)
771 return NULL;
772
773 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
774 while (scols_table_next_line(tb, &itr, &ln) == 0) {
775 if (ln->seqnum == n)
776 return ln;
777 }
778 return NULL;
779 }
780
781 /**
782 * scols_copy_table:
783 * @tb: table
784 *
785 * Creates a new independent table copy, except struct libscols_symbols that
786 * are shared between the tables.
787 *
788 * Returns: a newly allocated copy of @tb
789 */
790 struct libscols_table *scols_copy_table(struct libscols_table *tb)
791 {
792 struct libscols_table *ret;
793 struct libscols_line *ln;
794 struct libscols_column *cl;
795 struct libscols_iter itr;
796
797 if (!tb)
798 return NULL;
799 ret = scols_new_table();
800 if (!ret)
801 return NULL;
802
803 DBG(TAB, ul_debugobj(tb, "copy"));
804
805 if (tb->symbols)
806 scols_table_set_symbols(ret, tb->symbols);
807
808 /* columns */
809 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
810 while (scols_table_next_column(tb, &itr, &cl) == 0) {
811 cl = scols_copy_column(cl);
812 if (!cl)
813 goto err;
814 if (scols_table_add_column(ret, cl))
815 goto err;
816 scols_unref_column(cl);
817 }
818
819 /* lines */
820 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
821 while (scols_table_next_line(tb, &itr, &ln) == 0) {
822 struct libscols_line *newln = scols_copy_line(ln);
823 if (!newln)
824 goto err;
825 if (scols_table_add_line(ret, newln))
826 goto err;
827 if (ln->parent) {
828 struct libscols_line *p =
829 scols_table_get_line(ret, ln->parent->seqnum);
830 if (p)
831 scols_line_add_child(p, newln);
832 }
833 scols_unref_line(newln);
834 }
835
836 /* separators */
837 if (scols_table_set_column_separator(ret, tb->colsep) ||
838 scols_table_set_line_separator(ret, tb->linesep))
839 goto err;
840
841 return ret;
842 err:
843 scols_unref_table(ret);
844 return NULL;
845 }
846
847 /**
848 * scols_table_set_default_symbols:
849 * @tb: table
850 *
851 * The library check the current environment to select ASCII or UTF8 symbols.
852 * This default behavior could be controlled by scols_table_enable_ascii().
853 *
854 * Use scols_table_set_symbols() to unset symbols or use your own setting.
855 *
856 * Returns: 0, a negative value in case of an error.
857 *
858 * Since: 2.29
859 */
860 int scols_table_set_default_symbols(struct libscols_table *tb)
861 {
862 struct libscols_symbols *sy;
863 int rc;
864
865 if (!tb)
866 return -EINVAL;
867
868 DBG(TAB, ul_debugobj(tb, "setting default symbols"));
869
870 sy = scols_new_symbols();
871 if (!sy)
872 return -ENOMEM;
873
874 #if defined(HAVE_WIDECHAR)
875 if (!scols_table_is_ascii(tb) &&
876 !strcmp(nl_langinfo(CODESET), "UTF-8")) {
877 /* tree chart */
878 scols_symbols_set_branch(sy, UTF_VR UTF_H);
879 scols_symbols_set_vertical(sy, UTF_V " ");
880 scols_symbols_set_right(sy, UTF_UR UTF_H);
881 /* groups chart */
882 scols_symbols_set_group_horizontal(sy, UTF_H3);
883 scols_symbols_set_group_vertical(sy, UTF_V3);
884
885 scols_symbols_set_group_first_member(sy, UTF_DR UTF_H3 UTF_TR);
886 scols_symbols_set_group_last_member(sy, UTF_UR UTF_DH UTF_TR);
887 scols_symbols_set_group_middle_member(sy, UTF_VR UTF_H3 UTF_TR);
888 scols_symbols_set_group_last_child(sy, UTF_UR UTF_H3);
889 scols_symbols_set_group_middle_child(sy, UTF_VR UTF_H3);
890 } else
891 #endif
892 {
893 /* tree chart */
894 scols_symbols_set_branch(sy, "|-");
895 scols_symbols_set_vertical(sy, "| ");
896 scols_symbols_set_right(sy, "`-");
897 /* groups chart */
898 scols_symbols_set_group_horizontal(sy, "-");
899 scols_symbols_set_group_vertical(sy, "|");
900
901 scols_symbols_set_group_first_member(sy, ",->");
902 scols_symbols_set_group_last_member(sy, "'->");
903 scols_symbols_set_group_middle_member(sy, "|->");
904 scols_symbols_set_group_last_child(sy, "`-");
905 scols_symbols_set_group_middle_child(sy, "|-");
906 }
907 scols_symbols_set_title_padding(sy, " ");
908 scols_symbols_set_cell_padding(sy, " ");
909
910 rc = scols_table_set_symbols(tb, sy);
911 scols_unref_symbols(sy);
912 return rc;
913 }
914
915
916 /**
917 * scols_table_set_symbols:
918 * @tb: table
919 * @sy: symbols or NULL
920 *
921 * Add a reference to @sy from the table. The symbols are used by library to
922 * draw tree output. If no symbols are used for the table then library creates
923 * default temporary symbols to draw output by scols_table_set_default_symbols().
924 *
925 * If @sy is NULL then remove reference from the currently used symbols.
926 *
927 * Returns: 0, a negative value in case of an error.
928 */
929 int scols_table_set_symbols(struct libscols_table *tb,
930 struct libscols_symbols *sy)
931 {
932 if (!tb)
933 return -EINVAL;
934
935 /* remove old */
936 if (tb->symbols) {
937 DBG(TAB, ul_debugobj(tb, "remove symbols reference"));
938 scols_unref_symbols(tb->symbols);
939 tb->symbols = NULL;
940 }
941
942 /* set new */
943 if (sy) { /* ref user defined */
944 DBG(TAB, ul_debugobj(tb, "set symbols"));
945 tb->symbols = sy;
946 scols_ref_symbols(sy);
947 }
948 return 0;
949 }
950
951 /**
952 * scols_table_get_symbols:
953 * @tb: table
954 *
955 * Returns: pointer to symbols table.
956 *
957 * Since: 2.29
958 */
959 struct libscols_symbols *scols_table_get_symbols(const struct libscols_table *tb)
960 {
961 return tb->symbols;
962 }
963
964 /**
965 * scols_table_enable_nolinesep:
966 * @tb: table
967 * @enable: 1 or 0
968 *
969 * Enable/disable line separator printing. This is useful if you want to
970 * re-printing the same line more than once (e.g. progress bar). Don't use it
971 * if you're not sure.
972 *
973 * Note that for the last line in the table the separator is disabled at all.
974 * The library differentiate between table terminator and line terminator
975 * (although for standard output \n byte is used in both cases).
976 *
977 * Returns: 0 on success, negative number in case of an error.
978 */
979 int scols_table_enable_nolinesep(struct libscols_table *tb, int enable)
980 {
981 if (!tb)
982 return -EINVAL;
983
984 DBG(TAB, ul_debugobj(tb, "nolinesep: %s", enable ? "ENABLE" : "DISABLE"));
985 tb->no_linesep = enable ? 1 : 0;
986 return 0;
987 }
988
989 /**
990 * scols_table_is_nolinesep:
991 * @tb: a pointer to a struct libscols_table instance
992 *
993 * Returns: 1 if line separator printing is disabled.
994 *
995 * Since: 2.29
996 */
997 int scols_table_is_nolinesep(const struct libscols_table *tb)
998 {
999 return tb->no_linesep;
1000 }
1001
1002 /**
1003 * scols_table_enable_colors:
1004 * @tb: table
1005 * @enable: 1 or 0
1006 *
1007 * Enable/disable colors.
1008 *
1009 * Returns: 0 on success, negative number in case of an error.
1010 */
1011 int scols_table_enable_colors(struct libscols_table *tb, int enable)
1012 {
1013 if (!tb)
1014 return -EINVAL;
1015
1016 DBG(TAB, ul_debugobj(tb, "colors: %s", enable ? "ENABLE" : "DISABLE"));
1017 tb->colors_wanted = enable;
1018 return 0;
1019 }
1020
1021 /**
1022 * scols_table_enable_raw:
1023 * @tb: table
1024 * @enable: 1 or 0
1025 *
1026 * Enable/disable raw output format. The parsable output formats
1027 * (export, raw, JSON, ...) are mutually exclusive.
1028 *
1029 * Returns: 0 on success, negative number in case of an error.
1030 */
1031 int scols_table_enable_raw(struct libscols_table *tb, int enable)
1032 {
1033 if (!tb)
1034 return -EINVAL;
1035
1036 DBG(TAB, ul_debugobj(tb, "raw: %s", enable ? "ENABLE" : "DISABLE"));
1037 if (enable)
1038 tb->format = SCOLS_FMT_RAW;
1039 else if (tb->format == SCOLS_FMT_RAW)
1040 tb->format = 0;
1041 return 0;
1042 }
1043
1044 /**
1045 * scols_table_enable_json:
1046 * @tb: table
1047 * @enable: 1 or 0
1048 *
1049 * Enable/disable JSON output format. The parsable output formats
1050 * (export, raw, JSON, ...) are mutually exclusive.
1051 *
1052 * Returns: 0 on success, negative number in case of an error.
1053 *
1054 * Since: 2.27
1055 */
1056 int scols_table_enable_json(struct libscols_table *tb, int enable)
1057 {
1058 if (!tb)
1059 return -EINVAL;
1060
1061 DBG(TAB, ul_debugobj(tb, "json: %s", enable ? "ENABLE" : "DISABLE"));
1062 if (enable)
1063 tb->format = SCOLS_FMT_JSON;
1064 else if (tb->format == SCOLS_FMT_JSON)
1065 tb->format = 0;
1066 return 0;
1067 }
1068
1069 /**
1070 * scols_table_enable_export:
1071 * @tb: table
1072 * @enable: 1 or 0
1073 *
1074 * Enable/disable export output format (COLUMNAME="value" ...).
1075 * The parsable output formats (export and raw) are mutually exclusive.
1076 *
1077 * Returns: 0 on success, negative number in case of an error.
1078 */
1079 int scols_table_enable_export(struct libscols_table *tb, int enable)
1080 {
1081 if (!tb)
1082 return -EINVAL;
1083
1084 DBG(TAB, ul_debugobj(tb, "export: %s", enable ? "ENABLE" : "DISABLE"));
1085 if (enable)
1086 tb->format = SCOLS_FMT_EXPORT;
1087 else if (tb->format == SCOLS_FMT_EXPORT)
1088 tb->format = 0;
1089 return 0;
1090 }
1091
1092 /**
1093 * scols_table_enable_ascii:
1094 * @tb: table
1095 * @enable: 1 or 0
1096 *
1097 * The ASCII-only output is relevant for tree-like outputs. The library
1098 * checks if the current environment is UTF8 compatible by default. This
1099 * function overrides this check and force the library to use ASCII chars
1100 * for the tree.
1101 *
1102 * If a custom libcols_symbols are specified (see scols_table_set_symbols()
1103 * then ASCII flag setting is ignored.
1104 *
1105 * Returns: 0 on success, negative number in case of an error.
1106 */
1107 int scols_table_enable_ascii(struct libscols_table *tb, int enable)
1108 {
1109 if (!tb)
1110 return -EINVAL;
1111
1112 DBG(TAB, ul_debugobj(tb, "ascii: %s", enable ? "ENABLE" : "DISABLE"));
1113 tb->ascii = enable ? 1 : 0;
1114 return 0;
1115 }
1116
1117 /**
1118 * scols_table_enable_noheadings:
1119 * @tb: table
1120 * @enable: 1 or 0
1121 *
1122 * Enable/disable header line.
1123 *
1124 * Returns: 0 on success, negative number in case of an error.
1125 */
1126 int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
1127 {
1128 if (!tb)
1129 return -EINVAL;
1130 DBG(TAB, ul_debugobj(tb, "noheading: %s", enable ? "ENABLE" : "DISABLE"));
1131 tb->no_headings = enable ? 1 : 0;
1132 return 0;
1133 }
1134
1135 /**
1136 * scols_table_enable_header_repeat:
1137 * @tb: table
1138 * @enable: 1 or 0
1139 *
1140 * Enable/disable header line repeat. The header line is printed only once by
1141 * default. Note that the flag will be silently ignored and disabled if the
1142 * output is not on terminal or output format is JSON, raw, etc.
1143 *
1144 * Returns: 0 on success, negative number in case of an error.
1145 *
1146 * Since: 2.31
1147 */
1148 int scols_table_enable_header_repeat(struct libscols_table *tb, int enable)
1149 {
1150 if (!tb)
1151 return -EINVAL;
1152 DBG(TAB, ul_debugobj(tb, "header-repeat: %s", enable ? "ENABLE" : "DISABLE"));
1153 tb->header_repeat = enable ? 1 : 0;
1154 return 0;
1155 }
1156
1157 /**
1158 * scols_table_enable_maxout:
1159 * @tb: table
1160 * @enable: 1 or 0
1161 *
1162 * The extra space after last column is ignored by default. The output
1163 * maximization add padding for all columns.
1164 *
1165 * This setting is mutually exclusive to cols_table_enable_minout().
1166 *
1167 * Returns: 0 on success, negative number in case of an error.
1168 */
1169 int scols_table_enable_maxout(struct libscols_table *tb, int enable)
1170 {
1171 if (!tb || tb->minout)
1172 return -EINVAL;
1173
1174 DBG(TAB, ul_debugobj(tb, "maxout: %s", enable ? "ENABLE" : "DISABLE"));
1175 tb->maxout = enable ? 1 : 0;
1176 return 0;
1177 }
1178
1179 /**
1180 * scols_table_enable_minout:
1181 * @tb: table
1182 * @enable: 1 or 0
1183 *
1184 * Force library to terminate line after last column with data. The extra
1185 * padding is not added to the empty cells at the end of the line. The default is fill
1186 * tailing empty cells except the last line cell.
1187 *
1188 * This setting is mutually exclusive to cols_table_enable_maxout().
1189 *
1190 * Returns: 0 on success, negative number in case of an error.
1191 */
1192 int scols_table_enable_minout(struct libscols_table *tb, int enable)
1193 {
1194 if (!tb || tb->maxout)
1195 return -EINVAL;
1196
1197 DBG(TAB, ul_debugobj(tb, "minout: %s", enable ? "ENABLE" : "DISABLE"));
1198 tb->minout = enable ? 1 : 0;
1199 return 0;
1200 }
1201
1202 /**
1203 * scols_table_enable_nowrap:
1204 * @tb: table
1205 * @enable: 1 or 0
1206 *
1207 * Never continue on next line, remove last column(s) when too large, truncate last column.
1208 *
1209 * Returns: 0 on success, negative number in case of an error.
1210 *
1211 * Since: 2.28
1212 */
1213 int scols_table_enable_nowrap(struct libscols_table *tb, int enable)
1214 {
1215 if (!tb)
1216 return -EINVAL;
1217 DBG(TAB, ul_debugobj(tb, "nowrap: %s", enable ? "ENABLE" : "DISABLE"));
1218 tb->no_wrap = enable ? 1 : 0;
1219 return 0;
1220 }
1221
1222 /**
1223 * scols_table_is_nowrap:
1224 * @tb: a pointer to a struct libscols_table instance
1225 *
1226 * Returns: 1 if nowrap is enabled.
1227 *
1228 * Since: 2.29
1229 */
1230 int scols_table_is_nowrap(const struct libscols_table *tb)
1231 {
1232 return tb->no_wrap;
1233 }
1234
1235 /**
1236 * scols_table_enable_noencoding:
1237 * @tb: table
1238 * @enable: 1 or 0
1239 *
1240 * The library encode non-printable and control chars by \xHEX by default.
1241 *
1242 * Returns: 0 on success, negative number in case of an error.
1243 *
1244 * Since: 2.31
1245 */
1246 int scols_table_enable_noencoding(struct libscols_table *tb, int enable)
1247 {
1248 if (!tb)
1249 return -EINVAL;
1250 DBG(TAB, ul_debugobj(tb, "encoding: %s", enable ? "ENABLE" : "DISABLE"));
1251 tb->no_encode = enable ? 1 : 0;
1252 return 0;
1253 }
1254
1255 /**
1256 * scols_table_is_noencoding:
1257 * @tb: a pointer to a struct libscols_table instance
1258 *
1259 * Returns: 1 if encoding is disabled.
1260 *
1261 * Since: 2.31
1262 */
1263 int scols_table_is_noencoding(const struct libscols_table *tb)
1264 {
1265 return tb->no_encode;
1266 }
1267
1268 /**
1269 * scols_table_colors_wanted:
1270 * @tb: table
1271 *
1272 * Returns: 1 if colors are enabled.
1273 */
1274 int scols_table_colors_wanted(const struct libscols_table *tb)
1275 {
1276 return tb->colors_wanted;
1277 }
1278
1279 /**
1280 * scols_table_is_empty:
1281 * @tb: table
1282 *
1283 * Returns: 1 if the table is empty.
1284 */
1285 int scols_table_is_empty(const struct libscols_table *tb)
1286 {
1287 return !tb->nlines;
1288 }
1289
1290 /**
1291 * scols_table_is_ascii:
1292 * @tb: table
1293 *
1294 * Returns: 1 if ASCII tree is enabled.
1295 */
1296 int scols_table_is_ascii(const struct libscols_table *tb)
1297 {
1298 return tb->ascii;
1299 }
1300
1301 /**
1302 * scols_table_is_noheadings:
1303 * @tb: table
1304 *
1305 * Returns: 1 if header output is disabled.
1306 */
1307 int scols_table_is_noheadings(const struct libscols_table *tb)
1308 {
1309 return tb->no_headings;
1310 }
1311
1312 /**
1313 * scols_table_is_header_repeat
1314 * @tb: table
1315 *
1316 * Returns: 1 if header repeat is enabled.
1317 *
1318 * Since: 2.31
1319 */
1320 int scols_table_is_header_repeat(const struct libscols_table *tb)
1321 {
1322 return tb->header_repeat;
1323 }
1324
1325 /**
1326 * scols_table_is_export:
1327 * @tb: table
1328 *
1329 * Returns: 1 if export output format is enabled.
1330 */
1331 int scols_table_is_export(const struct libscols_table *tb)
1332 {
1333 return tb->format == SCOLS_FMT_EXPORT;
1334 }
1335
1336 /**
1337 * scols_table_is_raw:
1338 * @tb: table
1339 *
1340 * Returns: 1 if raw output format is enabled.
1341 */
1342 int scols_table_is_raw(const struct libscols_table *tb)
1343 {
1344 return tb->format == SCOLS_FMT_RAW;
1345 }
1346
1347 /**
1348 * scols_table_is_json:
1349 * @tb: table
1350 *
1351 * Returns: 1 if JSON output format is enabled.
1352 *
1353 * Since: 2.27
1354 */
1355 int scols_table_is_json(const struct libscols_table *tb)
1356 {
1357 return tb->format == SCOLS_FMT_JSON;
1358 }
1359
1360 /**
1361 * scols_table_is_maxout
1362 * @tb: table
1363 *
1364 * Returns: 1 if output maximization is enabled or 0
1365 */
1366 int scols_table_is_maxout(const struct libscols_table *tb)
1367 {
1368 return tb->maxout;
1369 }
1370
1371 /**
1372 * scols_table_is_minout
1373 * @tb: table
1374 *
1375 * Returns: 1 if output minimization is enabled or 0
1376 */
1377 int scols_table_is_minout(const struct libscols_table *tb)
1378 {
1379 return tb->minout;
1380 }
1381
1382 /**
1383 * scols_table_is_tree:
1384 * @tb: table
1385 *
1386 * Returns: returns 1 tree-like output is expected.
1387 */
1388 int scols_table_is_tree(const struct libscols_table *tb)
1389 {
1390 return tb->ntreecols > 0;
1391 }
1392
1393 /**
1394 * scols_table_set_column_separator:
1395 * @tb: table
1396 * @sep: separator
1397 *
1398 * Sets the column separator of @tb to @sep.
1399 *
1400 * Returns: 0, a negative value in case of an error.
1401 */
1402 int scols_table_set_column_separator(struct libscols_table *tb, const char *sep)
1403 {
1404 return strdup_to_struct_member(tb, colsep, sep);
1405 }
1406
1407 /**
1408 * scols_table_set_line_separator:
1409 * @tb: table
1410 * @sep: separator
1411 *
1412 * Sets the line separator of @tb to @sep.
1413 *
1414 * Returns: 0, a negative value in case of an error.
1415 */
1416 int scols_table_set_line_separator(struct libscols_table *tb, const char *sep)
1417 {
1418 return strdup_to_struct_member(tb, linesep, sep);
1419 }
1420
1421 /**
1422 * scols_table_get_column_separator:
1423 * @tb: table
1424 *
1425 * Returns: @tb column separator, NULL in case of an error
1426 */
1427 const char *scols_table_get_column_separator(const struct libscols_table *tb)
1428 {
1429 return tb->colsep;
1430 }
1431
1432 /**
1433 * scols_table_get_line_separator:
1434 * @tb: table
1435 *
1436 * Returns: @tb line separator, NULL in case of an error
1437 */
1438 const char *scols_table_get_line_separator(const struct libscols_table *tb)
1439 {
1440 return tb->linesep;
1441 }
1442 /* for lines in the struct libscols_line->ln_lines list */
1443 static int cells_cmp_wrapper_lines(struct list_head *a, struct list_head *b, void *data)
1444 {
1445 struct libscols_column *cl = (struct libscols_column *) data;
1446 struct libscols_line *ra, *rb;
1447 struct libscols_cell *ca, *cb;
1448
1449 assert(a);
1450 assert(b);
1451 assert(cl);
1452
1453 ra = list_entry(a, struct libscols_line, ln_lines);
1454 rb = list_entry(b, struct libscols_line, ln_lines);
1455 ca = scols_line_get_cell(ra, cl->seqnum);
1456 cb = scols_line_get_cell(rb, cl->seqnum);
1457
1458 return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
1459 }
1460
1461 /* for lines in the struct libscols_line->ln_children list */
1462 static int cells_cmp_wrapper_children(struct list_head *a, struct list_head *b, void *data)
1463 {
1464 struct libscols_column *cl = (struct libscols_column *) data;
1465 struct libscols_line *ra, *rb;
1466 struct libscols_cell *ca, *cb;
1467
1468 assert(a);
1469 assert(b);
1470 assert(cl);
1471
1472 ra = list_entry(a, struct libscols_line, ln_children);
1473 rb = list_entry(b, struct libscols_line, ln_children);
1474 ca = scols_line_get_cell(ra, cl->seqnum);
1475 cb = scols_line_get_cell(rb, cl->seqnum);
1476
1477 return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
1478 }
1479
1480
1481 static int sort_line_children(struct libscols_line *ln, struct libscols_column *cl)
1482 {
1483 struct list_head *p;
1484
1485 if (!list_empty(&ln->ln_branch)) {
1486 list_for_each(p, &ln->ln_branch) {
1487 struct libscols_line *chld =
1488 list_entry(p, struct libscols_line, ln_children);
1489 sort_line_children(chld, cl);
1490 }
1491
1492 list_sort(&ln->ln_branch, cells_cmp_wrapper_children, cl);
1493 }
1494
1495 if (is_first_group_member(ln)) {
1496 list_for_each(p, &ln->group->gr_children) {
1497 struct libscols_line *chld =
1498 list_entry(p, struct libscols_line, ln_children);
1499 sort_line_children(chld, cl);
1500 }
1501
1502 list_sort(&ln->group->gr_children, cells_cmp_wrapper_children, cl);
1503 }
1504
1505 return 0;
1506 }
1507
1508 /**
1509 * scols_sort_table:
1510 * @tb: table
1511 * @cl: order by this column
1512 *
1513 * Orders the table by the column. See also scols_column_set_cmpfunc(). If the
1514 * tree output is enabled then children in the tree are recursively sorted too.
1515 *
1516 * Returns: 0, a negative value in case of an error.
1517 */
1518 int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl)
1519 {
1520 if (!tb || !cl || !cl->cmpfunc)
1521 return -EINVAL;
1522
1523 DBG(TAB, ul_debugobj(tb, "sorting table"));
1524 list_sort(&tb->tb_lines, cells_cmp_wrapper_lines, cl);
1525
1526 if (scols_table_is_tree(tb)) {
1527 struct libscols_line *ln;
1528 struct libscols_iter itr;
1529
1530 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
1531 while (scols_table_next_line(tb, &itr, &ln) == 0)
1532 sort_line_children(ln, cl);
1533 }
1534
1535 return 0;
1536 }
1537
1538 static struct libscols_line *move_line_and_children(struct libscols_line *ln, struct libscols_line *pre)
1539 {
1540 if (pre) {
1541 list_del_init(&ln->ln_lines); /* remove from old position */
1542 list_add(&ln->ln_lines, &pre->ln_lines); /* add to the new place (behind @pre) */
1543 }
1544 pre = ln;
1545
1546 if (!list_empty(&ln->ln_branch)) {
1547 struct list_head *p;
1548
1549 list_for_each(p, &ln->ln_branch) {
1550 struct libscols_line *chld =
1551 list_entry(p, struct libscols_line, ln_children);
1552 pre = move_line_and_children(chld, pre);
1553 }
1554 }
1555
1556 return pre;
1557 }
1558
1559 /**
1560 * scols_sort_table_by_tree:
1561 * @tb: table
1562 *
1563 * Reorders lines in the table by parent->child relation. Note that order of
1564 * the lines in the table is independent on the tree hierarchy.
1565 *
1566 * Since: 2.30
1567 *
1568 * Returns: 0, a negative value in case of an error.
1569 */
1570 int scols_sort_table_by_tree(struct libscols_table *tb)
1571 {
1572 struct libscols_line *ln;
1573 struct libscols_iter itr;
1574
1575 if (!tb)
1576 return -EINVAL;
1577
1578 DBG(TAB, ul_debugobj(tb, "sorting table by tree"));
1579
1580 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
1581 while (scols_table_next_line(tb, &itr, &ln) == 0) {
1582 if (ln->parent)
1583 continue;
1584
1585 move_line_and_children(ln, NULL);
1586 }
1587
1588 return 0;
1589 }
1590
1591
1592 /**
1593 * scols_table_set_termforce:
1594 * @tb: table
1595 * @force: SCOLS_TERMFORCE_{NEVER,ALWAYS,AUTO}
1596 *
1597 * Forces library to use stdout as terminal, non-terminal or use automatic
1598 * detection (default).
1599 *
1600 * Returns: 0, a negative value in case of an error.
1601 *
1602 * Since: 2.29
1603 */
1604 int scols_table_set_termforce(struct libscols_table *tb, int force)
1605 {
1606 if (!tb)
1607 return -EINVAL;
1608 tb->termforce = force;
1609 return 0;
1610 }
1611
1612 /**
1613 * scols_table_get_termforce:
1614 * @tb: table
1615 *
1616 * Returns: SCOLS_TERMFORCE_{NEVER,ALWAYS,AUTO} or a negative value in case of an error.
1617 *
1618 * Since: 2.29
1619 */
1620 int scols_table_get_termforce(const struct libscols_table *tb)
1621 {
1622 return tb->termforce;
1623 }
1624
1625 /**
1626 * scols_table_set_termwidth
1627 * @tb: table
1628 * @width: terminal width
1629 *
1630 * The library automatically detects terminal width or defaults to 80 chars if
1631 * detections is unsuccessful. This function override this behaviour.
1632 *
1633 * Returns: 0, a negative value in case of an error.
1634 *
1635 * Since: 2.29
1636 */
1637 int scols_table_set_termwidth(struct libscols_table *tb, size_t width)
1638 {
1639 DBG(TAB, ul_debugobj(tb, "set terminatl width: %zu", width));
1640 tb->termwidth = width;
1641 return 0;
1642 }
1643
1644 /**
1645 * scols_table_get_termwidth
1646 * @tb: table
1647 *
1648 * Returns: terminal width.
1649 */
1650 size_t scols_table_get_termwidth(const struct libscols_table *tb)
1651 {
1652 return tb->termwidth;
1653 }
1654
1655 /**
1656 * scols_table_set_termheight
1657 * @tb: table
1658 * @height: terminal height (number of lines)
1659 *
1660 * The library automatically detects terminal height or defaults to 24 lines if
1661 * detections is unsuccessful. This function override this behaviour.
1662 *
1663 * Returns: 0, a negative value in case of an error.
1664 *
1665 * Since: 2.31
1666 */
1667 int scols_table_set_termheight(struct libscols_table *tb, size_t height)
1668 {
1669 DBG(TAB, ul_debugobj(tb, "set terminatl height: %zu", height));
1670 tb->termheight = height;
1671 return 0;
1672 }
1673
1674 /**
1675 * scols_table_get_termheight
1676 * @tb: table
1677 *
1678 * Returns: terminal height (number of lines).
1679 *
1680 * Since: 2.31
1681 */
1682 size_t scols_table_get_termheight(const struct libscols_table *tb)
1683 {
1684 return tb->termheight;
1685 }