]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libsmartcols/src/table.c
libsmartcols: add debug messages
[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>
3e542c76
KZ
6 *
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
9 */
1d90bcb1
OO
10
11/**
e2310281 12 * SECTION: table
1d90bcb1 13 * @title: Table
e2310281 14 * @short_description: table data API
1d90bcb1 15 *
e2310281 16 * Table data manipulation API.
1d90bcb1
OO
17 */
18
ce44112b 19
3e542c76
KZ
20#include <stdlib.h>
21#include <unistd.h>
22#include <string.h>
23#include <termios.h>
24#include <ctype.h>
25
26#include "nls.h"
27#include "widechar.h"
28#include "smartcolsP.h"
29
30#ifdef HAVE_WIDECHAR
31#define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */
32#define UTF_VR "\342\224\234" /* U+251C, Vertical and right */
33#define UTF_H "\342\224\200" /* U+2500, Horizontal */
34#define UTF_UR "\342\224\224" /* U+2514, Up and right */
35#endif /* !HAVE_WIDECHAR */
36
37#define is_last_column(_tb, _cl) \
38 list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
39
40
1d90bcb1
OO
41/**
42 * scols_new_table:
3e542c76 43 *
1d90bcb1 44 * Returns: A newly allocated table.
3e542c76 45 */
0925a9dd 46struct libscols_table *scols_new_table(void)
3e542c76
KZ
47{
48 struct libscols_table *tb;
49
50 tb = calloc(1, sizeof(struct libscols_table));
51 if (!tb)
52 return NULL;
53
3e542c76 54 tb->refcount = 1;
571441e2 55 tb->out = stdout;
3e542c76
KZ
56
57 INIT_LIST_HEAD(&tb->tb_lines);
58 INIT_LIST_HEAD(&tb->tb_columns);
59
710ed55d 60 DBG(TAB, ul_debugobj(tb, "alloc"));
1424fe8c 61 return tb;
3e542c76
KZ
62}
63
1d90bcb1
OO
64/**
65 * scols_ref_table:
66 * @tb: a pointer to a struct libscols_table instance
67 *
68 * Increases the refcount of @tb.
69 */
3e542c76
KZ
70void scols_ref_table(struct libscols_table *tb)
71{
72 if (tb)
73 tb->refcount++;
74}
75
1d90bcb1
OO
76/**
77 * scols_unref_table:
78 * @tb: a pointer to a struct libscols_table instance
79 *
80 * Decreases the refcount of @tb.
81 */
3e542c76
KZ
82void scols_unref_table(struct libscols_table *tb)
83{
84 if (tb && (--tb->refcount <= 0)) {
710ed55d 85 DBG(TAB, ul_debugobj(tb, "dealloc"));
3e542c76
KZ
86 scols_table_remove_lines(tb);
87 scols_table_remove_columns(tb);
88 scols_unref_symbols(tb->symbols);
d1b4d14f
OO
89 free(tb->linesep);
90 free(tb->colsep);
3e542c76
KZ
91 free(tb);
92 }
93}
94
1d90bcb1
OO
95/**
96 * scols_table_add_column:
97 * @tb: a pointer to a struct libscols_table instance
98 * @cl: a pointer to a struct libscols_column instance
1d90bcb1 99 *
4418714f 100 * Adds @cl to @tb's column list.
1d90bcb1
OO
101 *
102 * Returns: 0, a negative number in case of an error.
103 */
0925a9dd 104int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl)
3e542c76
KZ
105{
106 assert(tb);
107 assert(cl);
108
109 if (!tb || !cl || !list_empty(&tb->tb_lines))
110 return -EINVAL;
111
0925a9dd
KZ
112 if (cl->flags & SCOLS_FL_TREE)
113 tb->ntreecols++;
b72b824d 114
710ed55d 115 DBG(TAB, ul_debugobj(tb, "add column %p", cl));
3e542c76
KZ
116 list_add_tail(&cl->cl_columns, &tb->tb_columns);
117 cl->seqnum = tb->ncols++;
118 scols_ref_column(cl);
119
120 /* TODO:
121 *
122 * Currently it's possible to add/remove columns only if the table is
123 * empty (see list_empty(tb->tb_lines) above). It would be nice to
124 * enlarge/reduce lines cells[] always when we add/remove a new column.
125 */
126 return 0;
127}
128
1d90bcb1
OO
129/**
130 * scols_table_remove_column:
131 * @tb: a pointer to a struct libscols_table instance
132 * @cl: a pointer to a struct libscols_column instance
133 *
134 * Removes @cl from @tb.
135 *
136 * Returns: 0, a negative number in case of an error.
137 */
3e542c76
KZ
138int scols_table_remove_column(struct libscols_table *tb,
139 struct libscols_column *cl)
140{
141 assert(tb);
142 assert(cl);
143
144 if (!tb || !cl || !list_empty(&tb->tb_lines))
145 return -EINVAL;
146
0925a9dd
KZ
147 if (cl->flags & SCOLS_FL_TREE)
148 tb->ntreecols--;
149
710ed55d 150 DBG(TAB, ul_debugobj(tb, "remove column %p", cl));
3e542c76
KZ
151 list_del_init(&cl->cl_columns);
152 tb->ncols--;
153 scols_unref_column(cl);
154 return 0;
155}
156
1d90bcb1
OO
157/**
158 * scols_table_remove_columns:
159 * @tb: a pointer to a struct libscols_table instance
160 *
161 * Removes all of @tb's columns.
162 *
163 * Returns: 0, a negative number in case of an error.
164 */
3e542c76
KZ
165int scols_table_remove_columns(struct libscols_table *tb)
166{
167 assert(tb);
168
169 if (!tb || !list_empty(&tb->tb_lines))
170 return -EINVAL;
171
710ed55d 172 DBG(TAB, ul_debugobj(tb, "remove all columns"));
3e542c76
KZ
173 while (!list_empty(&tb->tb_columns)) {
174 struct libscols_column *cl = list_entry(tb->tb_columns.next,
175 struct libscols_column, cl_columns);
176 scols_table_remove_column(tb, cl);
177 }
178 return 0;
179}
180
181
1d90bcb1
OO
182/**
183 * scols_table_new_column:
3e542c76
KZ
184 * @tb: table
185 * @name: column header
186 * @whint: column width hint (absolute width: N > 1; relative width: N < 1)
1d90bcb1 187 * @flags: flags integer
3e542c76
KZ
188 *
189 * This is shortcut for
190 *
191 * cl = scols_new_column();
192 * scols_column_set_....(cl, ...);
193 * scols_table_add_column(tb, cl);
194 *
195 * The column width is possible to define by three ways:
196 *
197 * @whint = 0..1 : relative width, percent of terminal width
198 *
199 * @whint = 1..N : absolute width, empty colum will be truncated to
200 * the column header width
201 *
202 * @whint = 1..N
3e542c76 203 *
1d90bcb1 204 * The column is necessary to address by
3e542c76
KZ
205 * sequential number. The first defined column has the colnum = 0. For example:
206 *
207 * scols_table_new_column(tab, "FOO", 0.5, 0); // colnum = 0
208 * scols_table_new_column(tab, "BAR", 0.5, 0); // colnum = 1
209 * .
210 * .
211 * scols_line_get_cell(line, 0); // FOO column
212 * scols_line_get_cell(line, 1); // BAR column
213 *
214 * Returns: newly allocated column
215 */
216struct libscols_column *scols_table_new_column(struct libscols_table *tb,
217 const char *name,
8b992cb5
OO
218 double whint,
219 int flags)
3e542c76
KZ
220{
221 struct libscols_column *cl;
222 struct libscols_cell *hr;
223
224 assert (tb);
225 if (!tb)
226 return NULL;
710ed55d
KZ
227
228 DBG(TAB, ul_debugobj(tb, "new column name=%s, whint=%g, flags=%d",
229 name, whint, flags));
3e542c76
KZ
230 cl = scols_new_column();
231 if (!cl)
232 return NULL;
233
234 /* set column name */
235 hr = scols_column_get_header(cl);
236 if (!hr)
237 goto err;
238 if (scols_cell_set_data(hr, name))
239 goto err;
240
241 scols_column_set_whint(cl, whint);
8b992cb5
OO
242 scols_column_set_flags(cl, flags);
243
0925a9dd 244 if (scols_table_add_column(tb, cl)) /* this increments column ref-counter */
3e542c76
KZ
245 goto err;
246
247 scols_unref_column(cl);
248 return cl;
249err:
250 scols_unref_column(cl);
251 return NULL;
252}
253
1d90bcb1
OO
254/**
255 * scols_table_next_column:
256 * @tb: a pointer to a struct libscols_table instance
257 * @itr: a pointer to a struct libscols_iter instance
258 * @cl: a pointer to a pointer to a struct libscols_column instance
259 *
260 * Returns the next column of @tb via @cl.
261 *
262 * Returns: 0, a negative value in case of an error.
263 */
3e542c76
KZ
264int scols_table_next_column(struct libscols_table *tb,
265 struct libscols_iter *itr,
266 struct libscols_column **cl)
267{
268 int rc = 1;
269
270 if (!tb || !itr || !cl)
271 return -EINVAL;
272 *cl = NULL;
273
274 if (!itr->head)
275 SCOLS_ITER_INIT(itr, &tb->tb_columns);
276 if (itr->p != itr->head) {
277 SCOLS_ITER_ITERATE(itr, *cl, struct libscols_column, cl_columns);
278 rc = 0;
279 }
280
281 return rc;
282}
283
284
1d90bcb1
OO
285/**
286 * scols_table_get_ncols:
3e542c76
KZ
287 * @tb: table
288 *
1d90bcb1 289 * Returns: the ncols table member, a negative number in case of an error.
3e542c76
KZ
290 */
291int scols_table_get_ncols(struct libscols_table *tb)
292{
293 assert(tb);
294 return tb ? tb->ncols : -EINVAL;
295}
296
e2310281 297/**
1d90bcb1 298 * scols_table_get_nlines:
3e542c76
KZ
299 * @tb: table
300 *
1d90bcb1 301 * Returns: the nlines table member, a negative number in case of an error.
3e542c76
KZ
302 */
303int scols_table_get_nlines(struct libscols_table *tb)
304{
305 assert(tb);
306 return tb ? tb->nlines : -EINVAL;
307}
308
1d90bcb1
OO
309/**
310 * scols_table_set_stream:
311 * @tb: table
312 * @stream: output stream
313 *
314 * Sets the output stream for table @tb.
315 *
316 * Returns: 0, a negative number in case of an error.
317 */
571441e2
KZ
318int scols_table_set_stream(struct libscols_table *tb, FILE *stream)
319{
320 assert(tb);
321 if (!tb)
322 return -EINVAL;
323
710ed55d 324 DBG(TAB, ul_debugobj(tb, "setting alternative stream"));
571441e2
KZ
325 tb->out = stream;
326 return 0;
327}
328
1d90bcb1
OO
329/**
330 * scols_table_get_stream:
331 * @tb: table
332 *
333 * Gets the output stream for table @tb.
334 *
335 * Returns: stream pointer, NULL in case of an error or an unset stream.
336 */
571441e2
KZ
337FILE *scols_table_get_stream(struct libscols_table *tb)
338{
339 assert(tb);
340 return tb ? tb->out: NULL;
341}
342
1d90bcb1
OO
343/**
344 * scols_table_reduce_termwidth:
345 * @tb: table
346 * @reduce: width
347 *
348 * Reduce the output width to @reduce.
349 *
350 * Returns: 0, a negative value in case of an error.
351 */
e906be06
KZ
352int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce)
353{
354 assert(tb);
355 if (!tb)
356 return -EINVAL;
357
710ed55d 358 DBG(TAB, ul_debugobj(tb, "reduce terminal width: %zu", reduce));
e906be06
KZ
359 tb->termreduce = reduce;
360 return 0;
361}
362
1d90bcb1
OO
363/**
364 * scols_table_get_column:
3e542c76 365 * @tb: table
1d90bcb1 366 * @n: number of column (0..N)
3e542c76
KZ
367 *
368 * Returns: pointer to column or NULL
369 */
370struct libscols_column *scols_table_get_column(struct libscols_table *tb,
371 size_t n)
372{
373 struct libscols_iter itr;
374 struct libscols_column *cl;
375
376 assert(tb);
377 if (!tb)
378 return NULL;
379 if (n >= tb->ncols)
380 return NULL;
381
382 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
383 while (scols_table_next_column(tb, &itr, &cl) == 0) {
384 if (cl->seqnum == n)
385 return cl;
386 }
387 return NULL;
388}
389
1d90bcb1
OO
390/**
391 * scols_table_add_line:
392 * @tb: table
393 * @ln: line
394 *
395 * Note that this function calls scols_line_alloc_cells() if number
3e542c76 396 * of the cells in the line is too small for @tb.
1d90bcb1
OO
397 *
398 * Returns: 0, a negative value in case of an error.
3e542c76
KZ
399 */
400int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
401{
402
403 assert(tb);
404 assert(ln);
405
406 if (!tb || !ln)
407 return -EINVAL;
408
409 if (tb->ncols > ln->ncells) {
410 int rc = scols_line_alloc_cells(ln, tb->ncols);
411 if (rc)
412 return rc;
413 }
414
710ed55d 415 DBG(TAB, ul_debugobj(tb, "add line %p", ln));
3e542c76
KZ
416 list_add_tail(&ln->ln_lines, &tb->tb_lines);
417 ln->seqnum = tb->nlines++;
418 scols_ref_line(ln);
419 return 0;
420}
421
1d90bcb1
OO
422/**
423 * scols_table_remove_line:
424 * @tb: table
425 * @ln: line
426 *
427 * Note that this function does not destroy the parent<->child relationship between lines.
3e542c76 428 * You have to call scols_line_remove_child()
1d90bcb1
OO
429 *
430 * Returns: 0, a negative value in case of an error.
3e542c76
KZ
431 */
432int scols_table_remove_line(struct libscols_table *tb,
433 struct libscols_line *ln)
434{
435 assert(tb);
436 assert(ln);
437
438 if (!tb || !ln)
439 return -EINVAL;
440
710ed55d 441 DBG(TAB, ul_debugobj(tb, "remove line %p", ln));
3e542c76
KZ
442 list_del_init(&ln->ln_lines);
443 tb->nlines--;
444 scols_unref_line(ln);
445 return 0;
446}
447
1d90bcb1
OO
448/**
449 * scols_table_remove_lines:
450 * @tb: table
451 *
452 * This empties the table and also destroys all the parent<->child relationships.
453 */
3e542c76
KZ
454void scols_table_remove_lines(struct libscols_table *tb)
455{
456 assert(tb);
457 if (!tb)
458 return;
459
710ed55d 460 DBG(TAB, ul_debugobj(tb, "remove all lines"));
3e542c76
KZ
461 while (!list_empty(&tb->tb_lines)) {
462 struct libscols_line *ln = list_entry(tb->tb_lines.next,
463 struct libscols_line, ln_lines);
464 if (ln->parent)
465 scols_line_remove_child(ln->parent, ln);
466 scols_table_remove_line(tb, ln);
467 }
468}
469
1d90bcb1
OO
470/**
471 * scols_table_next_line:
472 * @tb: a pointer to a struct libscols_table instance
473 * @itr: a pointer to a struct libscols_iter instance
474 * @ln: a pointer to a pointer to a struct libscols_line instance
475 *
476 * Finds the next line and returns a pointer to it via @ln.
477 *
478 * Returns: 0, a negative value in case of an error.
479 */
3e542c76
KZ
480int scols_table_next_line(struct libscols_table *tb,
481 struct libscols_iter *itr,
482 struct libscols_line **ln)
483{
484 int rc = 1;
485
486 if (!tb || !itr || !ln)
487 return -EINVAL;
488 *ln = NULL;
489
490 if (!itr->head)
491 SCOLS_ITER_INIT(itr, &tb->tb_lines);
492 if (itr->p != itr->head) {
493 SCOLS_ITER_ITERATE(itr, *ln, struct libscols_line, ln_lines);
494 rc = 0;
495 }
496
497 return rc;
498}
499
1d90bcb1
OO
500/**
501 * scols_table_new_line:
3e542c76
KZ
502 * @tb: table
503 * @parent: parental line or NULL
504 *
505 * This is shortcut for
506 *
1d90bcb1 507 * ln = scols_new_line();
3e542c76 508 * scols_table_add_line(tb, ln);
6e792bb6
OO
509 * scols_line_add_child(parent, ln);
510 *
3e542c76
KZ
511 *
512 * Returns: newly allocate line
513 */
514struct libscols_line *scols_table_new_line(struct libscols_table *tb,
515 struct libscols_line *parent)
516{
517 struct libscols_line *ln;
518
519 assert(tb);
520 assert(tb->ncols);
521
522 if (!tb || !tb->ncols)
523 return NULL;
710ed55d 524
3e542c76
KZ
525 ln = scols_new_line();
526 if (!ln)
527 return NULL;
528
529 if (scols_table_add_line(tb, ln))
530 goto err;
531 if (parent)
532 scols_line_add_child(parent, ln);
533
534 scols_unref_line(ln); /* ref-counter incremented by scols_table_add_line() */
535 return ln;
536err:
537 scols_unref_line(ln);
538 return NULL;
539}
540
1d90bcb1
OO
541/**
542 * scols_table_get_line:
543 * @tb: table
544 * @n: column number (0..N)
545 *
546 * This is a shortcut for
547 *
548 * ln = scols_new_line();
549 * scols_line_set_....(cl, ...);
550 * scols_table_add_line(tb, ln);
551 *
552 * Returns: a newly allocate line
553 */
3e542c76
KZ
554struct libscols_line *scols_table_get_line(struct libscols_table *tb,
555 size_t n)
556{
557 struct libscols_iter itr;
558 struct libscols_line *ln;
559
560 assert(tb);
561 if (!tb)
562 return NULL;
563 if (n >= tb->nlines)
564 return NULL;
565
566 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
567 while (scols_table_next_line(tb, &itr, &ln) == 0) {
568 if (ln->seqnum == n)
569 return ln;
570 }
571 return NULL;
572}
573
1d90bcb1
OO
574/**
575 * scols_copy_table:
576 * @tb: table
577 *
3e542c76
KZ
578 * Creates a new independent table copy, except struct libscols_symbols that
579 * are shared between the tables.
1d90bcb1
OO
580 *
581 * Returns: a newly allocated copy of @tb
3e542c76
KZ
582 */
583struct libscols_table *scols_copy_table(struct libscols_table *tb)
584{
585 struct libscols_table *ret;
586 struct libscols_line *ln;
587 struct libscols_column *cl;
588 struct libscols_iter itr;
589
590 assert(tb);
591 if (!tb)
592 return NULL;
0925a9dd 593 ret = scols_new_table();
3e542c76
KZ
594 if (!ret)
595 return NULL;
596
710ed55d
KZ
597 DBG(TAB, ul_debugobj(tb, "copy into %p", ret));
598
0925a9dd
KZ
599 if (tb->symbols)
600 scols_table_set_symbols(ret, tb->symbols);
601
3e542c76
KZ
602 /* columns */
603 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
604 while (scols_table_next_column(tb, &itr, &cl) == 0) {
605 cl = scols_copy_column(cl);
606 if (!cl)
607 goto err;
0925a9dd 608 if (scols_table_add_column(ret, cl))
3e542c76
KZ
609 goto err;
610 scols_unref_column(cl);
611 }
612
613 /* lines */
614 scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
615 while (scols_table_next_line(tb, &itr, &ln) == 0) {
616 struct libscols_line *newln = scols_copy_line(ln);
617 if (!newln)
618 goto err;
619 if (scols_table_add_line(ret, newln))
620 goto err;
621 if (ln->parent) {
622 struct libscols_line *p =
623 scols_table_get_line(ret, ln->parent->seqnum);
624 if (p)
625 scols_line_add_child(p, newln);
626 }
627 scols_unref_line(newln);
628 }
629
d1b4d14f
OO
630 /* separators */
631 if (scols_table_set_column_separator(ret, tb->colsep) ||
632 scols_table_set_line_separator(ret, tb->linesep))
633 goto err;
634
3e542c76
KZ
635 return ret;
636err:
637 scols_unref_table(ret);
638 return NULL;
639}
640
1d90bcb1
OO
641/**
642 * scols_table_set_symbols:
643 * @tb: table
0925a9dd
KZ
644 * @sy: symbols or NULL
645 *
646 * Add a reference to @sy from the table. The symbols are used by library to
647 * draw tree output. If no symbols are specified then library checks the
648 * current environment to select ASCII or UTF8 symbols. This default behavior
649 * could be controlled by scols_table_enable_ascii().
1d90bcb1
OO
650 *
651 * Returns: 0, a negative value in case of an error.
652 */
3e542c76
KZ
653int scols_table_set_symbols(struct libscols_table *tb,
654 struct libscols_symbols *sy)
655{
656 assert(tb);
657
658 if (!tb)
659 return -EINVAL;
660
710ed55d
KZ
661 DBG(TAB, ul_debugobj(tb, "setting alternative symbols %p", sy));
662
3e542c76
KZ
663 if (tb->symbols) /* unref old */
664 scols_unref_symbols(tb->symbols);
665 if (sy) { /* ref user defined */
666 tb->symbols = sy;
667 scols_ref_symbols(sy);
668 } else { /* default symbols */
669 tb->symbols = scols_new_symbols();
670 if (!tb->symbols)
671 return -ENOMEM;
672#if defined(HAVE_WIDECHAR)
8a38a8d3 673 if (!scols_table_is_ascii(tb) &&
3e542c76
KZ
674 !strcmp(nl_langinfo(CODESET), "UTF-8")) {
675 scols_symbols_set_branch(tb->symbols, UTF_VR UTF_H);
676 scols_symbols_set_vertical(tb->symbols, UTF_V " ");
677 scols_symbols_set_right(tb->symbols, UTF_UR UTF_H);
678 } else
679#endif
680 {
681 scols_symbols_set_branch(tb->symbols, "|-");
682 scols_symbols_set_vertical(tb->symbols, "| ");
683 scols_symbols_set_right(tb->symbols, "`-");
684 }
685 }
686
687 return 0;
688}
8a38a8d3
OO
689/**
690 * scols_table_enable_colors:
691 * @tb: table
692 * @enable: 1 or 0
693 *
0925a9dd 694 * Enable/disable colors.
8a38a8d3
OO
695 *
696 * Returns: 0 on success, negative number in case of an error.
697 */
698int scols_table_enable_colors(struct libscols_table *tb, int enable)
699{
700 assert(tb);
701 if (!tb)
702 return -EINVAL;
710ed55d
KZ
703
704 DBG(TAB, ul_debugobj(tb, "colors: %s", enable ? "ENABLE" : "DISABLE"));
8a38a8d3
OO
705 tb->colors_wanted = enable;
706 return 0;
707}
708/**
0925a9dd 709 * scols_table_enable_raw:
8a38a8d3
OO
710 * @tb: table
711 * @enable: 1 or 0
712 *
0925a9dd
KZ
713 * Enable/disable raw output format. The parsable output formats
714 * (export and raw) are mutually exclusive.
8a38a8d3
OO
715 *
716 * Returns: 0 on success, negative number in case of an error.
717 */
0925a9dd 718int scols_table_enable_raw(struct libscols_table *tb, int enable)
8a38a8d3
OO
719{
720 assert(tb);
721 if (!tb)
722 return -EINVAL;
0925a9dd 723
710ed55d 724 DBG(TAB, ul_debugobj(tb, "raw: %s", enable ? "ENABLE" : "DISABLE"));
0925a9dd
KZ
725 if (enable)
726 tb->format = SCOLS_FMT_RAW;
727 else if (tb->format == SCOLS_FMT_RAW)
728 tb->format = 0;
8a38a8d3
OO
729 return 0;
730}
0925a9dd 731
8a38a8d3 732/**
0925a9dd 733 * scols_table_enable_export:
8a38a8d3
OO
734 * @tb: table
735 * @enable: 1 or 0
736 *
0925a9dd
KZ
737 * Enable/disable export output format (COLUMNAME="value" ...).
738 * The parsable output formats (export and raw) are mutually exclusive.
8a38a8d3
OO
739 *
740 * Returns: 0 on success, negative number in case of an error.
741 */
0925a9dd 742int scols_table_enable_export(struct libscols_table *tb, int enable)
8a38a8d3
OO
743{
744 assert(tb);
745 if (!tb)
746 return -EINVAL;
710ed55d
KZ
747
748 DBG(TAB, ul_debugobj(tb, "export: %s", enable ? "ENABLE" : "DISABLE"));
0925a9dd
KZ
749 if (enable)
750 tb->format = SCOLS_FMT_EXPORT;
751 else if (tb->format == SCOLS_FMT_EXPORT)
752 tb->format = 0;
8a38a8d3
OO
753 return 0;
754}
0925a9dd 755
8a38a8d3 756/**
0925a9dd 757 * scols_table_enable_ascii:
8a38a8d3
OO
758 * @tb: table
759 * @enable: 1 or 0
760 *
0925a9dd
KZ
761 * The ASCII-only output is relevant for tree-like outputs. The library
762 * checks if the current environment is UTF8 compatible by default. This
763 * function overrides this check and force the library to use ASCII chars
764 * for the tree.
8a38a8d3 765 *
0925a9dd
KZ
766 * If a custom libcols_symbols are specified (see scols_table_set_symbols()
767 * then ASCII flag setting is ignored.
8a38a8d3
OO
768 *
769 * Returns: 0 on success, negative number in case of an error.
770 */
0925a9dd 771int scols_table_enable_ascii(struct libscols_table *tb, int enable)
8a38a8d3
OO
772{
773 assert(tb);
774 if (!tb)
775 return -EINVAL;
710ed55d
KZ
776
777 DBG(TAB, ul_debugobj(tb, "ascii: %s", enable ? "ENABLE" : "DISABLE"));
0925a9dd 778 tb->ascii = enable ? 1 : 0;
8a38a8d3
OO
779 return 0;
780}
0925a9dd 781
8a38a8d3 782/**
0925a9dd 783 * scols_table_enable_noheadings:
8a38a8d3
OO
784 * @tb: table
785 * @enable: 1 or 0
786 *
0925a9dd 787 * Enable/disable header line.
8a38a8d3
OO
788 *
789 * Returns: 0 on success, negative number in case of an error.
790 */
0925a9dd 791int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
8a38a8d3
OO
792{
793 assert(tb);
794 if (!tb)
795 return -EINVAL;
710ed55d 796 DBG(TAB, ul_debugobj(tb, "noheading: %s", enable ? "ENABLE" : "DISABLE"));
0925a9dd 797 tb->no_headings = enable ? 1 : 0;
8a38a8d3
OO
798 return 0;
799}
3e542c76 800
8a38a8d3 801/**
0925a9dd 802 * scols_table_enable_maxout:
8a38a8d3
OO
803 * @tb: table
804 * @enable: 1 or 0
805 *
0925a9dd
KZ
806 * The extra space after last column is ignored by default. The output
807 * maximization use the extra space for all columns.
8a38a8d3
OO
808 *
809 * Returns: 0 on success, negative number in case of an error.
810 */
0925a9dd 811int scols_table_enable_maxout(struct libscols_table *tb, int enable)
8a38a8d3
OO
812{
813 assert(tb);
814 if (!tb)
815 return -EINVAL;
710ed55d 816 DBG(TAB, ul_debugobj(tb, "maxout: %s", enable ? "ENABLE" : "DISABLE"));
0925a9dd 817 tb->maxout = enable ? 1 : 0;
8a38a8d3
OO
818 return 0;
819}
0925a9dd 820
8a38a8d3
OO
821/**
822 * scols_table_colors_wanted:
823 * @tb: table
824 *
0925a9dd 825 * Returns: 1 if colors are enabled.
8a38a8d3
OO
826 */
827int scols_table_colors_wanted(struct libscols_table *tb)
828{
829 assert(tb);
0925a9dd 830 return tb && tb->colors_wanted;
8a38a8d3 831}
c0070f81
OO
832
833/**
834 * scols_table_is_empty:
835 * @tb: table
836 *
0925a9dd 837 * Returns: 1 if the table is empty.
c0070f81
OO
838 */
839int scols_table_is_empty(struct libscols_table *tb)
840{
0925a9dd 841 assert(tb);
c0070f81
OO
842 return !tb || !tb->nlines;
843}
0925a9dd 844
8a38a8d3 845/**
0925a9dd 846 * scols_table_is_ascii:
8a38a8d3
OO
847 * @tb: table
848 *
0925a9dd 849 * Returns: 1 if ASCII tree is enabled.
8a38a8d3 850 */
0925a9dd 851int scols_table_is_ascii(struct libscols_table *tb)
8a38a8d3
OO
852{
853 assert(tb);
0925a9dd 854 return tb && tb->ascii;
8a38a8d3 855}
0925a9dd 856
8a38a8d3 857/**
0925a9dd 858 * scols_table_is_noheadings:
8a38a8d3
OO
859 * @tb: table
860 *
0925a9dd 861 * Returns: 1 if header output is disabled.
8a38a8d3 862 */
0925a9dd 863int scols_table_is_noheadings(struct libscols_table *tb)
8a38a8d3
OO
864{
865 assert(tb);
0925a9dd 866 return tb && tb->no_headings;
8a38a8d3 867}
0925a9dd 868
8a38a8d3 869/**
0925a9dd 870 * scols_table_is_export:
8a38a8d3
OO
871 * @tb: table
872 *
0925a9dd 873 * Returns: 1 if export output format is enabled.
8a38a8d3 874 */
0925a9dd 875int scols_table_is_export(struct libscols_table *tb)
8a38a8d3
OO
876{
877 assert(tb);
0925a9dd 878 return tb && tb->format == SCOLS_FMT_EXPORT;
8a38a8d3 879}
0925a9dd 880
8a38a8d3 881/**
0925a9dd 882 * scols_table_is_raw:
8a38a8d3
OO
883 * @tb: table
884 *
0925a9dd 885 * Returns: 1 if raw output format is enabled.
8a38a8d3 886 */
0925a9dd 887int scols_table_is_raw(struct libscols_table *tb)
8a38a8d3
OO
888{
889 assert(tb);
0925a9dd 890 return tb && tb->format == SCOLS_FMT_RAW;
8a38a8d3 891}
0925a9dd
KZ
892
893
8a38a8d3 894/**
0925a9dd 895 * scols_table_is_maxout
8a38a8d3
OO
896 * @tb: table
897 *
0925a9dd 898 * Returns: 1 if output maximization is enabled, negative value in case of an error.
8a38a8d3 899 */
0925a9dd 900int scols_table_is_maxout(struct libscols_table *tb)
8a38a8d3
OO
901{
902 assert(tb);
0925a9dd 903 return tb && tb->maxout;
8a38a8d3 904}
0925a9dd 905
8a38a8d3
OO
906/**
907 * scols_table_is_tree:
908 * @tb: table
909 *
0925a9dd 910 * Returns: returns 1 tree-like output is expected.
8a38a8d3
OO
911 */
912int scols_table_is_tree(struct libscols_table *tb)
913{
914 assert(tb);
0925a9dd 915 return tb && tb->ntreecols > 0;
8a38a8d3 916}
d1b4d14f
OO
917
918/**
919 * scols_table_set_column_separator:
920 * @tb: table
921 * @sep: separator
922 *
923 * Sets the column separator of @tb to @sep.
924 * Please note that @sep should always take up a single cell in the output.
925 *
926 * Returns: 0, a negative value in case of an error.
927 */
4baab7df 928int scols_table_set_column_separator(struct libscols_table *tb, const char *sep)
d1b4d14f 929{
4baab7df
KZ
930 char *p = NULL;
931
d1b4d14f
OO
932 assert (tb);
933
934 if (!tb)
935 return -EINVAL;
936
4baab7df
KZ
937 if (sep) {
938 p = strdup(sep);
939 if (!p)
940 return -ENOMEM;
941 }
d1b4d14f 942
710ed55d 943 DBG(TAB, ul_debugobj(tb, "new columns separator: %s", sep));
d1b4d14f 944 free(tb->colsep);
4baab7df 945 tb->colsep = p;
d1b4d14f
OO
946 return 0;
947}
948
949/**
950 * scols_table_set_line_separator:
951 * @tb: table
952 * @sep: separator
953 *
954 * Sets the line separator of @tb to @sep.
955 *
956 * Returns: 0, a negative value in case of an error.
957 */
4baab7df 958int scols_table_set_line_separator(struct libscols_table *tb, const char *sep)
d1b4d14f 959{
4baab7df
KZ
960 char *p = NULL;
961
d1b4d14f
OO
962 assert (tb);
963
964 if (!tb)
965 return -EINVAL;
966
4baab7df
KZ
967 if (sep) {
968 p = strdup(sep);
969 if (!p)
970 return -ENOMEM;
971 }
d1b4d14f 972
710ed55d 973 DBG(TAB, ul_debugobj(tb, "new lines separator: %s", sep));
d1b4d14f 974 free(tb->linesep);
4baab7df 975 tb->linesep = p;
d1b4d14f
OO
976 return 0;
977}
978
979/**
980 * scols_table_get_column_separator:
981 * @tb: table
982 *
983 * Returns: @tb column separator, NULL in case of an error
984 */
985char *scols_table_get_column_separator(struct libscols_table *tb)
986{
987 assert (tb);
988
989 if (!tb)
990 return NULL;
991 return tb->colsep;
992}
993
994/**
995 * scols_table_get_line_separator:
996 * @tb: table
997 *
998 * Returns: @tb line separator, NULL in case of an error
999 */
1000char *scols_table_get_line_separator(struct libscols_table *tb)
1001{
1002 assert (tb);
1003
1004 if (!tb)
1005 return NULL;
1006 return tb->linesep;
1007
1008}
57a86f9b
KZ
1009
1010static int cells_cmp_wrapper(struct list_head *a, struct list_head *b, void *data)
1011{
1012 struct libscols_column *cl = (struct libscols_column *) data;
1013 struct libscols_line *ra, *rb;
1014 struct libscols_cell *ca, *cb;
1015
1016 assert(a);
1017 assert(b);
1018 assert(cl);
1019
1020 ra = list_entry(a, struct libscols_line, ln_lines);
1021 rb = list_entry(b, struct libscols_line, ln_lines);
1022 ca = scols_line_get_cell(ra, cl->seqnum);
1023 cb = scols_line_get_cell(rb, cl->seqnum);
1024
1025 return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
1026}
1027
1028/**
1029 * scols_sort_table:
1030 * @tb: table
1031 * @cl: order by this column
1032 *
1033 * Orders the table by the column. See also scols_column_set_cmpfunc().
1034 *
1035 * Returns: 0, a negative value in case of an error.
1036 */
1037int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl)
1038{
1039 assert(tb);
1040 assert(cl);
1041
1042 if (!tb || !cl)
1043 return -EINVAL;
1044
710ed55d 1045 DBG(TAB, ul_debugobj(tb, "sorting table"));
57a86f9b
KZ
1046 list_sort(&tb->tb_lines, cells_cmp_wrapper, cl);
1047 return 0;
1048}