blob: e9d6dc4041590af3f2c935e93684bb2efdfea0c1 [file] [log] [blame]
/*
* column.c - functions for table handling at the column level
*
* Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
* Copyright (C) 2014 Karel Zak <kzak@redhat.com>
*
* This file may be redistributed under the terms of the
* GNU Lesser General Public License.
*/
/**
* SECTION: column
* @title: Column
* @short_description: defines output columns formats, headers, etc.
*
* An API to access and modify per-column data and information.
*/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include "mbsalign.h"
#include "smartcolsP.h"
/**
* scols_new_column:
*
* Allocates space for a new column.
*
* Returns: a pointer to a new struct libscols_column instance, NULL in case of an ENOMEM error.
*/
struct libscols_column *scols_new_column(void)
{
struct libscols_column *cl;
cl = calloc(1, sizeof(*cl));
if (!cl)
return NULL;
DBG(COL, ul_debugobj(cl, "alloc"));
cl->refcount = 1;
INIT_LIST_HEAD(&cl->cl_columns);
return cl;
}
/**
* scols_ref_column:
* @cl: a pointer to a struct libscols_column instance
*
* Increases the refcount of @cl.
*/
void scols_ref_column(struct libscols_column *cl)
{
if (cl)
cl->refcount++;
}
/**
* scols_unref_column:
* @cl: a pointer to a struct libscols_column instance
*
* Decreases the refcount of @cl. When the count falls to zero, the instance
* is automatically deallocated.
*/
void scols_unref_column(struct libscols_column *cl)
{
if (cl && --cl->refcount <= 0) {
DBG(COL, ul_debugobj(cl, "dealloc"));
list_del(&cl->cl_columns);
scols_reset_cell(&cl->header);
free(cl->color);
free(cl->safechars);
free(cl->pending_data_buf);
free(cl);
}
}
/**
* scols_copy_column:
* @cl: a pointer to a struct libscols_column instance
*
* Creates a new column and copies @cl's data over to it.
*
* Returns: a pointer to a new struct libscols_column instance.
*/
struct libscols_column *scols_copy_column(const struct libscols_column *cl)
{
struct libscols_column *ret;
if (!cl)
return NULL;
ret = scols_new_column();
if (!ret)
return NULL;
DBG(COL, ul_debugobj(cl, "copy"));
if (scols_column_set_color(ret, cl->color))
goto err;
if (scols_cell_copy_content(&ret->header, &cl->header))
goto err;
ret->width = cl->width;
ret->width_min = cl->width_min;
ret->width_max = cl->width_max;
ret->width_avg = cl->width_avg;
ret->width_hint = cl->width_hint;
ret->flags = cl->flags;
ret->is_extreme = cl->is_extreme;
return ret;
err:
scols_unref_column(ret);
return NULL;
}
/**
* scols_column_set_whint:
* @cl: a pointer to a struct libscols_column instance
* @whint: a width hint
*
* Sets the width hint of column @cl to @whint. See scols_table_new_column().
*
* Returns: 0, a negative value in case of an error.
*/
int scols_column_set_whint(struct libscols_column *cl, double whint)
{
if (!cl)
return -EINVAL;
cl->width_hint = whint;
return 0;
}
/**
* scols_column_get_whint:
* @cl: a pointer to a struct libscols_column instance
*
* Returns: The width hint of column @cl, a negative value in case of an error.
*/
double scols_column_get_whint(const struct libscols_column *cl)
{
return cl->width_hint;
}
/**
* scols_column_set_flags:
* @cl: a pointer to a struct libscols_column instance
* @flags: a flag mask
*
* Sets the flags of @cl to @flags.
*
* Returns: 0, a negative value in case of an error.
*/
int scols_column_set_flags(struct libscols_column *cl, int flags)
{
if (!cl)
return -EINVAL;
if (cl->table) {
if (!(cl->flags & SCOLS_FL_TREE) && (flags & SCOLS_FL_TREE))
cl->table->ntreecols++;
else if ((cl->flags & SCOLS_FL_TREE) && !(flags & SCOLS_FL_TREE))
cl->table->ntreecols--;
}
cl->flags = flags;
return 0;
}
/**
* scols_column_set_json_type:
* @cl: a pointer to a struct libscols_column instance
* @type: SCOLS_JSON_* type
*
* Sets the type used for JSON formatting, the default is SCOLS_JSON_STRING.
*
* Returns: 0, a negative value in case of an error.
*
* Since: 2.33
*/
int scols_column_set_json_type(struct libscols_column *cl, int type)
{
if (!cl)
return -EINVAL;
cl->json_type = type;
return 0;
}
/**
* scols_column_get_json_type:
* @cl: a pointer to a struct libscols_column instance
*
* Note that SCOLS_JSON_BOOLEAN interprets NULL, empty strings, '0', 'N' and
* 'n' as "false"; and everything else as "true".
*
* Returns: JSON type used for formatting or a negative value in case of an error.
*
* Since: 2.33
*/
int scols_column_get_json_type(const struct libscols_column *cl)
{
return cl ? cl->json_type : -EINVAL;
}
/**
* scols_column_get_table:
* @cl: a pointer to a struct libscols_column instance
*
* Returns: pointer to the table where columns is used
*/
struct libscols_table *scols_column_get_table(const struct libscols_column *cl)
{
return cl->table;
}
/**
* scols_column_get_flags:
* @cl: a pointer to a struct libscols_column instance
*
* Returns: The flag mask of @cl, a negative value in case of an error.
*/
int scols_column_get_flags(const struct libscols_column *cl)
{
return cl->flags;
}
/**
* scols_column_get_header:
* @cl: a pointer to a struct libscols_column instance
*
* Returns: A pointer to a struct libscols_cell instance, representing the
* header info of column @cl or NULL in case of an error.
*/
struct libscols_cell *scols_column_get_header(struct libscols_column *cl)
{
return &cl->header;
}
/**
* scols_column_set_color:
* @cl: a pointer to a struct libscols_column instance
* @color: color name or ESC sequence
*
* The default color for data cells and column header.
*
* If you want to set header specific color then use scols_column_get_header()
* and scols_cell_set_color().
*
* If you want to set data cell specific color the use scols_line_get_cell() +
* scols_cell_set_color().
*
* Returns: 0, a negative value in case of an error.
*/
int scols_column_set_color(struct libscols_column *cl, const char *color)
{
if (color && isalpha(*color)) {
color = color_sequence_from_colorname(color);
if (!color)
return -EINVAL;
}
return strdup_to_struct_member(cl, color, color);
}
/**
* scols_column_get_color:
* @cl: a pointer to a struct libscols_column instance
*
* Returns: The current color setting of the column @cl.
*/
const char *scols_column_get_color(const struct libscols_column *cl)
{
return cl->color;
}
/**
* scols_wrapnl_nextchunk:
* @cl: a pointer to a struct libscols_column instance
* @data: string
* @userdata: callback private data
*
* This is built-in function for scols_column_set_wrapfunc(). This function
* terminates the current chunk by \0 and returns pointer to the begin of
* the next chunk. The chunks are based on \n.
*
* For example for data "AAA\nBBB\nCCC" the next chunk is "BBB".
*
* Returns: next chunk
*
* Since: 2.29
*/
char *scols_wrapnl_nextchunk(const struct libscols_column *cl __attribute__((unused)),
char *data,
void *userdata __attribute__((unused)))
{
char *p = data ? strchr(data, '\n') : NULL;
if (p) {
*p = '\0';
return p + 1;
}
return NULL;
}
/**
* scols_wrapnl_chunksize:
* @cl: a pointer to a struct libscols_column instance
* @data: string
* @userdata: callback private data
*
* Analyzes @data and returns size of the largest chunk. The chunks are based
* on \n. For example for data "AAA\nBBB\nCCCC" the largest chunk size is 4.
*
* Note that the size has to be based on number of terminal cells rather than
* bytes to support multu-byte output.
*
* Returns: size of the largest chunk.
*
* Since: 2.29
*/
size_t scols_wrapnl_chunksize(const struct libscols_column *cl __attribute__((unused)),
const char *data,
void *userdata __attribute__((unused)))
{
size_t sum = 0;
while (data && *data) {
const char *p;
size_t sz;
p = strchr(data, '\n');
if (p) {
sz = mbs_safe_nwidth(data, p - data, NULL);
p++;
} else
sz = mbs_safe_width(data);
sum = max(sum, sz);
data = p;
}
return sum;
}
/**
* scols_column_set_cmpfunc:
* @cl: column
* @cmp: pointer to compare function
* @data: private data for cmp function
*
* Returns: 0, a negative value in case of an error.
*/
int scols_column_set_cmpfunc(struct libscols_column *cl,
int (*cmp)(struct libscols_cell *,
struct libscols_cell *,
void *),
void *data)
{
if (!cl)
return -EINVAL;
cl->cmpfunc = cmp;
cl->cmpfunc_data = data;
return 0;
}
/**
* scols_column_set_wrapfunc:
* @cl: a pointer to a struct libscols_column instance
* @wrap_chunksize: function to return size of the largest chink of data
* @wrap_nextchunk: function to return next zero terminated data
* @userdata: optional stuff for callbacks
*
* Extends SCOLS_FL_WRAP and allows to set custom wrap function. The default
* is to wrap by column size, but you can create functions to wrap for example
* after \n or after words, etc.
*
* Returns: 0, a negative value in case of an error.
*
* Since: 2.29
*/
int scols_column_set_wrapfunc(struct libscols_column *cl,
size_t (*wrap_chunksize)(const struct libscols_column *,
const char *,
void *),
char * (*wrap_nextchunk)(const struct libscols_column *,
char *,
void *),
void *userdata)
{
if (!cl)
return -EINVAL;
cl->wrap_nextchunk = wrap_nextchunk;
cl->wrap_chunksize = wrap_chunksize;
cl->wrapfunc_data = userdata;
return 0;
}
/**
* scols_column_set_safechars:
* @cl: a pointer to a struct libscols_column instance
* @safe: safe characters (e.g. "\n\t")
*
* Use for bytes you don't want to encode on output. This is for example
* necessary if you want to use custom wrap function based on \n, in this case
* you have to set "\n" as a safe char.
*
* Returns: 0, a negative value in case of an error.
*
* Since: 2.29
*/
int scols_column_set_safechars(struct libscols_column *cl, const char *safe)
{
return strdup_to_struct_member(cl, safechars, safe);
}
/**
* scols_column_get_safechars:
* @cl: a pointer to a struct libscols_column instance
*
* Returns: safe chars
*
* Since: 2.29
*/
const char *scols_column_get_safechars(const struct libscols_column *cl)
{
return cl->safechars;
}
/**
* scols_column_get_width:
* @cl: a pointer to a struct libscols_column instance
*
* Important note: the column width is unknown until library starts printing
* (width is calculated before printing). The function is usable for example in
* nextchunk() callback specified by scols_column_set_wrapfunc().
*
* See also scols_column_get_whint(), it returns wanted size (!= final size).
*
* Returns: column width
*
* Since: 2.29
*/
size_t scols_column_get_width(const struct libscols_column *cl)
{
return cl->width;
}
/**
* scols_column_is_hidden:
* @cl: a pointer to a struct libscols_column instance
*
* Gets the value of @cl's flag hidden.
*
* Returns: 0 or 1
*
* Since: 2.27
*/
int scols_column_is_hidden(const struct libscols_column *cl)
{
return cl->flags & SCOLS_FL_HIDDEN ? 1 : 0;
}
/**
* scols_column_is_trunc:
* @cl: a pointer to a struct libscols_column instance
*
* Gets the value of @cl's flag trunc.
*
* Returns: 0 or 1
*/
int scols_column_is_trunc(const struct libscols_column *cl)
{
return cl->flags & SCOLS_FL_TRUNC ? 1 : 0;
}
/**
* scols_column_is_tree:
* @cl: a pointer to a struct libscols_column instance
*
* Gets the value of @cl's flag tree.
*
* Returns: 0 or 1
*/
int scols_column_is_tree(const struct libscols_column *cl)
{
return cl->flags & SCOLS_FL_TREE ? 1 : 0;
}
/**
* scols_column_is_right:
* @cl: a pointer to a struct libscols_column instance
*
* Gets the value of @cl's flag right.
*
* Returns: 0 or 1
*/
int scols_column_is_right(const struct libscols_column *cl)
{
return cl->flags & SCOLS_FL_RIGHT ? 1 : 0;
}
/**
* scols_column_is_strict_width:
* @cl: a pointer to a struct libscols_column instance
*
* Gets the value of @cl's flag strict_width.
*
* Returns: 0 or 1
*/
int scols_column_is_strict_width(const struct libscols_column *cl)
{
return cl->flags & SCOLS_FL_STRICTWIDTH ? 1 : 0;
}
/**
* scols_column_is_noextremes:
* @cl: a pointer to a struct libscols_column instance
*
* Gets the value of @cl's flag no_extremes.
*
* Returns: 0 or 1
*/
int scols_column_is_noextremes(const struct libscols_column *cl)
{
return cl->flags & SCOLS_FL_NOEXTREMES ? 1 : 0;
}
/**
* scols_column_is_wrap:
* @cl: a pointer to a struct libscols_column instance
*
* Gets the value of @cl's flag wrap.
*
* Returns: 0 or 1
*
* Since: 2.28
*/
int scols_column_is_wrap(const struct libscols_column *cl)
{
return cl->flags & SCOLS_FL_WRAP ? 1 : 0;
}
/**
* scols_column_is_customwrap:
* @cl: a pointer to a struct libscols_column instance
*
* Returns: 0 or 1
*
* Since: 2.29
*/
int scols_column_is_customwrap(const struct libscols_column *cl)
{
return (cl->flags & SCOLS_FL_WRAP)
&& cl->wrap_chunksize
&& cl->wrap_nextchunk ? 1 : 0;
}