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 }