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