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