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