]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libsmartcols/src/table.c
libsmartcols: add debug messages
[thirdparty/util-linux.git] / libsmartcols / src / table.c
1 /*
2 * table.c - functions handling the data at the table level
3 *
4 * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
5 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
6 *
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
9 */
10
11 /**
12 * SECTION: table
13 * @title: Table
14 * @short_description: table data API
15 *
16 * Table data manipulation API.
17 */
18
19
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
41 /**
42 * scols_new_table:
43 *
44 * Returns: A newly allocated table.
45 */
46 struct libscols_table *scols_new_table(void)
47 {
48 struct libscols_table *tb;
49
50 tb = calloc(1, sizeof(struct libscols_table));
51 if (!tb)
52 return NULL;
53
54 tb->refcount = 1;
55 tb->out = stdout;
56
57 INIT_LIST_HEAD(&tb->tb_lines);
58 INIT_LIST_HEAD(&tb->tb_columns);
59
60 DBG(TAB, ul_debugobj(tb, "alloc"));
61 return tb;
62 }
63
64 /**
65 * scols_ref_table:
66 * @tb: a pointer to a struct libscols_table instance
67 *
68 * Increases the refcount of @tb.
69 */
70 void scols_ref_table(struct libscols_table *tb)
71 {
72 if (tb)
73 tb->refcount++;
74 }
75
76 /**
77 * scols_unref_table:
78 * @tb: a pointer to a struct libscols_table instance
79 *
80 * Decreases the refcount of @tb.
81 */
82 void scols_unref_table(struct libscols_table *tb)
83 {
84 if (tb && (--tb->refcount <= 0)) {
85 DBG(TAB, ul_debugobj(tb, "dealloc"));
86 scols_table_remove_lines(tb);
87 scols_table_remove_columns(tb);
88 scols_unref_symbols(tb->symbols);
89 free(tb->linesep);
90 free(tb->colsep);
91 free(tb);
92 }
93 }
94
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
99 *
100 * Adds @cl to @tb's column list.
101 *
102 * Returns: 0, a negative number in case of an error.
103 */
104 int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl)
105 {
106 assert(tb);
107 assert(cl);
108
109 if (!tb || !cl || !list_empty(&tb->tb_lines))
110 return -EINVAL;
111
112 if (cl->flags & SCOLS_FL_TREE)
113 tb->ntreecols++;
114
115 DBG(TAB, ul_debugobj(tb, "add column %p", cl));
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
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 */
138 int 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
147 if (cl->flags & SCOLS_FL_TREE)
148 tb->ntreecols--;
149
150 DBG(TAB, ul_debugobj(tb, "remove column %p", cl));
151 list_del_init(&cl->cl_columns);
152 tb->ncols--;
153 scols_unref_column(cl);
154 return 0;
155 }
156
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 */
165 int 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
172 DBG(TAB, ul_debugobj(tb, "remove all columns"));
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
182 /**
183 * scols_table_new_column:
184 * @tb: table
185 * @name: column header
186 * @whint: column width hint (absolute width: N > 1; relative width: N < 1)
187 * @flags: flags integer
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
203 *
204 * The column is necessary to address by
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 */
216 struct libscols_column *scols_table_new_column(struct libscols_table *tb,
217 const char *name,
218 double whint,
219 int flags)
220 {
221 struct libscols_column *cl;
222 struct libscols_cell *hr;
223
224 assert (tb);
225 if (!tb)
226 return NULL;
227
228 DBG(TAB, ul_debugobj(tb, "new column name=%s, whint=%g, flags=%d",
229 name, whint, flags));
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);
242 scols_column_set_flags(cl, flags);
243
244 if (scols_table_add_column(tb, cl)) /* this increments column ref-counter */
245 goto err;
246
247 scols_unref_column(cl);
248 return cl;
249 err:
250 scols_unref_column(cl);
251 return NULL;
252 }
253
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 */
264 int 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
285 /**
286 * scols_table_get_ncols:
287 * @tb: table
288 *
289 * Returns: the ncols table member, a negative number in case of an error.
290 */
291 int scols_table_get_ncols(struct libscols_table *tb)
292 {
293 assert(tb);
294 return tb ? tb->ncols : -EINVAL;
295 }
296
297 /**
298 * scols_table_get_nlines:
299 * @tb: table
300 *
301 * Returns: the nlines table member, a negative number in case of an error.
302 */
303 int scols_table_get_nlines(struct libscols_table *tb)
304 {
305 assert(tb);
306 return tb ? tb->nlines : -EINVAL;
307 }
308
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 */
318 int scols_table_set_stream(struct libscols_table *tb, FILE *stream)
319 {
320 assert(tb);
321 if (!tb)
322 return -EINVAL;
323
324 DBG(TAB, ul_debugobj(tb, "setting alternative stream"));
325 tb->out = stream;
326 return 0;
327 }
328
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 */
337 FILE *scols_table_get_stream(struct libscols_table *tb)
338 {
339 assert(tb);
340 return tb ? tb->out: NULL;
341 }
342
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 */
352 int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce)
353 {
354 assert(tb);
355 if (!tb)
356 return -EINVAL;
357
358 DBG(TAB, ul_debugobj(tb, "reduce terminal width: %zu", reduce));
359 tb->termreduce = reduce;
360 return 0;
361 }
362
363 /**
364 * scols_table_get_column:
365 * @tb: table
366 * @n: number of column (0..N)
367 *
368 * Returns: pointer to column or NULL
369 */
370 struct 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
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
396 * of the cells in the line is too small for @tb.
397 *
398 * Returns: 0, a negative value in case of an error.
399 */
400 int 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
415 DBG(TAB, ul_debugobj(tb, "add line %p", ln));
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
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.
428 * You have to call scols_line_remove_child()
429 *
430 * Returns: 0, a negative value in case of an error.
431 */
432 int 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
441 DBG(TAB, ul_debugobj(tb, "remove line %p", ln));
442 list_del_init(&ln->ln_lines);
443 tb->nlines--;
444 scols_unref_line(ln);
445 return 0;
446 }
447
448 /**
449 * scols_table_remove_lines:
450 * @tb: table
451 *
452 * This empties the table and also destroys all the parent<->child relationships.
453 */
454 void scols_table_remove_lines(struct libscols_table *tb)
455 {
456 assert(tb);
457 if (!tb)
458 return;
459
460 DBG(TAB, ul_debugobj(tb, "remove all lines"));
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
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 */
480 int 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
500 /**
501 * scols_table_new_line:
502 * @tb: table
503 * @parent: parental line or NULL
504 *
505 * This is shortcut for
506 *
507 * ln = scols_new_line();
508 * scols_table_add_line(tb, ln);
509 * scols_line_add_child(parent, ln);
510 *
511 *
512 * Returns: newly allocate line
513 */
514 struct 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;
524
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;
536 err:
537 scols_unref_line(ln);
538 return NULL;
539 }
540
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 */
554 struct 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
574 /**
575 * scols_copy_table:
576 * @tb: table
577 *
578 * Creates a new independent table copy, except struct libscols_symbols that
579 * are shared between the tables.
580 *
581 * Returns: a newly allocated copy of @tb
582 */
583 struct 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;
593 ret = scols_new_table();
594 if (!ret)
595 return NULL;
596
597 DBG(TAB, ul_debugobj(tb, "copy into %p", ret));
598
599 if (tb->symbols)
600 scols_table_set_symbols(ret, tb->symbols);
601
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;
608 if (scols_table_add_column(ret, cl))
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
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
635 return ret;
636 err:
637 scols_unref_table(ret);
638 return NULL;
639 }
640
641 /**
642 * scols_table_set_symbols:
643 * @tb: table
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().
650 *
651 * Returns: 0, a negative value in case of an error.
652 */
653 int 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
661 DBG(TAB, ul_debugobj(tb, "setting alternative symbols %p", sy));
662
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)
673 if (!scols_table_is_ascii(tb) &&
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 }
689 /**
690 * scols_table_enable_colors:
691 * @tb: table
692 * @enable: 1 or 0
693 *
694 * Enable/disable colors.
695 *
696 * Returns: 0 on success, negative number in case of an error.
697 */
698 int scols_table_enable_colors(struct libscols_table *tb, int enable)
699 {
700 assert(tb);
701 if (!tb)
702 return -EINVAL;
703
704 DBG(TAB, ul_debugobj(tb, "colors: %s", enable ? "ENABLE" : "DISABLE"));
705 tb->colors_wanted = enable;
706 return 0;
707 }
708 /**
709 * scols_table_enable_raw:
710 * @tb: table
711 * @enable: 1 or 0
712 *
713 * Enable/disable raw output format. The parsable output formats
714 * (export and raw) are mutually exclusive.
715 *
716 * Returns: 0 on success, negative number in case of an error.
717 */
718 int scols_table_enable_raw(struct libscols_table *tb, int enable)
719 {
720 assert(tb);
721 if (!tb)
722 return -EINVAL;
723
724 DBG(TAB, ul_debugobj(tb, "raw: %s", enable ? "ENABLE" : "DISABLE"));
725 if (enable)
726 tb->format = SCOLS_FMT_RAW;
727 else if (tb->format == SCOLS_FMT_RAW)
728 tb->format = 0;
729 return 0;
730 }
731
732 /**
733 * scols_table_enable_export:
734 * @tb: table
735 * @enable: 1 or 0
736 *
737 * Enable/disable export output format (COLUMNAME="value" ...).
738 * The parsable output formats (export and raw) are mutually exclusive.
739 *
740 * Returns: 0 on success, negative number in case of an error.
741 */
742 int scols_table_enable_export(struct libscols_table *tb, int enable)
743 {
744 assert(tb);
745 if (!tb)
746 return -EINVAL;
747
748 DBG(TAB, ul_debugobj(tb, "export: %s", enable ? "ENABLE" : "DISABLE"));
749 if (enable)
750 tb->format = SCOLS_FMT_EXPORT;
751 else if (tb->format == SCOLS_FMT_EXPORT)
752 tb->format = 0;
753 return 0;
754 }
755
756 /**
757 * scols_table_enable_ascii:
758 * @tb: table
759 * @enable: 1 or 0
760 *
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.
765 *
766 * If a custom libcols_symbols are specified (see scols_table_set_symbols()
767 * then ASCII flag setting is ignored.
768 *
769 * Returns: 0 on success, negative number in case of an error.
770 */
771 int scols_table_enable_ascii(struct libscols_table *tb, int enable)
772 {
773 assert(tb);
774 if (!tb)
775 return -EINVAL;
776
777 DBG(TAB, ul_debugobj(tb, "ascii: %s", enable ? "ENABLE" : "DISABLE"));
778 tb->ascii = enable ? 1 : 0;
779 return 0;
780 }
781
782 /**
783 * scols_table_enable_noheadings:
784 * @tb: table
785 * @enable: 1 or 0
786 *
787 * Enable/disable header line.
788 *
789 * Returns: 0 on success, negative number in case of an error.
790 */
791 int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
792 {
793 assert(tb);
794 if (!tb)
795 return -EINVAL;
796 DBG(TAB, ul_debugobj(tb, "noheading: %s", enable ? "ENABLE" : "DISABLE"));
797 tb->no_headings = enable ? 1 : 0;
798 return 0;
799 }
800
801 /**
802 * scols_table_enable_maxout:
803 * @tb: table
804 * @enable: 1 or 0
805 *
806 * The extra space after last column is ignored by default. The output
807 * maximization use the extra space for all columns.
808 *
809 * Returns: 0 on success, negative number in case of an error.
810 */
811 int scols_table_enable_maxout(struct libscols_table *tb, int enable)
812 {
813 assert(tb);
814 if (!tb)
815 return -EINVAL;
816 DBG(TAB, ul_debugobj(tb, "maxout: %s", enable ? "ENABLE" : "DISABLE"));
817 tb->maxout = enable ? 1 : 0;
818 return 0;
819 }
820
821 /**
822 * scols_table_colors_wanted:
823 * @tb: table
824 *
825 * Returns: 1 if colors are enabled.
826 */
827 int scols_table_colors_wanted(struct libscols_table *tb)
828 {
829 assert(tb);
830 return tb && tb->colors_wanted;
831 }
832
833 /**
834 * scols_table_is_empty:
835 * @tb: table
836 *
837 * Returns: 1 if the table is empty.
838 */
839 int scols_table_is_empty(struct libscols_table *tb)
840 {
841 assert(tb);
842 return !tb || !tb->nlines;
843 }
844
845 /**
846 * scols_table_is_ascii:
847 * @tb: table
848 *
849 * Returns: 1 if ASCII tree is enabled.
850 */
851 int scols_table_is_ascii(struct libscols_table *tb)
852 {
853 assert(tb);
854 return tb && tb->ascii;
855 }
856
857 /**
858 * scols_table_is_noheadings:
859 * @tb: table
860 *
861 * Returns: 1 if header output is disabled.
862 */
863 int scols_table_is_noheadings(struct libscols_table *tb)
864 {
865 assert(tb);
866 return tb && tb->no_headings;
867 }
868
869 /**
870 * scols_table_is_export:
871 * @tb: table
872 *
873 * Returns: 1 if export output format is enabled.
874 */
875 int scols_table_is_export(struct libscols_table *tb)
876 {
877 assert(tb);
878 return tb && tb->format == SCOLS_FMT_EXPORT;
879 }
880
881 /**
882 * scols_table_is_raw:
883 * @tb: table
884 *
885 * Returns: 1 if raw output format is enabled.
886 */
887 int scols_table_is_raw(struct libscols_table *tb)
888 {
889 assert(tb);
890 return tb && tb->format == SCOLS_FMT_RAW;
891 }
892
893
894 /**
895 * scols_table_is_maxout
896 * @tb: table
897 *
898 * Returns: 1 if output maximization is enabled, negative value in case of an error.
899 */
900 int scols_table_is_maxout(struct libscols_table *tb)
901 {
902 assert(tb);
903 return tb && tb->maxout;
904 }
905
906 /**
907 * scols_table_is_tree:
908 * @tb: table
909 *
910 * Returns: returns 1 tree-like output is expected.
911 */
912 int scols_table_is_tree(struct libscols_table *tb)
913 {
914 assert(tb);
915 return tb && tb->ntreecols > 0;
916 }
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 */
928 int scols_table_set_column_separator(struct libscols_table *tb, const char *sep)
929 {
930 char *p = NULL;
931
932 assert (tb);
933
934 if (!tb)
935 return -EINVAL;
936
937 if (sep) {
938 p = strdup(sep);
939 if (!p)
940 return -ENOMEM;
941 }
942
943 DBG(TAB, ul_debugobj(tb, "new columns separator: %s", sep));
944 free(tb->colsep);
945 tb->colsep = p;
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 */
958 int scols_table_set_line_separator(struct libscols_table *tb, const char *sep)
959 {
960 char *p = NULL;
961
962 assert (tb);
963
964 if (!tb)
965 return -EINVAL;
966
967 if (sep) {
968 p = strdup(sep);
969 if (!p)
970 return -ENOMEM;
971 }
972
973 DBG(TAB, ul_debugobj(tb, "new lines separator: %s", sep));
974 free(tb->linesep);
975 tb->linesep = p;
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 */
985 char *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 */
1000 char *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 }
1009
1010 static 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 */
1037 int 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
1045 DBG(TAB, ul_debugobj(tb, "sorting table"));
1046 list_sort(&tb->tb_lines, cells_cmp_wrapper, cl);
1047 return 0;
1048 }