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