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