]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libsmartcols/src/column.c
8ebfa1ea27cb0d8e70faa21a330e411a39654b9b
2 * column.c - functions for table handling at the column level
4 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
5 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
14 * @short_description: defines output columns formats, headers, etc.
16 * An API to access and modify per-column data and information.
27 #include "smartcolsP.h"
32 * Allocates space for a new column.
34 * Returns: a pointer to a new struct libscols_column instance, NULL in case of an ENOMEM error.
36 struct libscols_column
*scols_new_column(void)
38 struct libscols_column
*cl
;
40 cl
= calloc(1, sizeof(*cl
));
43 DBG(COL
, ul_debugobj(cl
, "alloc"));
45 INIT_LIST_HEAD(&cl
->cl_columns
);
51 * @cl: a pointer to a struct libscols_column instance
53 * Increases the refcount of @cl.
55 void scols_ref_column(struct libscols_column
*cl
)
63 * @cl: a pointer to a struct libscols_column instance
65 * Decreases the refcount of @cl. When the count falls to zero, the instance
66 * is automatically deallocated.
68 void scols_unref_column(struct libscols_column
*cl
)
70 if (cl
&& --cl
->refcount
<= 0) {
71 DBG(COL
, ul_debugobj(cl
, "dealloc"));
72 list_del(&cl
->cl_columns
);
73 scols_reset_cell(&cl
->header
);
76 free(cl
->pending_data_buf
);
84 * @cl: a pointer to a struct libscols_column instance
86 * Creates a new column and copies @cl's data over to it.
88 * Returns: a pointer to a new struct libscols_column instance.
90 struct libscols_column
*scols_copy_column(const struct libscols_column
*cl
)
92 struct libscols_column
*ret
;
96 ret
= scols_new_column();
100 DBG(COL
, ul_debugobj(cl
, "copy"));
102 if (scols_column_set_color(ret
, cl
->color
))
104 if (scols_cell_copy_content(&ret
->header
, &cl
->header
))
107 ret
->width
= cl
->width
;
108 ret
->width_hint
= cl
->width_hint
;
109 ret
->flags
= cl
->flags
;
110 ret
->is_groups
= cl
->is_groups
;
112 memcpy(&ret
->wstat
, &cl
->wstat
, sizeof(cl
->wstat
));
116 scols_unref_column(ret
);
121 * scols_column_set_whint:
122 * @cl: a pointer to a struct libscols_column instance
123 * @whint: a width hint
125 * Sets the width hint of column @cl to @whint. See scols_table_new_column().
127 * Returns: 0, a negative value in case of an error.
129 int scols_column_set_whint(struct libscols_column
*cl
, double whint
)
134 cl
->width_hint
= whint
;
139 * scols_column_get_whint:
140 * @cl: a pointer to a struct libscols_column instance
142 * Returns: The width hint of column @cl, a negative value in case of an error.
144 double scols_column_get_whint(const struct libscols_column
*cl
)
146 return cl
->width_hint
;
150 * scols_column_set_flags:
151 * @cl: a pointer to a struct libscols_column instance
152 * @flags: a flag mask
154 * Sets the flags of @cl to @flags.
156 * Returns: 0, a negative value in case of an error.
158 int scols_column_set_flags(struct libscols_column
*cl
, int flags
)
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
--;
170 DBG(COL
, ul_debugobj(cl
, "setting flags from 0x%04x to 0x%04x", cl
->flags
, flags
));
176 * scols_column_set_json_type:
177 * @cl: a pointer to a struct libscols_column instance
178 * @type: SCOLS_JSON_* type
180 * Sets the type used for JSON formatting, the default is SCOLS_JSON_STRING.
182 * Returns: 0, a negative value in case of an error.
186 int scols_column_set_json_type(struct libscols_column
*cl
, int type
)
191 cl
->json_type
= type
;
197 * scols_column_get_json_type:
198 * @cl: a pointer to a struct libscols_column instance
200 * Note that SCOLS_JSON_BOOLEAN interprets NULL, empty strings, '0', 'N' and
201 * 'n' as "false"; and everything else as "true".
203 * Returns: JSON type used for formatting or a negative value in case of an error.
207 int scols_column_get_json_type(const struct libscols_column
*cl
)
209 return cl
? cl
->json_type
: -EINVAL
;
214 * scols_column_get_table:
215 * @cl: a pointer to a struct libscols_column instance
217 * Returns: pointer to the table where columns is used
219 struct libscols_table
*scols_column_get_table(const struct libscols_column
*cl
)
225 * scols_column_get_flags:
226 * @cl: a pointer to a struct libscols_column instance
228 * Returns: The flag mask of @cl, a negative value in case of an error.
230 int scols_column_get_flags(const struct libscols_column
*cl
)
236 * scols_column_get_header:
237 * @cl: a pointer to a struct libscols_column instance
239 * Returns: A pointer to a struct libscols_cell instance, representing the
240 * header info of column @cl or NULL in case of an error.
242 struct libscols_cell
*scols_column_get_header(struct libscols_column
*cl
)
248 * scols_column_set_name:
249 * @cl: a pointer to a struct libscols_column instance
252 * Returns: 0, a negative value in case of an error.
256 int scols_column_set_name(struct libscols_column
*cl
, const char *name
)
258 struct libscols_cell
*hr
= scols_column_get_header(cl
);
266 return scols_cell_set_data(hr
, name
);
270 * scols_column_get_name:
271 * @cl: a pointer to a struct libscols_column instance
273 * Returns: A pointer to a column name, which is stored in column header
277 const char *scols_column_get_name(struct libscols_column
*cl
)
279 return scols_cell_get_data(&cl
->header
);
283 * scols_column_get_name_as_shellvar
284 * @cl: a pointer to a struct libscols_column instance
286 * Like scols_column_get_name(), but column name is modified to be compatible with shells
287 * requirements for variable names.
291 const char *scols_column_get_name_as_shellvar(struct libscols_column
*cl
)
294 const char *s
, *name
= scols_column_get_name(cl
);
301 /* "1FOO%" --> "_1FOO_PCT */
302 sz
= strlen(name
) + 1 + 3;
303 p
= cl
->shellvar
= calloc(1, sz
+ 1);
307 /* convert "1FOO" to "_1FOO" */
311 /* replace all "bad" chars with "_" */
312 for (s
= name
; *s
; s
++)
313 *p
++ = !isalnum(*s
) ? '_' : *s
;
315 if (!*s
&& *(s
- 1) == '%') {
326 * scols_column_set_color:
327 * @cl: a pointer to a struct libscols_column instance
328 * @color: color name or ESC sequence
330 * The default color for data cells and column header.
332 * If you want to set header specific color then use scols_column_get_header()
333 * and scols_cell_set_color().
335 * If you want to set data cell specific color the use scols_line_get_cell() +
336 * scols_cell_set_color().
338 * Returns: 0, a negative value in case of an error.
340 int scols_column_set_color(struct libscols_column
*cl
, const char *color
)
342 if (color
&& isalpha(*color
)) {
343 color
= color_sequence_from_colorname(color
);
347 return strdup_to_struct_member(cl
, color
, color
);
351 * scols_column_get_color:
352 * @cl: a pointer to a struct libscols_column instance
354 * Returns: The current color setting of the column @cl.
356 const char *scols_column_get_color(const struct libscols_column
*cl
)
362 * scols_wrapnl_nextchunk:
363 * @cl: a pointer to a struct libscols_column instance
365 * @userdata: callback private data
367 * This is built-in function for scols_column_set_wrapfunc(). This function
368 * terminates the current chunk by \0 and returns pointer to the begin of
369 * the next chunk. The chunks are based on \n.
371 * For example for data "AAA\nBBB\nCCC" the next chunk is "BBB".
373 * Returns: next chunk
377 char *scols_wrapnl_nextchunk(const struct libscols_column
*cl
__attribute__((unused
)),
379 void *userdata
__attribute__((unused
)))
381 char *p
= data
? strchr(data
, '\n') : NULL
;
391 * scols_wrapnl_chunksize:
392 * @cl: a pointer to a struct libscols_column instance
394 * @userdata: callback private data
396 * Analyzes @data and returns size of the largest chunk. The chunks are based
397 * on \n. For example for data "AAA\nBBB\nCCCC" the largest chunk size is 4.
399 * Note that the size has to be based on number of terminal cells rather than
400 * bytes to support multu-byte output.
402 * Returns: size of the largest chunk.
406 size_t scols_wrapnl_chunksize(const struct libscols_column
*cl
__attribute__((unused
)),
408 void *userdata
__attribute__((unused
)))
412 while (data
&& *data
) {
416 p
= strchr(data
, '\n');
418 sz
= cl
->table
&& scols_table_is_noencoding(cl
->table
) ?
419 mbs_nwidth(data
, p
- data
) :
420 mbs_safe_nwidth(data
, p
- data
, NULL
);
423 sz
= cl
->table
&& scols_table_is_noencoding(cl
->table
) ?
425 mbs_safe_width(data
);
435 * scols_column_set_cmpfunc:
437 * @cmp: pointer to compare function
438 * @data: private data for cmp function
440 * Returns: 0, a negative value in case of an error.
442 int scols_column_set_cmpfunc(struct libscols_column
*cl
,
443 int (*cmp
)(struct libscols_cell
*,
444 struct libscols_cell
*,
452 cl
->cmpfunc_data
= data
;
457 * scols_column_set_wrapfunc:
458 * @cl: a pointer to a struct libscols_column instance
459 * @wrap_chunksize: function to return size of the largest chink of data
460 * @wrap_nextchunk: function to return next zero terminated data
461 * @userdata: optional stuff for callbacks
463 * Extends SCOLS_FL_WRAP and can be used to set custom wrap function. The default
464 * is to wrap by column size, but you can create functions to wrap for example
465 * after \n or after words, etc.
467 * Returns: 0, a negative value in case of an error.
471 int scols_column_set_wrapfunc(struct libscols_column
*cl
,
472 size_t (*wrap_chunksize
)(const struct libscols_column
*,
475 char * (*wrap_nextchunk
)(const struct libscols_column
*,
483 cl
->wrap_nextchunk
= wrap_nextchunk
;
484 cl
->wrap_chunksize
= wrap_chunksize
;
485 cl
->wrapfunc_data
= userdata
;
490 * scols_column_set_safechars:
491 * @cl: a pointer to a struct libscols_column instance
492 * @safe: safe characters (e.g. "\n\t")
494 * Use for bytes you don't want to encode on output. This is for example
495 * necessary if you want to use custom wrap function based on \n, in this case
496 * you have to set "\n" as a safe char.
498 * Returns: 0, a negative value in case of an error.
502 int scols_column_set_safechars(struct libscols_column
*cl
, const char *safe
)
504 return strdup_to_struct_member(cl
, safechars
, safe
);
508 * scols_column_get_safechars:
509 * @cl: a pointer to a struct libscols_column instance
511 * Returns: safe chars
515 const char *scols_column_get_safechars(const struct libscols_column
*cl
)
517 return cl
->safechars
;
521 * scols_column_get_width:
522 * @cl: a pointer to a struct libscols_column instance
524 * Important note: the column width is unknown until library starts printing
525 * (width is calculated before printing). The function is usable for example in
526 * nextchunk() callback specified by scols_column_set_wrapfunc().
528 * See also scols_column_get_whint(), it returns wanted size (!= final size).
530 * Returns: column width
534 size_t scols_column_get_width(const struct libscols_column
*cl
)
540 * scols_column_is_hidden:
541 * @cl: a pointer to a struct libscols_column instance
543 * Gets the value of @cl's flag hidden.
549 int scols_column_is_hidden(const struct libscols_column
*cl
)
551 return cl
->flags
& SCOLS_FL_HIDDEN
? 1 : 0;
555 * scols_column_is_trunc:
556 * @cl: a pointer to a struct libscols_column instance
558 * Gets the value of @cl's flag trunc.
562 int scols_column_is_trunc(const struct libscols_column
*cl
)
564 return cl
->flags
& SCOLS_FL_TRUNC
? 1 : 0;
567 * scols_column_is_tree:
568 * @cl: a pointer to a struct libscols_column instance
570 * Gets the value of @cl's flag tree.
574 int scols_column_is_tree(const struct libscols_column
*cl
)
576 return cl
->flags
& SCOLS_FL_TREE
? 1 : 0;
579 * scols_column_is_right:
580 * @cl: a pointer to a struct libscols_column instance
582 * Gets the value of @cl's flag right.
586 int scols_column_is_right(const struct libscols_column
*cl
)
588 return cl
->flags
& SCOLS_FL_RIGHT
? 1 : 0;
591 * scols_column_is_strict_width:
592 * @cl: a pointer to a struct libscols_column instance
594 * Gets the value of @cl's flag strict_width.
598 int scols_column_is_strict_width(const struct libscols_column
*cl
)
600 return cl
->flags
& SCOLS_FL_STRICTWIDTH
? 1 : 0;
603 * scols_column_is_noextremes:
604 * @cl: a pointer to a struct libscols_column instance
606 * Gets the value of @cl's flag no_extremes.
610 int scols_column_is_noextremes(const struct libscols_column
*cl
)
612 return cl
->flags
& SCOLS_FL_NOEXTREMES
? 1 : 0;
615 * scols_column_is_wrap:
616 * @cl: a pointer to a struct libscols_column instance
618 * Gets the value of @cl's flag wrap.
624 int scols_column_is_wrap(const struct libscols_column
*cl
)
626 return cl
->flags
& SCOLS_FL_WRAP
? 1 : 0;
629 * scols_column_is_customwrap:
630 * @cl: a pointer to a struct libscols_column instance
636 int scols_column_is_customwrap(const struct libscols_column
*cl
)
638 return (cl
->flags
& SCOLS_FL_WRAP
)
639 && cl
->wrap_chunksize
640 && cl
->wrap_nextchunk
? 1 : 0;
644 * scols_column_set_properties:
645 * @cl: a pointer to a struct libscols_column instance
646 * @opts: options string
648 * Set properties from string, the string is comma seprated list, like
649 * "trunc,right,json=number", ...
651 * Returns: 0 on success, <0 on error
655 int scols_column_set_properties(struct libscols_column
*cl
, const char *opts
)
657 char *str
= (char *) opts
;
659 size_t namesz
, valuesz
;
660 unsigned int flags
= 0;
663 DBG(COL
, ul_debugobj(cl
, "apply properties '%s'", opts
));
666 && !ul_optstr_next(&str
, &name
, &namesz
, &value
, &valuesz
)) {
668 if (strncmp(name
, "trunc", namesz
) == 0)
669 flags
|= SCOLS_FL_TRUNC
;
671 else if (strncmp(name
, "tree", namesz
) == 0)
672 flags
|= SCOLS_FL_TREE
;
674 else if (strncmp(name
, "right", namesz
) == 0)
675 flags
|= SCOLS_FL_RIGHT
;
677 else if (strncmp(name
, "strictwidth", namesz
) == 0)
678 flags
|= SCOLS_FL_STRICTWIDTH
;
680 else if (strncmp(name
, "noextremes", namesz
) == 0)
681 flags
|= SCOLS_FL_STRICTWIDTH
;
683 else if (strncmp(name
, "hidden", namesz
) == 0)
684 flags
|= SCOLS_FL_HIDDEN
;
686 else if (strncmp(name
, "wrap", namesz
) == 0)
687 flags
|= SCOLS_FL_WRAP
;
689 else if (value
&& strncmp(name
, "json", namesz
) == 0) {
691 if (strncmp(value
, "string", valuesz
) == 0)
692 rc
= scols_column_set_json_type(cl
, SCOLS_JSON_STRING
);
693 else if (strncmp(value
, "number", valuesz
) == 0)
694 rc
= scols_column_set_json_type(cl
, SCOLS_JSON_NUMBER
);
695 else if (strncmp(value
, "array-string", valuesz
) == 0)
696 rc
= scols_column_set_json_type(cl
, SCOLS_JSON_ARRAY_STRING
);
697 else if (strncmp(value
, "array-number", valuesz
) == 0)
698 rc
= scols_column_set_json_type(cl
, SCOLS_JSON_ARRAY_NUMBER
);
699 else if (strncmp(value
, "boolean", valuesz
) == 0)
700 rc
= scols_column_set_json_type(cl
, SCOLS_JSON_BOOLEAN
);
702 } else if (value
&& strncmp(name
, "width", namesz
) == 0) {
705 double x
= strtod(value
, &end
);
706 if (errno
|| str
== end
)
709 rc
= scols_column_set_whint(cl
, x
);
711 } else if (value
&& strncmp(name
, "color", namesz
) == 0) {
713 char *x
= strndup(value
, valuesz
);
715 scols_column_set_color(cl
, x
);
719 } else if (value
&& strncmp(name
, "name", namesz
) == 0) {
721 char *x
= strndup(value
, valuesz
);
723 scols_column_set_name(cl
, x
);
730 rc
= scols_column_set_flags(cl
, flags
);