]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libsmartcols/src/column.c
libsmartcols: improve JSON support (add types)
[thirdparty/util-linux.git] / libsmartcols / src / column.c
CommitLineData
1577b259
KZ
1/*
2 * column.c - functions for table handling at the column level
3 *
4 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
5 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
6 *
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
9 */
10
1d90bcb1
OO
11/**
12 * SECTION: column
13 * @title: Column
2473b711 14 * @short_description: defines output columns formats, headers, etc.
1d90bcb1
OO
15 *
16 * An API to access and modify per-column data and information.
17 */
18
ce44112b 19
1577b259
KZ
20#include <stdlib.h>
21#include <unistd.h>
22#include <string.h>
35958d0c 23#include <ctype.h>
1577b259 24
949ea05f
KZ
25#include "mbsalign.h"
26
1577b259
KZ
27#include "smartcolsP.h"
28
1d90bcb1
OO
29/**
30 * scols_new_column:
31 *
32 * Allocates space for a new column.
33 *
bfc6941a 34 * Returns: a pointer to a new struct libscols_column instance, NULL in case of an ENOMEM error.
1d90bcb1 35 */
1577b259
KZ
36struct libscols_column *scols_new_column(void)
37{
38 struct libscols_column *cl;
39
40 cl = calloc(1, sizeof(*cl));
41 if (!cl)
42 return NULL;
710ed55d 43 DBG(COL, ul_debugobj(cl, "alloc"));
1577b259
KZ
44 cl->refcount = 1;
45 INIT_LIST_HEAD(&cl->cl_columns);
46 return cl;
47}
48
1d90bcb1
OO
49/**
50 * scols_ref_column:
51 * @cl: a pointer to a struct libscols_column instance
52 *
53 * Increases the refcount of @cl.
54 */
1577b259
KZ
55void scols_ref_column(struct libscols_column *cl)
56{
57 if (cl)
58 cl->refcount++;
59}
60
1d90bcb1
OO
61/**
62 * scols_unref_column:
63 * @cl: a pointer to a struct libscols_column instance
64 *
3175f035
KZ
65 * Decreases the refcount of @cl. When the count falls to zero, the instance
66 * is automatically deallocated.
1d90bcb1 67 */
1577b259
KZ
68void scols_unref_column(struct libscols_column *cl)
69{
70 if (cl && --cl->refcount <= 0) {
710ed55d 71 DBG(COL, ul_debugobj(cl, "dealloc"));
1577b259
KZ
72 list_del(&cl->cl_columns);
73 scols_reset_cell(&cl->header);
74 free(cl->color);
68a7f92b 75 free(cl->safechars);
d94c5198 76 free(cl->pending_data_buf);
1577b259
KZ
77 free(cl);
78 }
79}
80
1d90bcb1
OO
81/**
82 * scols_copy_column:
83 * @cl: a pointer to a struct libscols_column instance
84 *
710ed55d 85 * Creates a new column and copies @cl's data over to it.
1d90bcb1
OO
86 *
87 * Returns: a pointer to a new struct libscols_column instance.
88 */
1577b259
KZ
89struct libscols_column *scols_copy_column(const struct libscols_column *cl)
90{
91 struct libscols_column *ret;
92
1577b259
KZ
93 if (!cl)
94 return NULL;
95 ret = scols_new_column();
96 if (!ret)
97 return NULL;
1577b259 98
63c9c05d 99 DBG(COL, ul_debugobj(cl, "copy"));
710ed55d 100
74bd28ad 101 if (scols_column_set_color(ret, cl->color))
1577b259 102 goto err;
74bd28ad 103 if (scols_cell_copy_content(&ret->header, &cl->header))
1577b259
KZ
104 goto err;
105
106 ret->width = cl->width;
107 ret->width_min = cl->width_min;
108 ret->width_max = cl->width_max;
109 ret->width_avg = cl->width_avg;
110 ret->width_hint = cl->width_hint;
8b992cb5 111 ret->flags = cl->flags;
1577b259
KZ
112 ret->is_extreme = cl->is_extreme;
113
114 return ret;
115err:
116 scols_unref_column(ret);
117 return NULL;
118}
119
1d90bcb1
OO
120/**
121 * scols_column_set_whint:
122 * @cl: a pointer to a struct libscols_column instance
123 * @whint: a width hint
124 *
cbe3e495 125 * Sets the width hint of column @cl to @whint. See scols_table_new_column().
1d90bcb1
OO
126 *
127 * Returns: 0, a negative value in case of an error.
128 */
1577b259
KZ
129int scols_column_set_whint(struct libscols_column *cl, double whint)
130{
1577b259
KZ
131 if (!cl)
132 return -EINVAL;
133
134 cl->width_hint = whint;
135 return 0;
136}
137
1d90bcb1
OO
138/**
139 * scols_column_get_whint:
140 * @cl: a pointer to a struct libscols_column instance
141 *
142 * Returns: The width hint of column @cl, a negative value in case of an error.
143 */
f7a9ea28 144double scols_column_get_whint(const struct libscols_column *cl)
1577b259 145{
d4275a4b 146 return cl->width_hint;
1577b259
KZ
147}
148
1d90bcb1
OO
149/**
150 * scols_column_set_flags:
151 * @cl: a pointer to a struct libscols_column instance
152 * @flags: a flag mask
153 *
154 * Sets the flags of @cl to @flags.
155 *
156 * Returns: 0, a negative value in case of an error.
157 */
8b992cb5
OO
158int scols_column_set_flags(struct libscols_column *cl, int flags)
159{
8b992cb5
OO
160 if (!cl)
161 return -EINVAL;
162
d10fa7e6
IG
163 if (cl->table) {
164 if (!(cl->flags & SCOLS_FL_TREE) && (flags & SCOLS_FL_TREE))
165 cl->table->ntreecols++;
166 else if ((cl->flags & SCOLS_FL_TREE) && !(flags & SCOLS_FL_TREE))
167 cl->table->ntreecols--;
168 }
169
8b992cb5
OO
170 cl->flags = flags;
171 return 0;
172}
173
b2c871f9
KZ
174/**
175 * scols_column_set_json_type:
176 * @cl: a pointer to a struct libscols_column instance
177 * @type: SCOLS_JSON_* type
178 *
179 * Sets the type used for JSON formatting, the default is SCOLS_JSON_STRING.
180 *
181 * Returns: 0, a negative value in case of an error.
182 *
183 * Since: 2.33
184 */
185int scols_column_set_json_type(struct libscols_column *cl, int type)
186{
187 if (!cl)
188 return -EINVAL;
189
190 cl->json_type = type;
191 return 0;
192
193}
194
195/**
196 * scols_column_get_json_type:
197 * @cl: a pointer to a struct libscols_column instance
198 *
199 * Note that SCOLS_JSON_BOOLEAN interprets NULL, empty strings, '0', 'N' and
200 * 'n' as "false"; and everything else as "true".
201 *
202 * Returns: JSON type used for formatting or a negative value in case of an error.
203 *
204 * Since: 2.33
205 */
206int scols_column_get_json_type(const struct libscols_column *cl)
207{
208 return cl ? cl->json_type : -EINVAL;
209}
210
211
949ea05f
KZ
212/**
213 * scols_column_get_table:
214 * @cl: a pointer to a struct libscols_column instance
215 *
216 * Returns: pointer to the table where columns is used
217 */
68a7f92b 218struct libscols_table *scols_column_get_table(const struct libscols_column *cl)
949ea05f
KZ
219{
220 return cl->table;
221}
222
1d90bcb1
OO
223/**
224 * scols_column_get_flags:
225 * @cl: a pointer to a struct libscols_column instance
226 *
227 * Returns: The flag mask of @cl, a negative value in case of an error.
228 */
f7a9ea28 229int scols_column_get_flags(const struct libscols_column *cl)
8b992cb5 230{
d4275a4b 231 return cl->flags;
8b992cb5
OO
232}
233
1d90bcb1 234/**
e2310281 235 * scols_column_get_header:
1d90bcb1
OO
236 * @cl: a pointer to a struct libscols_column instance
237 *
238 * Returns: A pointer to a struct libscols_cell instance, representing the
239 * header info of column @cl or NULL in case of an error.
240 */
74bd28ad 241struct libscols_cell *scols_column_get_header(struct libscols_column *cl)
1577b259 242{
d4275a4b 243 return &cl->header;
1577b259
KZ
244}
245
1d90bcb1
OO
246/**
247 * scols_column_set_color:
248 * @cl: a pointer to a struct libscols_column instance
618a1d6d 249 * @color: color name or ESC sequence
1d90bcb1 250 *
1577b259
KZ
251 * The default color for data cells and column header.
252 *
253 * If you want to set header specific color then use scols_column_get_header()
254 * and scols_cell_set_color().
255 *
256 * If you want to set data cell specific color the use scols_line_get_cell() +
257 * scols_cell_set_color().
1d90bcb1
OO
258 *
259 * Returns: 0, a negative value in case of an error.
1577b259 260 */
618a1d6d 261int scols_column_set_color(struct libscols_column *cl, const char *color)
1577b259 262{
618a1d6d
IG
263 if (color && isalpha(*color)) {
264 color = color_sequence_from_colorname(color);
265 if (!color)
8fcdce8f 266 return -EINVAL;
1577b259 267 }
618a1d6d 268 return strdup_to_struct_member(cl, color, color);
1577b259
KZ
269}
270
1d90bcb1
OO
271/**
272 * scols_column_get_color:
273 * @cl: a pointer to a struct libscols_column instance
274 *
275 * Returns: The current color setting of the column @cl.
276 */
f7a9ea28 277const char *scols_column_get_color(const struct libscols_column *cl)
1577b259 278{
d4275a4b 279 return cl->color;
1577b259
KZ
280}
281
949ea05f
KZ
282/**
283 * scols_wrapnl_nextchunk:
284 * @cl: a pointer to a struct libscols_column instance
285 * @data: string
81b176c4 286 * @userdata: callback private data
949ea05f 287 *
68a7f92b 288 * This is built-in function for scols_column_set_wrapfunc(). This function
949ea05f
KZ
289 * terminates the current chunk by \0 and returns pointer to the begin of
290 * the next chunk. The chunks are based on \n.
291 *
292 * For example for data "AAA\nBBB\nCCC" the next chunk is "BBB".
293 *
294 * Returns: next chunk
3f47320a
KZ
295 *
296 * Since: 2.29
949ea05f
KZ
297 */
298char *scols_wrapnl_nextchunk(const struct libscols_column *cl __attribute__((unused)),
299 char *data,
300 void *userdata __attribute__((unused)))
301{
302 char *p = data ? strchr(data, '\n') : NULL;
303
304 if (p) {
305 *p = '\0';
306 return p + 1;
307 }
308 return NULL;
309}
310
311/**
312 * scols_wrapnl_chunksize:
313 * @cl: a pointer to a struct libscols_column instance
314 * @data: string
81b176c4 315 * @userdata: callback private data
949ea05f
KZ
316 *
317 * Analyzes @data and returns size of the largest chunk. The chunks are based
318 * on \n. For example for data "AAA\nBBB\nCCCC" the largest chunk size is 4.
319 *
320 * Note that the size has to be based on number of terminal cells rather than
321 * bytes to support multu-byte output.
322 *
323 * Returns: size of the largest chunk.
3f47320a
KZ
324 *
325 * Since: 2.29
949ea05f
KZ
326 */
327size_t scols_wrapnl_chunksize(const struct libscols_column *cl __attribute__((unused)),
328 const char *data,
329 void *userdata __attribute__((unused)))
330{
331 size_t sum = 0;
332
333 while (data && *data) {
1b504263 334 const char *p;
949ea05f
KZ
335 size_t sz;
336
337 p = strchr(data, '\n');
338 if (p) {
339 sz = mbs_safe_nwidth(data, p - data, NULL);
340 p++;
341 } else
342 sz = mbs_safe_width(data);
343
344 sum = max(sum, sz);
f4d37838 345 data = p;
949ea05f
KZ
346 }
347
348 return sum;
349}
57a86f9b
KZ
350
351/**
352 * scols_column_set_cmpfunc:
353 * @cl: column
354 * @cmp: pointer to compare function
355 * @data: private data for cmp function
356 *
357 * Returns: 0, a negative value in case of an error.
358 */
359int scols_column_set_cmpfunc(struct libscols_column *cl,
360 int (*cmp)(struct libscols_cell *,
361 struct libscols_cell *,
362 void *),
363 void *data)
364{
57a86f9b
KZ
365 if (!cl)
366 return -EINVAL;
367
368 cl->cmpfunc = cmp;
369 cl->cmpfunc_data = data;
370 return 0;
371}
372
949ea05f
KZ
373/**
374 * scols_column_set_wrapfunc:
375 * @cl: a pointer to a struct libscols_column instance
376 * @wrap_chunksize: function to return size of the largest chink of data
377 * @wrap_nextchunk: function to return next zero terminated data
81b176c4 378 * @userdata: optional stuff for callbacks
949ea05f
KZ
379 *
380 * Extends SCOLS_FL_WRAP and allows to set custom wrap function. The default
381 * is to wrap by column size, but you can create functions to wrap for example
382 * after \n or after words, etc.
383 *
384 * Returns: 0, a negative value in case of an error.
3f47320a
KZ
385 *
386 * Since: 2.29
949ea05f
KZ
387 */
388int scols_column_set_wrapfunc(struct libscols_column *cl,
389 size_t (*wrap_chunksize)(const struct libscols_column *,
390 const char *,
391 void *),
392 char * (*wrap_nextchunk)(const struct libscols_column *,
393 char *,
394 void *),
81b176c4 395 void *userdata)
949ea05f
KZ
396{
397 if (!cl)
398 return -EINVAL;
399
400 cl->wrap_nextchunk = wrap_nextchunk;
401 cl->wrap_chunksize = wrap_chunksize;
81b176c4 402 cl->wrapfunc_data = userdata;
949ea05f
KZ
403 return 0;
404}
405
406/**
407 * scols_column_set_safechars:
408 * @cl: a pointer to a struct libscols_column instance
409 * @safe: safe characters (e.g. "\n\t")
410 *
411 * Use for bytes you don't want to encode on output. This is for example
412 * necessary if you want to use custom wrap function based on \n, in this case
413 * you have to set "\n" as a safe char.
414 *
415 * Returns: 0, a negative value in case of an error.
3f47320a
KZ
416 *
417 * Since: 2.29
949ea05f
KZ
418 */
419int scols_column_set_safechars(struct libscols_column *cl, const char *safe)
420{
68a7f92b 421 return strdup_to_struct_member(cl, safechars, safe);
949ea05f
KZ
422}
423
424/**
425 * scols_column_get_safechars:
426 * @cl: a pointer to a struct libscols_column instance
427 *
428 * Returns: safe chars
3f47320a
KZ
429 *
430 * Since: 2.29
949ea05f
KZ
431 */
432const char *scols_column_get_safechars(const struct libscols_column *cl)
433{
434 return cl->safechars;
435}
436
82053f5e
KZ
437/**
438 * scols_column_get_width:
439 * @cl: a pointer to a struct libscols_column instance
440 *
441 * Important note: the column width is unknown until library starts printing
442 * (width is calculated before printing). The function is usable for example in
443 * nextchunk() callback specified by scols_column_set_wrapfunc().
444 *
445 * See also scols_column_get_whint(), it returns wanted size (!= final size).
446 *
447 * Returns: column width
448 *
449 * Since: 2.29
450 */
451size_t scols_column_get_width(const struct libscols_column *cl)
452{
453 return cl->width;
454}
455
6d6b6d18
KZ
456/**
457 * scols_column_is_hidden:
458 * @cl: a pointer to a struct libscols_column instance
459 *
460 * Gets the value of @cl's flag hidden.
461 *
d4275a4b 462 * Returns: 0 or 1
982034c3
KZ
463 *
464 * Since: 2.27
6d6b6d18 465 */
f7a9ea28 466int scols_column_is_hidden(const struct libscols_column *cl)
6d6b6d18 467{
d4275a4b 468 return cl->flags & SCOLS_FL_HIDDEN ? 1 : 0;
6d6b6d18
KZ
469}
470
8a38a8d3
OO
471/**
472 * scols_column_is_trunc:
1d90bcb1 473 * @cl: a pointer to a struct libscols_column instance
8a38a8d3 474 *
1d90bcb1 475 * Gets the value of @cl's flag trunc.
8a38a8d3 476 *
d4275a4b 477 * Returns: 0 or 1
8a38a8d3 478 */
f7a9ea28 479int scols_column_is_trunc(const struct libscols_column *cl)
8a38a8d3 480{
d4275a4b 481 return cl->flags & SCOLS_FL_TRUNC ? 1 : 0;
8a38a8d3
OO
482}
483/**
484 * scols_column_is_tree:
1d90bcb1 485 * @cl: a pointer to a struct libscols_column instance
8a38a8d3 486 *
1d90bcb1 487 * Gets the value of @cl's flag tree.
8a38a8d3 488 *
d4275a4b 489 * Returns: 0 or 1
8a38a8d3 490 */
f7a9ea28 491int scols_column_is_tree(const struct libscols_column *cl)
8a38a8d3 492{
d4275a4b 493 return cl->flags & SCOLS_FL_TREE ? 1 : 0;
8a38a8d3
OO
494}
495/**
496 * scols_column_is_right:
1d90bcb1 497 * @cl: a pointer to a struct libscols_column instance
8a38a8d3 498 *
1d90bcb1 499 * Gets the value of @cl's flag right.
8a38a8d3 500 *
d4275a4b 501 * Returns: 0 or 1
8a38a8d3 502 */
f7a9ea28 503int scols_column_is_right(const struct libscols_column *cl)
8a38a8d3 504{
d4275a4b 505 return cl->flags & SCOLS_FL_RIGHT ? 1 : 0;
8a38a8d3
OO
506}
507/**
508 * scols_column_is_strict_width:
1d90bcb1 509 * @cl: a pointer to a struct libscols_column instance
8a38a8d3 510 *
1d90bcb1 511 * Gets the value of @cl's flag strict_width.
8a38a8d3 512 *
d4275a4b 513 * Returns: 0 or 1
8a38a8d3 514 */
f7a9ea28 515int scols_column_is_strict_width(const struct libscols_column *cl)
8a38a8d3 516{
d4275a4b 517 return cl->flags & SCOLS_FL_STRICTWIDTH ? 1 : 0;
8a38a8d3
OO
518}
519/**
0925a9dd 520 * scols_column_is_noextremes:
1d90bcb1 521 * @cl: a pointer to a struct libscols_column instance
8a38a8d3 522 *
1d90bcb1 523 * Gets the value of @cl's flag no_extremes.
8a38a8d3 524 *
d4275a4b 525 * Returns: 0 or 1
8a38a8d3 526 */
f7a9ea28 527int scols_column_is_noextremes(const struct libscols_column *cl)
8a38a8d3 528{
d4275a4b 529 return cl->flags & SCOLS_FL_NOEXTREMES ? 1 : 0;
8a38a8d3 530}
a6404093
IG
531/**
532 * scols_column_is_wrap:
533 * @cl: a pointer to a struct libscols_column instance
534 *
535 * Gets the value of @cl's flag wrap.
536 *
d4275a4b 537 * Returns: 0 or 1
2f09ae9d
KZ
538 *
539 * Since: 2.28
a6404093 540 */
f7a9ea28 541int scols_column_is_wrap(const struct libscols_column *cl)
a6404093 542{
d4275a4b 543 return cl->flags & SCOLS_FL_WRAP ? 1 : 0;
a6404093 544}
ff471d89 545/**
949ea05f 546 * scols_column_is_customwrap:
ff471d89
KZ
547 * @cl: a pointer to a struct libscols_column instance
548 *
d4275a4b 549 * Returns: 0 or 1
ff471d89
KZ
550 *
551 * Since: 2.29
552 */
949ea05f 553int scols_column_is_customwrap(const struct libscols_column *cl)
ff471d89 554{
949ea05f
KZ
555 return (cl->flags & SCOLS_FL_WRAP)
556 && cl->wrap_chunksize
557 && cl->wrap_nextchunk ? 1 : 0;
ff471d89 558}