]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libsmartcols/src/table.c
2 * table.c - functions handling the data at the table level
4 * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
5 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
14 * @short_description: table data API
16 * Table data manipulation API.
28 #include "smartcolsP.h"
31 #define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */
32 #define UTF_VR "\342\224\234" /* U+251C, Vertical and right */
33 #define UTF_H "\342\224\200" /* U+2500, Horizontal */
34 #define UTF_UR "\342\224\224" /* U+2514, Up and right */
35 #endif /* !HAVE_WIDECHAR */
37 #define is_last_column(_tb, _cl) \
38 list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
44 * Returns: A newly allocated table.
46 struct libscols_table
*scols_new_table(void)
48 struct libscols_table
*tb
;
50 tb
= calloc(1, sizeof(struct libscols_table
));
57 INIT_LIST_HEAD(&tb
->tb_lines
);
58 INIT_LIST_HEAD(&tb
->tb_columns
);
60 DBG(TAB
, ul_debugobj(tb
, "alloc"));
66 * @tb: a pointer to a struct libscols_table instance
68 * Increases the refcount of @tb.
70 void scols_ref_table(struct libscols_table
*tb
)
78 * @tb: a pointer to a struct libscols_table instance
80 * Decreases the refcount of @tb.
82 void scols_unref_table(struct libscols_table
*tb
)
84 if (tb
&& (--tb
->refcount
<= 0)) {
85 DBG(TAB
, ul_debugobj(tb
, "dealloc"));
86 scols_table_remove_lines(tb
);
87 scols_table_remove_columns(tb
);
88 scols_unref_symbols(tb
->symbols
);
96 * scols_table_add_column:
97 * @tb: a pointer to a struct libscols_table instance
98 * @cl: a pointer to a struct libscols_column instance
100 * Adds @cl to @tb's column list.
102 * Returns: 0, a negative number in case of an error.
104 int scols_table_add_column(struct libscols_table
*tb
, struct libscols_column
*cl
)
109 if (!tb
|| !cl
|| !list_empty(&tb
->tb_lines
))
112 if (cl
->flags
& SCOLS_FL_TREE
)
115 DBG(TAB
, ul_debugobj(tb
, "add column %p", cl
));
116 list_add_tail(&cl
->cl_columns
, &tb
->tb_columns
);
117 cl
->seqnum
= tb
->ncols
++;
118 scols_ref_column(cl
);
122 * Currently it's possible to add/remove columns only if the table is
123 * empty (see list_empty(tb->tb_lines) above). It would be nice to
124 * enlarge/reduce lines cells[] always when we add/remove a new column.
130 * scols_table_remove_column:
131 * @tb: a pointer to a struct libscols_table instance
132 * @cl: a pointer to a struct libscols_column instance
134 * Removes @cl from @tb.
136 * Returns: 0, a negative number in case of an error.
138 int scols_table_remove_column(struct libscols_table
*tb
,
139 struct libscols_column
*cl
)
144 if (!tb
|| !cl
|| !list_empty(&tb
->tb_lines
))
147 if (cl
->flags
& SCOLS_FL_TREE
)
150 DBG(TAB
, ul_debugobj(tb
, "remove column %p", cl
));
151 list_del_init(&cl
->cl_columns
);
153 scols_unref_column(cl
);
158 * scols_table_remove_columns:
159 * @tb: a pointer to a struct libscols_table instance
161 * Removes all of @tb's columns.
163 * Returns: 0, a negative number in case of an error.
165 int scols_table_remove_columns(struct libscols_table
*tb
)
169 if (!tb
|| !list_empty(&tb
->tb_lines
))
172 DBG(TAB
, ul_debugobj(tb
, "remove all columns"));
173 while (!list_empty(&tb
->tb_columns
)) {
174 struct libscols_column
*cl
= list_entry(tb
->tb_columns
.next
,
175 struct libscols_column
, cl_columns
);
176 scols_table_remove_column(tb
, cl
);
183 * scols_table_new_column:
185 * @name: column header
186 * @whint: column width hint (absolute width: N > 1; relative width: N < 1)
187 * @flags: flags integer
189 * This is shortcut for
191 * cl = scols_new_column();
192 * scols_column_set_....(cl, ...);
193 * scols_table_add_column(tb, cl);
195 * The column width is possible to define by three ways:
197 * @whint = 0..1 : relative width, percent of terminal width
199 * @whint = 1..N : absolute width, empty colum will be truncated to
200 * the column header width
204 * The column is necessary to address by
205 * sequential number. The first defined column has the colnum = 0. For example:
207 * scols_table_new_column(tab, "FOO", 0.5, 0); // colnum = 0
208 * scols_table_new_column(tab, "BAR", 0.5, 0); // colnum = 1
211 * scols_line_get_cell(line, 0); // FOO column
212 * scols_line_get_cell(line, 1); // BAR column
214 * Returns: newly allocated column
216 struct libscols_column
*scols_table_new_column(struct libscols_table
*tb
,
221 struct libscols_column
*cl
;
222 struct libscols_cell
*hr
;
228 DBG(TAB
, ul_debugobj(tb
, "new column name=%s, whint=%g, flags=%d",
229 name
, whint
, flags
));
230 cl
= scols_new_column();
234 /* set column name */
235 hr
= scols_column_get_header(cl
);
238 if (scols_cell_set_data(hr
, name
))
241 scols_column_set_whint(cl
, whint
);
242 scols_column_set_flags(cl
, flags
);
244 if (scols_table_add_column(tb
, cl
)) /* this increments column ref-counter */
247 scols_unref_column(cl
);
250 scols_unref_column(cl
);
255 * scols_table_next_column:
256 * @tb: a pointer to a struct libscols_table instance
257 * @itr: a pointer to a struct libscols_iter instance
258 * @cl: a pointer to a pointer to a struct libscols_column instance
260 * Returns the next column of @tb via @cl.
262 * Returns: 0, a negative value in case of an error.
264 int scols_table_next_column(struct libscols_table
*tb
,
265 struct libscols_iter
*itr
,
266 struct libscols_column
**cl
)
270 if (!tb
|| !itr
|| !cl
)
275 SCOLS_ITER_INIT(itr
, &tb
->tb_columns
);
276 if (itr
->p
!= itr
->head
) {
277 SCOLS_ITER_ITERATE(itr
, *cl
, struct libscols_column
, cl_columns
);
286 * scols_table_get_ncols:
289 * Returns: the ncols table member, a negative number in case of an error.
291 int scols_table_get_ncols(struct libscols_table
*tb
)
294 return tb
? tb
->ncols
: -EINVAL
;
298 * scols_table_get_nlines:
301 * Returns: the nlines table member, a negative number in case of an error.
303 int scols_table_get_nlines(struct libscols_table
*tb
)
306 return tb
? tb
->nlines
: -EINVAL
;
310 * scols_table_set_stream:
312 * @stream: output stream
314 * Sets the output stream for table @tb.
316 * Returns: 0, a negative number in case of an error.
318 int scols_table_set_stream(struct libscols_table
*tb
, FILE *stream
)
324 DBG(TAB
, ul_debugobj(tb
, "setting alternative stream"));
330 * scols_table_get_stream:
333 * Gets the output stream for table @tb.
335 * Returns: stream pointer, NULL in case of an error or an unset stream.
337 FILE *scols_table_get_stream(struct libscols_table
*tb
)
340 return tb
? tb
->out
: NULL
;
344 * scols_table_reduce_termwidth:
348 * Reduce the output width to @reduce.
350 * Returns: 0, a negative value in case of an error.
352 int scols_table_reduce_termwidth(struct libscols_table
*tb
, size_t reduce
)
358 DBG(TAB
, ul_debugobj(tb
, "reduce terminal width: %zu", reduce
));
359 tb
->termreduce
= reduce
;
364 * scols_table_get_column:
366 * @n: number of column (0..N)
368 * Returns: pointer to column or NULL
370 struct libscols_column
*scols_table_get_column(struct libscols_table
*tb
,
373 struct libscols_iter itr
;
374 struct libscols_column
*cl
;
382 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
383 while (scols_table_next_column(tb
, &itr
, &cl
) == 0) {
391 * scols_table_add_line:
395 * Note that this function calls scols_line_alloc_cells() if number
396 * of the cells in the line is too small for @tb.
398 * Returns: 0, a negative value in case of an error.
400 int scols_table_add_line(struct libscols_table
*tb
, struct libscols_line
*ln
)
409 if (tb
->ncols
> ln
->ncells
) {
410 int rc
= scols_line_alloc_cells(ln
, tb
->ncols
);
415 DBG(TAB
, ul_debugobj(tb
, "add line %p", ln
));
416 list_add_tail(&ln
->ln_lines
, &tb
->tb_lines
);
417 ln
->seqnum
= tb
->nlines
++;
423 * scols_table_remove_line:
427 * Note that this function does not destroy the parent<->child relationship between lines.
428 * You have to call scols_line_remove_child()
430 * Returns: 0, a negative value in case of an error.
432 int scols_table_remove_line(struct libscols_table
*tb
,
433 struct libscols_line
*ln
)
441 DBG(TAB
, ul_debugobj(tb
, "remove line %p", ln
));
442 list_del_init(&ln
->ln_lines
);
444 scols_unref_line(ln
);
449 * scols_table_remove_lines:
452 * This empties the table and also destroys all the parent<->child relationships.
454 void scols_table_remove_lines(struct libscols_table
*tb
)
460 DBG(TAB
, ul_debugobj(tb
, "remove all lines"));
461 while (!list_empty(&tb
->tb_lines
)) {
462 struct libscols_line
*ln
= list_entry(tb
->tb_lines
.next
,
463 struct libscols_line
, ln_lines
);
465 scols_line_remove_child(ln
->parent
, ln
);
466 scols_table_remove_line(tb
, ln
);
471 * scols_table_next_line:
472 * @tb: a pointer to a struct libscols_table instance
473 * @itr: a pointer to a struct libscols_iter instance
474 * @ln: a pointer to a pointer to a struct libscols_line instance
476 * Finds the next line and returns a pointer to it via @ln.
478 * Returns: 0, a negative value in case of an error.
480 int scols_table_next_line(struct libscols_table
*tb
,
481 struct libscols_iter
*itr
,
482 struct libscols_line
**ln
)
486 if (!tb
|| !itr
|| !ln
)
491 SCOLS_ITER_INIT(itr
, &tb
->tb_lines
);
492 if (itr
->p
!= itr
->head
) {
493 SCOLS_ITER_ITERATE(itr
, *ln
, struct libscols_line
, ln_lines
);
501 * scols_table_new_line:
503 * @parent: parental line or NULL
505 * This is shortcut for
507 * ln = scols_new_line();
508 * scols_table_add_line(tb, ln);
509 * scols_line_add_child(parent, ln);
512 * Returns: newly allocate line
514 struct libscols_line
*scols_table_new_line(struct libscols_table
*tb
,
515 struct libscols_line
*parent
)
517 struct libscols_line
*ln
;
522 if (!tb
|| !tb
->ncols
)
525 ln
= scols_new_line();
529 if (scols_table_add_line(tb
, ln
))
532 scols_line_add_child(parent
, ln
);
534 scols_unref_line(ln
); /* ref-counter incremented by scols_table_add_line() */
537 scols_unref_line(ln
);
542 * scols_table_get_line:
544 * @n: column number (0..N)
546 * This is a shortcut for
548 * ln = scols_new_line();
549 * scols_line_set_....(cl, ...);
550 * scols_table_add_line(tb, ln);
552 * Returns: a newly allocate line
554 struct libscols_line
*scols_table_get_line(struct libscols_table
*tb
,
557 struct libscols_iter itr
;
558 struct libscols_line
*ln
;
566 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
567 while (scols_table_next_line(tb
, &itr
, &ln
) == 0) {
578 * Creates a new independent table copy, except struct libscols_symbols that
579 * are shared between the tables.
581 * Returns: a newly allocated copy of @tb
583 struct libscols_table
*scols_copy_table(struct libscols_table
*tb
)
585 struct libscols_table
*ret
;
586 struct libscols_line
*ln
;
587 struct libscols_column
*cl
;
588 struct libscols_iter itr
;
593 ret
= scols_new_table();
597 DBG(TAB
, ul_debugobj(tb
, "copy into %p", ret
));
600 scols_table_set_symbols(ret
, tb
->symbols
);
603 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
604 while (scols_table_next_column(tb
, &itr
, &cl
) == 0) {
605 cl
= scols_copy_column(cl
);
608 if (scols_table_add_column(ret
, cl
))
610 scols_unref_column(cl
);
614 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
615 while (scols_table_next_line(tb
, &itr
, &ln
) == 0) {
616 struct libscols_line
*newln
= scols_copy_line(ln
);
619 if (scols_table_add_line(ret
, newln
))
622 struct libscols_line
*p
=
623 scols_table_get_line(ret
, ln
->parent
->seqnum
);
625 scols_line_add_child(p
, newln
);
627 scols_unref_line(newln
);
631 if (scols_table_set_column_separator(ret
, tb
->colsep
) ||
632 scols_table_set_line_separator(ret
, tb
->linesep
))
637 scols_unref_table(ret
);
642 * scols_table_set_symbols:
644 * @sy: symbols or NULL
646 * Add a reference to @sy from the table. The symbols are used by library to
647 * draw tree output. If no symbols are specified then library checks the
648 * current environment to select ASCII or UTF8 symbols. This default behavior
649 * could be controlled by scols_table_enable_ascii().
651 * Returns: 0, a negative value in case of an error.
653 int scols_table_set_symbols(struct libscols_table
*tb
,
654 struct libscols_symbols
*sy
)
661 DBG(TAB
, ul_debugobj(tb
, "setting alternative symbols %p", sy
));
663 if (tb
->symbols
) /* unref old */
664 scols_unref_symbols(tb
->symbols
);
665 if (sy
) { /* ref user defined */
667 scols_ref_symbols(sy
);
668 } else { /* default symbols */
669 tb
->symbols
= scols_new_symbols();
672 #if defined(HAVE_WIDECHAR)
673 if (!scols_table_is_ascii(tb
) &&
674 !strcmp(nl_langinfo(CODESET
), "UTF-8")) {
675 scols_symbols_set_branch(tb
->symbols
, UTF_VR UTF_H
);
676 scols_symbols_set_vertical(tb
->symbols
, UTF_V
" ");
677 scols_symbols_set_right(tb
->symbols
, UTF_UR UTF_H
);
681 scols_symbols_set_branch(tb
->symbols
, "|-");
682 scols_symbols_set_vertical(tb
->symbols
, "| ");
683 scols_symbols_set_right(tb
->symbols
, "`-");
690 * scols_table_enable_colors:
694 * Enable/disable colors.
696 * Returns: 0 on success, negative number in case of an error.
698 int scols_table_enable_colors(struct libscols_table
*tb
, int enable
)
704 DBG(TAB
, ul_debugobj(tb
, "colors: %s", enable
? "ENABLE" : "DISABLE"));
705 tb
->colors_wanted
= enable
;
709 * scols_table_enable_raw:
713 * Enable/disable raw output format. The parsable output formats
714 * (export and raw) are mutually exclusive.
716 * Returns: 0 on success, negative number in case of an error.
718 int scols_table_enable_raw(struct libscols_table
*tb
, int enable
)
724 DBG(TAB
, ul_debugobj(tb
, "raw: %s", enable
? "ENABLE" : "DISABLE"));
726 tb
->format
= SCOLS_FMT_RAW
;
727 else if (tb
->format
== SCOLS_FMT_RAW
)
733 * scols_table_enable_export:
737 * Enable/disable export output format (COLUMNAME="value" ...).
738 * The parsable output formats (export and raw) are mutually exclusive.
740 * Returns: 0 on success, negative number in case of an error.
742 int scols_table_enable_export(struct libscols_table
*tb
, int enable
)
748 DBG(TAB
, ul_debugobj(tb
, "export: %s", enable
? "ENABLE" : "DISABLE"));
750 tb
->format
= SCOLS_FMT_EXPORT
;
751 else if (tb
->format
== SCOLS_FMT_EXPORT
)
757 * scols_table_enable_ascii:
761 * The ASCII-only output is relevant for tree-like outputs. The library
762 * checks if the current environment is UTF8 compatible by default. This
763 * function overrides this check and force the library to use ASCII chars
766 * If a custom libcols_symbols are specified (see scols_table_set_symbols()
767 * then ASCII flag setting is ignored.
769 * Returns: 0 on success, negative number in case of an error.
771 int scols_table_enable_ascii(struct libscols_table
*tb
, int enable
)
777 DBG(TAB
, ul_debugobj(tb
, "ascii: %s", enable
? "ENABLE" : "DISABLE"));
778 tb
->ascii
= enable
? 1 : 0;
783 * scols_table_enable_noheadings:
787 * Enable/disable header line.
789 * Returns: 0 on success, negative number in case of an error.
791 int scols_table_enable_noheadings(struct libscols_table
*tb
, int enable
)
796 DBG(TAB
, ul_debugobj(tb
, "noheading: %s", enable
? "ENABLE" : "DISABLE"));
797 tb
->no_headings
= enable
? 1 : 0;
802 * scols_table_enable_maxout:
806 * The extra space after last column is ignored by default. The output
807 * maximization use the extra space for all columns.
809 * Returns: 0 on success, negative number in case of an error.
811 int scols_table_enable_maxout(struct libscols_table
*tb
, int enable
)
816 DBG(TAB
, ul_debugobj(tb
, "maxout: %s", enable
? "ENABLE" : "DISABLE"));
817 tb
->maxout
= enable
? 1 : 0;
822 * scols_table_colors_wanted:
825 * Returns: 1 if colors are enabled.
827 int scols_table_colors_wanted(struct libscols_table
*tb
)
830 return tb
&& tb
->colors_wanted
;
834 * scols_table_is_empty:
837 * Returns: 1 if the table is empty.
839 int scols_table_is_empty(struct libscols_table
*tb
)
842 return !tb
|| !tb
->nlines
;
846 * scols_table_is_ascii:
849 * Returns: 1 if ASCII tree is enabled.
851 int scols_table_is_ascii(struct libscols_table
*tb
)
854 return tb
&& tb
->ascii
;
858 * scols_table_is_noheadings:
861 * Returns: 1 if header output is disabled.
863 int scols_table_is_noheadings(struct libscols_table
*tb
)
866 return tb
&& tb
->no_headings
;
870 * scols_table_is_export:
873 * Returns: 1 if export output format is enabled.
875 int scols_table_is_export(struct libscols_table
*tb
)
878 return tb
&& tb
->format
== SCOLS_FMT_EXPORT
;
882 * scols_table_is_raw:
885 * Returns: 1 if raw output format is enabled.
887 int scols_table_is_raw(struct libscols_table
*tb
)
890 return tb
&& tb
->format
== SCOLS_FMT_RAW
;
895 * scols_table_is_maxout
898 * Returns: 1 if output maximization is enabled, negative value in case of an error.
900 int scols_table_is_maxout(struct libscols_table
*tb
)
903 return tb
&& tb
->maxout
;
907 * scols_table_is_tree:
910 * Returns: returns 1 tree-like output is expected.
912 int scols_table_is_tree(struct libscols_table
*tb
)
915 return tb
&& tb
->ntreecols
> 0;
919 * scols_table_set_column_separator:
923 * Sets the column separator of @tb to @sep.
924 * Please note that @sep should always take up a single cell in the output.
926 * Returns: 0, a negative value in case of an error.
928 int scols_table_set_column_separator(struct libscols_table
*tb
, const char *sep
)
943 DBG(TAB
, ul_debugobj(tb
, "new columns separator: %s", sep
));
950 * scols_table_set_line_separator:
954 * Sets the line separator of @tb to @sep.
956 * Returns: 0, a negative value in case of an error.
958 int scols_table_set_line_separator(struct libscols_table
*tb
, const char *sep
)
973 DBG(TAB
, ul_debugobj(tb
, "new lines separator: %s", sep
));
980 * scols_table_get_column_separator:
983 * Returns: @tb column separator, NULL in case of an error
985 char *scols_table_get_column_separator(struct libscols_table
*tb
)
995 * scols_table_get_line_separator:
998 * Returns: @tb line separator, NULL in case of an error
1000 char *scols_table_get_line_separator(struct libscols_table
*tb
)
1010 static int cells_cmp_wrapper(struct list_head
*a
, struct list_head
*b
, void *data
)
1012 struct libscols_column
*cl
= (struct libscols_column
*) data
;
1013 struct libscols_line
*ra
, *rb
;
1014 struct libscols_cell
*ca
, *cb
;
1020 ra
= list_entry(a
, struct libscols_line
, ln_lines
);
1021 rb
= list_entry(b
, struct libscols_line
, ln_lines
);
1022 ca
= scols_line_get_cell(ra
, cl
->seqnum
);
1023 cb
= scols_line_get_cell(rb
, cl
->seqnum
);
1025 return cl
->cmpfunc(ca
, cb
, cl
->cmpfunc_data
);
1031 * @cl: order by this column
1033 * Orders the table by the column. See also scols_column_set_cmpfunc().
1035 * Returns: 0, a negative value in case of an error.
1037 int scols_sort_table(struct libscols_table
*tb
, struct libscols_column
*cl
)
1045 DBG(TAB
, ul_debugobj(tb
, "sorting table"));
1046 list_sort(&tb
->tb_lines
, cells_cmp_wrapper
, cl
);