2 * table.c - functions handling the data at the table level
4 * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
5 * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
12 * SECTION: table_print
14 * @short_description: output functions
26 #include "carefulputc.h"
27 #include "smartcolsP.h"
29 /* Fallback for symbols
31 * Note that by default library define all the symbols, but in case user does
32 * not define all symbols or if we extended the symbols struct then we need
33 * fallback to be more robust and backwardly compatible.
35 #define titlepadding_symbol(tb) ((tb)->symbols->title_padding ? (tb)->symbols->title_padding : " ")
36 #define branch_symbol(tb) ((tb)->symbols->tree_branch ? (tb)->symbols->tree_branch : "|-")
37 #define vertical_symbol(tb) ((tb)->symbols->tree_vert ? (tb)->symbols->tree_vert : "| ")
38 #define right_symbol(tb) ((tb)->symbols->tree_right ? (tb)->symbols->tree_right : "`-")
40 #define grp_vertical_symbol(tb) ((tb)->symbols->group_vert ? (tb)->symbols->group_vert : "|")
41 #define grp_horizontal_symbol(tb) ((tb)->symbols->group_horz ? (tb)->symbols->group_horz : "-")
42 #define grp_m_first_symbol(tb) ((tb)->symbols->group_first_member ? (tb)->symbols->group_first_member : ",->")
43 #define grp_m_last_symbol(tb) ((tb)->symbols->group_last_member ? (tb)->symbols->group_last_member : "\\->")
44 #define grp_m_middle_symbol(tb) ((tb)->symbols->group_middle_member ? (tb)->symbols->group_middle_member : "|->")
45 #define grp_c_middle_symbol(tb) ((tb)->symbols->group_middle_child ? (tb)->symbols->group_middle_child : "|-")
46 #define grp_c_last_symbol(tb) ((tb)->symbols->group_last_child ? (tb)->symbols->group_last_child : "`-")
48 #define cellpadding_symbol(tb) ((tb)->padding_debug ? "." : \
49 ((tb)->symbols->cell_padding ? (tb)->symbols->cell_padding: " "))
51 #define want_repeat_header(tb) (!(tb)->header_repeat || (tb)->header_next <= (tb)->termlines_used)
54 /* returns pointer to the end of used data */
55 static int tree_ascii_art_to_buffer(struct libscols_table
*tb
,
56 struct libscols_line
*ln
,
57 struct libscols_buffer
*buf
)
68 rc
= tree_ascii_art_to_buffer(tb
, ln
->parent
, buf
);
72 if (is_last_child(ln
))
75 art
= vertical_symbol(tb
);
77 return buffer_append_data(buf
, art
);
80 static int grpset_is_empty( struct libscols_table
*tb
,
86 for (i
= idx
; i
< tb
->grpset_size
; i
++) {
87 if (tb
->grpset
[i
] == NULL
) {
96 static int groups_ascii_art_to_buffer( struct libscols_table
*tb
,
97 struct libscols_line
*ln
,
98 struct libscols_buffer
*buf
)
102 const char *filler
= cellpadding_symbol(tb
);
104 if (!has_groups(tb
) || !tb
->grpset
)
107 DBG(LINE
, ul_debugobj(ln
, "printing groups chart"));
109 rc
= scols_groups_update_grpset(tb
, ln
);
113 for (i
= 0; i
< tb
->grpset_size
; i
+=3) {
114 struct libscols_group
*gr
= tb
->grpset
[i
];
117 buffer_append_ntimes(buf
, 3, cellpadding_symbol(tb
));
122 case SCOLS_GSTATE_FIRST_MEMBER
:
123 buffer_append_data(buf
, grp_m_first_symbol(tb
));
125 case SCOLS_GSTATE_MIDDLE_MEMBER
:
126 buffer_append_data(buf
, grp_m_middle_symbol(tb
));
128 case SCOLS_GSTATE_LAST_MEMBER
:
129 buffer_append_data(buf
, grp_m_last_symbol(tb
));
131 case SCOLS_GSTATE_CONT_MEMBERS
:
132 buffer_append_data(buf
, grp_vertical_symbol(tb
));
133 buffer_append_ntimes(buf
, 2, filler
);
135 case SCOLS_GSTATE_MIDDLE_CHILD
:
136 buffer_append_data(buf
, filler
);
137 buffer_append_data(buf
, grp_c_middle_symbol(tb
));
138 if (grpset_is_empty(tb
, i
+ 3, &rest
)) {
139 buffer_append_ntimes(buf
, rest
+1, grp_horizontal_symbol(tb
));
142 filler
= grp_horizontal_symbol(tb
);
144 case SCOLS_GSTATE_LAST_CHILD
:
145 buffer_append_data(buf
, cellpadding_symbol(tb
));
146 buffer_append_data(buf
, grp_c_last_symbol(tb
));
147 if (grpset_is_empty(tb
, i
+ 3, &rest
)) {
148 buffer_append_ntimes(buf
, rest
+1, grp_horizontal_symbol(tb
));
151 filler
= grp_horizontal_symbol(tb
);
153 case SCOLS_GSTATE_CONT_CHILDREN
:
154 buffer_append_data(buf
, filler
);
155 buffer_append_data(buf
, grp_vertical_symbol(tb
));
156 buffer_append_data(buf
, filler
);
165 buffer_append_data(buf
, filler
);
169 static int has_pending_data(struct libscols_table
*tb
)
171 struct libscols_column
*cl
;
172 struct libscols_iter itr
;
174 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
175 while (scols_table_next_column(tb
, &itr
, &cl
) == 0) {
176 if (scols_column_is_hidden(cl
))
178 if (cl
->pending_data
)
184 /* print padding or ASCII-art instead of data of @cl */
185 static void print_empty_cell(struct libscols_table
*tb
,
186 struct libscols_column
*cl
,
187 struct libscols_line
*ln
, /* optional */
190 size_t len_pad
= 0; /* in screen cells as opposed to bytes */
192 /* generate tree ASCII-art rather than padding */
193 if (ln
&& scols_column_is_tree(cl
)) {
195 /* only print symbols->vert if followed by child */
196 if (!list_empty(&ln
->ln_branch
)) {
197 fputs(vertical_symbol(tb
), tb
->out
);
198 len_pad
= mbs_safe_width(vertical_symbol(tb
));
201 /* use the same draw function as though we were intending to draw an L-shape */
202 struct libscols_buffer
*art
= new_buffer(bufsz
);
206 /* whatever the rc, len_pad will be sensible */
207 tree_ascii_art_to_buffer(tb
, ln
, art
);
208 if (!list_empty(&ln
->ln_branch
) && has_pending_data(tb
))
209 buffer_append_data(art
, vertical_symbol(tb
));
210 data
= buffer_get_safe_data(tb
, art
, &len_pad
, NULL
);
212 fputs(data
, tb
->out
);
218 if (is_last_column(cl
))
221 /* fill rest of cell with space */
222 for(; len_pad
< cl
->width
; ++len_pad
)
223 fputs(cellpadding_symbol(tb
), tb
->out
);
225 fputs(colsep(tb
), tb
->out
);
229 static const char *get_cell_color(struct libscols_table
*tb
,
230 struct libscols_column
*cl
,
231 struct libscols_line
*ln
, /* optional */
232 struct libscols_cell
*ce
) /* optional */
234 const char *color
= NULL
;
236 if (tb
&& tb
->colors_wanted
) {
247 /* Fill the start of a line with padding (or with tree ascii-art).
249 * This is necessary after a long non-truncated column, as this requires the
250 * next column to be printed on the next line. For example (see 'DDD'):
252 * aaa bbb ccc ddd eee
258 static void print_newline_padding(struct libscols_table
*tb
,
259 struct libscols_column
*cl
,
260 struct libscols_line
*ln
, /* optional */
268 fputs(linesep(tb
), tb
->out
); /* line break */
269 tb
->termlines_used
++;
271 /* fill cells after line break */
272 for (i
= 0; i
<= (size_t) cl
->seqnum
; i
++)
273 print_empty_cell(tb
, scols_table_get_column(tb
, i
), ln
, bufsz
);
279 * The first line in the multi-line cells (columns with SCOLS_FL_WRAP flag) is
280 * printed as usually and output is truncated to match column width.
282 * The rest of the long text is printed on next extra line(s). The extra lines
283 * don't exist in the table (not represented by libscols_line). The data for
284 * the extra lines are stored in libscols_column->pending_data_buf and the
285 * function print_line() adds extra lines until the buffer is not empty in all
289 /* set data that will be printed by extra lines */
290 static int set_pending_data(struct libscols_column
*cl
, const char *data
, size_t sz
)
295 DBG(COL
, ul_debugobj(cl
, "setting pending data"));
302 free(cl
->pending_data_buf
);
303 cl
->pending_data_buf
= p
;
304 cl
->pending_data_sz
= sz
;
305 cl
->pending_data
= cl
->pending_data_buf
;
309 /* the next extra line has been printed, move pending data cursor */
310 static int step_pending_data(struct libscols_column
*cl
, size_t bytes
)
312 DBG(COL
, ul_debugobj(cl
, "step pending data %zu -= %zu", cl
->pending_data_sz
, bytes
));
314 if (bytes
>= cl
->pending_data_sz
)
315 return set_pending_data(cl
, NULL
, 0);
317 cl
->pending_data
+= bytes
;
318 cl
->pending_data_sz
-= bytes
;
322 /* print next pending data for the column @cl */
323 static int print_pending_data(
324 struct libscols_table
*tb
,
325 struct libscols_column
*cl
,
326 struct libscols_line
*ln
, /* optional */
327 struct libscols_cell
*ce
)
329 const char *color
= get_cell_color(tb
, cl
, ln
, ce
);
330 size_t width
= cl
->width
, bytes
;
331 size_t len
= width
, i
;
333 char *nextchunk
= NULL
;
335 if (!cl
->pending_data
)
340 DBG(COL
, ul_debugobj(cl
, "printing pending data"));
342 data
= strdup(cl
->pending_data
);
346 if (scols_column_is_customwrap(cl
)
347 && (nextchunk
= cl
->wrap_nextchunk(cl
, data
, cl
->wrapfunc_data
))) {
348 bytes
= nextchunk
- data
;
350 len
= mbs_safe_nwidth(data
, bytes
, NULL
);
352 bytes
= mbs_truncate(data
, &len
);
354 if (bytes
== (size_t) -1)
358 step_pending_data(cl
, bytes
);
361 fputs(color
, tb
->out
);
362 fputs(data
, tb
->out
);
364 fputs(UL_COLOR_RESET
, tb
->out
);
367 if (is_last_column(cl
))
370 for (i
= len
; i
< width
; i
++)
371 fputs(cellpadding_symbol(tb
), tb
->out
); /* padding */
373 fputs(colsep(tb
), tb
->out
); /* columns separator */
380 static int print_data(struct libscols_table
*tb
,
381 struct libscols_column
*cl
,
382 struct libscols_line
*ln
, /* optional */
383 struct libscols_cell
*ce
, /* optional */
384 struct libscols_buffer
*buf
)
386 size_t len
= 0, i
, width
, bytes
;
387 const char *color
= NULL
;
388 char *data
, *nextchunk
;
394 data
= buffer_get_data(buf
);
398 is_last
= is_last_column(cl
);
400 switch (tb
->format
) {
402 fputs_nonblank(data
, tb
->out
);
404 fputs(colsep(tb
), tb
->out
);
407 case SCOLS_FMT_EXPORT
:
408 fprintf(tb
->out
, "%s=", scols_cell_get_data(&cl
->header
));
409 fputs_quoted(data
, tb
->out
);
411 fputs(colsep(tb
), tb
->out
);
415 fputs_quoted_json_lower(scols_cell_get_data(&cl
->header
), tb
->out
);
417 switch (cl
->json_type
) {
418 case SCOLS_JSON_STRING
:
420 fputs("null", tb
->out
);
422 fputs_quoted_json(data
, tb
->out
);
424 case SCOLS_JSON_NUMBER
:
426 fputs("null", tb
->out
);
428 fputs(data
, tb
->out
);
430 case SCOLS_JSON_BOOLEAN
:
431 fputs(!*data
? "false" :
432 *data
== '0' ? "false" :
433 *data
== 'N' || *data
== 'n' ? "false" : "true",
438 fputs(", ", tb
->out
);
441 case SCOLS_FMT_HUMAN
:
442 break; /* continue below */
445 color
= get_cell_color(tb
, cl
, ln
, ce
);
447 /* Encode. Note that 'len' and 'width' are number of cells, not bytes.
449 data
= buffer_get_safe_data(tb
, buf
, &len
, scols_column_get_safechars(cl
));
452 bytes
= strlen(data
);
455 /* custom multi-line cell based */
456 if (*data
&& scols_column_is_customwrap(cl
)
457 && (nextchunk
= cl
->wrap_nextchunk(cl
, data
, cl
->wrapfunc_data
))) {
458 set_pending_data(cl
, nextchunk
, bytes
- (nextchunk
- data
));
459 bytes
= nextchunk
- data
;
460 len
= mbs_safe_nwidth(data
, bytes
, NULL
);
465 && !scols_table_is_maxout(tb
)
466 && !scols_column_is_right(cl
))
470 if (len
> width
&& scols_column_is_trunc(cl
)) {
472 bytes
= mbs_truncate(data
, &len
); /* updates 'len' */
475 /* standard multi-line cell */
476 if (len
> width
&& scols_column_is_wrap(cl
)
477 && !scols_column_is_customwrap(cl
)) {
478 set_pending_data(cl
, data
, bytes
);
481 bytes
= mbs_truncate(data
, &len
);
482 if (bytes
!= (size_t) -1 && bytes
> 0)
483 step_pending_data(cl
, bytes
);
486 if (bytes
== (size_t) -1) {
492 if (scols_column_is_right(cl
)) {
494 fputs(color
, tb
->out
);
495 for (i
= len
; i
< width
; i
++)
496 fputs(cellpadding_symbol(tb
), tb
->out
);
497 fputs(data
, tb
->out
);
499 fputs(UL_COLOR_RESET
, tb
->out
);
504 size_t art
= buffer_get_safe_art_size(buf
);
506 /* we don't want to colorize tree ascii art */
507 if (scols_column_is_tree(cl
) && art
&& art
< bytes
) {
508 fwrite(p
, 1, art
, tb
->out
);
512 fputs(color
, tb
->out
);
514 fputs(UL_COLOR_RESET
, tb
->out
);
516 fputs(data
, tb
->out
);
518 for (i
= len
; i
< width
; i
++)
519 fputs(cellpadding_symbol(tb
), tb
->out
); /* padding */
524 if (len
> width
&& !scols_column_is_trunc(cl
))
525 print_newline_padding(tb
, cl
, ln
, buffer_get_size(buf
)); /* next column starts on next line */
527 fputs(colsep(tb
), tb
->out
); /* columns separator */
532 int __cell_to_buffer(struct libscols_table
*tb
,
533 struct libscols_line
*ln
,
534 struct libscols_column
*cl
,
535 struct libscols_buffer
*buf
)
538 struct libscols_cell
*ce
;
545 assert(cl
->seqnum
<= tb
->ncols
);
547 buffer_reset_data(buf
);
549 ce
= scols_line_get_cell(ln
, cl
->seqnum
);
550 data
= ce
? scols_cell_get_data(ce
) : NULL
;
554 if (!scols_column_is_tree(cl
))
555 return buffer_set_data(buf
, data
);
560 if (!scols_table_is_json(tb
) && cl
->is_groups
)
561 rc
= groups_ascii_art_to_buffer(tb
, ln
, buf
);
566 if (!rc
&& ln
->parent
&& !scols_table_is_json(tb
)) {
567 rc
= tree_ascii_art_to_buffer(tb
, ln
->parent
, buf
);
569 if (!rc
&& is_last_child(ln
))
570 rc
= buffer_append_data(buf
, right_symbol(tb
));
572 rc
= buffer_append_data(buf
, branch_symbol(tb
));
575 if (!rc
&& (ln
->parent
|| cl
->is_groups
) && !scols_table_is_json(tb
))
576 buffer_set_art_index(buf
);
579 rc
= buffer_append_data(buf
, data
);
584 * Prints data. Data can be printed in more formats (raw, NAME=xxx pairs), and
585 * control and non-printable characters can be encoded in the \x?? encoding.
587 static int print_line(struct libscols_table
*tb
,
588 struct libscols_line
*ln
,
589 struct libscols_buffer
*buf
)
591 int rc
= 0, pending
= 0;
592 struct libscols_column
*cl
;
593 struct libscols_iter itr
;
598 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
599 while (rc
== 0 && scols_table_next_column(tb
, &itr
, &cl
) == 0) {
600 if (scols_column_is_hidden(cl
))
602 rc
= __cell_to_buffer(tb
, ln
, cl
, buf
);
604 rc
= print_data(tb
, cl
, ln
,
605 scols_line_get_cell(ln
, cl
->seqnum
),
607 if (rc
== 0 && cl
->pending_data
)
611 /* extra lines of the multi-line cells */
612 while (rc
== 0 && pending
) {
614 fputs(linesep(tb
), tb
->out
);
615 tb
->termlines_used
++;
616 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
617 while (rc
== 0 && scols_table_next_column(tb
, &itr
, &cl
) == 0) {
618 if (scols_column_is_hidden(cl
))
620 if (cl
->pending_data
) {
621 rc
= print_pending_data(tb
, cl
, ln
, scols_line_get_cell(ln
, cl
->seqnum
));
622 if (rc
== 0 && cl
->pending_data
)
625 print_empty_cell(tb
, cl
, ln
, buffer_get_size(buf
));
632 int __scols_print_title(struct libscols_table
*tb
)
636 size_t width
, len
= 0, bufsz
, titlesz
;
637 char *title
= NULL
, *buf
= NULL
;
644 DBG(TAB
, ul_debugobj(tb
, "printing title"));
648 len
= bufsz
= strlen(tb
->title
.data
) + 1;
649 buf
= strdup(tb
->title
.data
);
655 bufsz
= mbs_safe_encode_size(strlen(tb
->title
.data
)) + 1;
657 DBG(TAB
, ul_debugobj(tb
, "title is empty string -- ignore"));
666 if (!mbs_safe_encode_to_buffer(tb
->title
.data
, &len
, buf
, NULL
) ||
667 !len
|| len
== (size_t) -1) {
673 /* truncate and align */
674 width
= tb
->is_term
? tb
->termwidth
: 80;
675 titlesz
= width
+ bufsz
;
677 title
= malloc(titlesz
);
683 switch (scols_cell_get_alignment(&tb
->title
)) {
684 case SCOLS_CELL_FL_RIGHT
:
685 align
= MBS_ALIGN_RIGHT
;
687 case SCOLS_CELL_FL_CENTER
:
688 align
= MBS_ALIGN_CENTER
;
690 case SCOLS_CELL_FL_LEFT
:
692 align
= MBS_ALIGN_LEFT
;
694 * Don't print extra blank chars after the title if on left
695 * (that's same as we use for the last column in the table).
698 && !scols_table_is_maxout(tb
)
699 && isblank(*titlepadding_symbol(tb
)))
705 /* copy from buf to title and align to width with title_padding */
706 rc
= mbsalign_with_padding(buf
, title
, titlesz
,
708 0, (int) *titlepadding_symbol(tb
));
715 if (tb
->colors_wanted
&& tb
->title
.color
)
718 fputs(tb
->title
.color
, tb
->out
);
720 fputs(title
, tb
->out
);
723 fputs(UL_COLOR_RESET
, tb
->out
);
725 fputc('\n', tb
->out
);
730 DBG(TAB
, ul_debugobj(tb
, "printing title done [rc=%d]", rc
));
734 int __scols_print_header(struct libscols_table
*tb
, struct libscols_buffer
*buf
)
737 struct libscols_column
*cl
;
738 struct libscols_iter itr
;
742 if ((tb
->header_printed
== 1 && tb
->header_repeat
== 0) ||
743 scols_table_is_noheadings(tb
) ||
744 scols_table_is_export(tb
) ||
745 scols_table_is_json(tb
) ||
746 list_empty(&tb
->tb_lines
))
749 DBG(TAB
, ul_debugobj(tb
, "printing header"));
751 /* set the width according to the size of the data */
752 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
753 while (rc
== 0 && scols_table_next_column(tb
, &itr
, &cl
) == 0) {
754 if (scols_column_is_hidden(cl
))
757 buffer_reset_data(buf
);
760 && scols_table_is_tree(tb
) && scols_column_is_tree(cl
)) {
762 for (i
= 0; i
< tb
->grpset_size
+ 1; i
++) {
763 rc
= buffer_append_data(buf
, " ");
769 rc
= buffer_append_data(buf
, scols_cell_get_data(&cl
->header
));
771 rc
= print_data(tb
, cl
, NULL
, &cl
->header
, buf
);
775 fputs(linesep(tb
), tb
->out
);
776 tb
->termlines_used
++;
779 tb
->header_printed
= 1;
780 tb
->header_next
= tb
->termlines_used
+ tb
->termheight
;
781 if (tb
->header_repeat
)
782 DBG(TAB
, ul_debugobj(tb
, "\tnext header: %zu [current=%zu, rc=%d]",
783 tb
->header_next
, tb
->termlines_used
, rc
));
788 int __scols_print_range(struct libscols_table
*tb
,
789 struct libscols_buffer
*buf
,
790 struct libscols_iter
*itr
,
791 struct libscols_line
*end
)
794 struct libscols_line
*ln
;
797 DBG(TAB
, ul_debugobj(tb
, "printing range"));
799 while (rc
== 0 && scols_table_next_line(tb
, itr
, &ln
) == 0) {
801 int last
= scols_iter_is_last(itr
);
804 rc
= print_line(tb
, ln
, buf
);
805 fput_line_close(tb
, last
, last
);
807 if (end
&& ln
== end
)
810 if (!last
&& want_repeat_header(tb
))
811 __scols_print_header(tb
, buf
);
818 int __scols_print_table(struct libscols_table
*tb
, struct libscols_buffer
*buf
)
820 struct libscols_iter itr
;
822 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
823 return __scols_print_range(tb
, buf
, &itr
, NULL
);
827 static int print_tree_line(struct libscols_table
*tb
,
828 struct libscols_line
*ln
,
829 struct libscols_buffer
*buf
,
833 int rc
, children
= 0, gr_children
= 0;
835 DBG(LINE
, ul_debugobj(ln
, "printing line"));
839 rc
= print_line(tb
, ln
, buf
);
843 children
= has_children(ln
);
844 gr_children
= is_last_group_member(ln
) && has_group_children(ln
);
846 if (children
|| gr_children
)
847 fput_children_open(tb
);
853 list_for_each(p
, &ln
->ln_branch
) {
854 struct libscols_line
*chld
=
855 list_entry(p
, struct libscols_line
, ln_children
);
856 int last_child
= !gr_children
&& p
->next
== &ln
->ln_branch
;
858 rc
= print_tree_line(tb
, chld
, buf
, last_child
, last_in_table
&& last_child
);
864 /* print group's children */
868 list_for_each(p
, &ln
->group
->gr_children
) {
869 struct libscols_line
*chld
=
870 list_entry(p
, struct libscols_line
, ln_children
);
871 int last_child
= p
->next
== &ln
->group
->gr_children
;
873 rc
= print_tree_line(tb
, chld
, buf
, last_child
, last_in_table
&& last_child
);
879 if (children
|| gr_children
)
880 fput_children_close(tb
);
882 if ((!children
&& !gr_children
) || scols_table_is_json(tb
))
883 fput_line_close(tb
, last
, last_in_table
);
888 int __scols_print_tree(struct libscols_table
*tb
, struct libscols_buffer
*buf
)
891 struct libscols_line
*ln
, *last
= NULL
;
892 struct libscols_iter itr
;
896 DBG(TAB
, ul_debugobj(tb
, "----printing-tree-----"));
898 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
900 while (scols_table_next_line(tb
, &itr
, &ln
) == 0) {
901 if (!last
|| !ln
->parent
)
905 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
906 while (rc
== 0 && scols_table_next_line(tb
, &itr
, &ln
) == 0) {
907 if (ln
->parent
|| ln
->parent_group
)
909 rc
= print_tree_line(tb
, ln
, buf
, ln
== last
, ln
== last
);
915 static size_t strlen_line(struct libscols_line
*ln
)
921 for (i
= 0; i
< ln
->ncells
; i
++) {
922 struct libscols_cell
*ce
= scols_line_get_cell(ln
, i
);
923 const char *data
= ce
? scols_cell_get_data(ce
) : NULL
;
925 sz
+= data
? strlen(data
) : 0;
931 void __scols_cleanup_printing(struct libscols_table
*tb
, struct libscols_buffer
*buf
)
938 if (tb
->priv_symbols
) {
939 scols_table_set_symbols(tb
, NULL
);
940 tb
->priv_symbols
= 0;
944 int __scols_initialize_printing(struct libscols_table
*tb
, struct libscols_buffer
**buf
)
946 size_t bufsz
, extra_bufsz
= 0;
947 struct libscols_line
*ln
;
948 struct libscols_iter itr
;
951 DBG(TAB
, ul_debugobj(tb
, "initialize printing"));
955 rc
= scols_table_set_default_symbols(tb
);
958 tb
->priv_symbols
= 1;
960 tb
->priv_symbols
= 0;
962 if (tb
->format
== SCOLS_FMT_HUMAN
)
963 tb
->is_term
= tb
->termforce
== SCOLS_TERMFORCE_NEVER
? 0 :
964 tb
->termforce
== SCOLS_TERMFORCE_ALWAYS
? 1 :
965 isatty(STDOUT_FILENO
);
968 size_t width
= (size_t) scols_table_get_termwidth(tb
);
970 if (tb
->termreduce
> 0 && tb
->termreduce
< width
) {
971 width
-= tb
->termreduce
;
972 scols_table_set_termwidth(tb
, width
);
978 if (!tb
->is_term
|| tb
->format
!= SCOLS_FMT_HUMAN
|| scols_table_is_tree(tb
))
979 tb
->header_repeat
= 0;
982 * Estimate extra space necessary for tree, JSON or another output
985 if (scols_table_is_tree(tb
))
986 extra_bufsz
+= tb
->nlines
* strlen(vertical_symbol(tb
));
988 switch (tb
->format
) {
990 extra_bufsz
+= tb
->ncols
; /* separator between columns */
993 if (tb
->format
== SCOLS_FMT_JSON
)
994 extra_bufsz
+= tb
->nlines
* 3; /* indentation */
996 case SCOLS_FMT_EXPORT
:
998 struct libscols_column
*cl
;
1000 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
1002 while (scols_table_next_column(tb
, &itr
, &cl
) == 0) {
1003 if (scols_column_is_hidden(cl
))
1005 extra_bufsz
+= strlen(scols_cell_get_data(&cl
->header
)); /* data */
1006 extra_bufsz
+= 2; /* separators */
1010 case SCOLS_FMT_HUMAN
:
1015 * Enlarge buffer if necessary, the buffer should be large enough to
1016 * store line data and tree ascii art (or another decoration).
1018 scols_reset_iter(&itr
, SCOLS_ITER_FORWARD
);
1019 while (scols_table_next_line(tb
, &itr
, &ln
) == 0) {
1022 sz
= strlen_line(ln
) + extra_bufsz
;
1027 *buf
= new_buffer(bufsz
+ 1); /* data + space for \0 */
1034 * Make sure groups members are in the same orders as the tree
1036 if (has_groups(tb
) && scols_table_is_tree(tb
))
1037 scols_groups_fix_members_order(tb
);
1039 if (tb
->format
== SCOLS_FMT_HUMAN
) {
1040 rc
= __scols_calculate(tb
, *buf
);
1047 __scols_cleanup_printing(tb
, *buf
);