summaryrefslogblamecommitdiffstats
path: root/libsmartcols/src/line.c
blob: 32c8964ad69b4e0ba1f2442588c98d54931c66a3 (plain) (tree)
1
2
3
4
5
6
7
8
9
10



                                                          
                                                        




                                                        







                                                             
 


                   
                  


                       


                  



                                                                             

                                                             
   






                                          






                                         





                                                    





                                             





                                                    

                                               
 
                                        


                                           
                                          

                                
                       


         





                                                    














                                                    




                                                    



                                                           


                                                    




























                                                                        








                                                    








                                                                 





                                                    





                                                       








                                                       
                                                                                  

                   











                                           








                                                       





                                                                               
                               












                                                              


                 





                                                                                              





                                                                     





                                                    





                                                     









                                                                   



















                                                                                  


                                                    
                                     

                                                    








                                                                     
                                      
                                                                     



                                               









                                       





                                                         





                                                          





                                                    





                                                      






                                                            






                                                                   


                             







                                                    








                                                                             
   
                         





                                                    






                                                                         

 





                                                                    


                                                               
                 









                                                 


                                                    
                                     
                                   
                                   
 

                                                                           
                                 








                              
/*
 * line.c - functions for table handling at the line level
 *
 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
 *
 * This file may be redistributed under the terms of the
 * GNU Lesser General Public License.
 */

/**
 * SECTION: line
 * @title: Line
 * @short_description: line API
 *
 * An API to access and modify per-line data and information.
 */


#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>

#include "smartcolsP.h"

/**
 * scols_new_line:
 *
 * Note that the line is allocated without cells, the cells will be allocated
 * later when you add the line to the table. If you want to use the line
 * without table then you have to explicitly allocate the cells by
 * scols_line_alloc_cells().
 *
 * Returns: a pointer to a new struct libscols_line instance.
 */
struct libscols_line *scols_new_line(void)
{
	struct libscols_line *ln;

	ln = calloc(1, sizeof(*ln));
	if (!ln)
		return NULL;
	ln->refcount = 1;
	INIT_LIST_HEAD(&ln->ln_lines);
	INIT_LIST_HEAD(&ln->ln_children);
	INIT_LIST_HEAD(&ln->ln_branch);
	return ln;
}

/**
 * scols_ref_line:
 * @ln: a pointer to a struct libscols_line instance
 *
 * Increases the refcount of @ln.
 */
void scols_ref_line(struct libscols_line *ln)
{
	if (ln)
		ln->refcount++;
}

/**
 * scols_unref_line:
 * @ln: a pointer to a struct libscols_line instance
 *
 * Decreases the refcount of @ln.
 */
void scols_unref_line(struct libscols_line *ln)
{

	if (ln && --ln->refcount <= 0) {
		list_del(&ln->ln_lines);
		list_del(&ln->ln_children);

		scols_line_free_cells(ln);
		free(ln->color);
		free(ln);
		return;
	}
}

/**
 * scols_line_free_cells:
 * @ln: a pointer to a struct libscols_line instance
 *
 * Frees the allocated cells referenced to by @ln.
 */
void scols_line_free_cells(struct libscols_line *ln)
{
	size_t i;

	if (!ln || !ln->cells)
		return;

	for (i = 0; i < ln->ncells; i++)
		scols_reset_cell(&ln->cells[i]);

	free(ln->cells);
	ln->ncells = 0;
	ln->cells = NULL;
}

/**
 * scols_line_alloc_cells:
 * @ln: a pointer to a struct libscols_line instance
 * @n: the number of elements
 *
 * Allocates space for @n cells. This function is optional,
 * and libsmartcols automatically allocates necessary cells
 * according to number of columns in the table when you add
 * the line to the table. See scols_table_add_line().
 *
 * Returns: 0, a negative value in case of an error.
 */
int scols_line_alloc_cells(struct libscols_line *ln, size_t n)
{
	struct libscols_cell *ce;

	assert(ln);

	if (!ln)
		return -EINVAL;
	if (ln->ncells == n)
		return 0;

	if (!n) {
		scols_line_free_cells(ln);
		return 0;
	}

	ce = realloc(ln->cells, n * sizeof(struct libscols_cell));
	if (!ce)
		return -errno;

	if (n > ln->ncells)
		memset(ce + ln->ncells, 0,
		       (n - ln->ncells) * sizeof(struct libscols_cell));

	ln->cells = ce;
	ln->ncells = n;
	return 0;
}

/**
 * scols_line_set_userdata:
 * @ln: a pointer to a struct libscols_line instance
 * @data: user data
 *
 * Binds @data to @ln.
 *
 * Returns: 0, a negative value in case of an error.
 */
int scols_line_set_userdata(struct libscols_line *ln, void *data)
{
	assert(ln);
	if (!ln)
		return -EINVAL;
	ln->userdata = data;
	return 0;
}

/**
 * scols_line_get_userdata:
 * @ln: a pointer to a struct libscols_line instance
 *
 * Returns: 0, a negative value in case of an error.
 */
void *scols_line_get_userdata(struct libscols_line *ln)
{
	assert(ln);
	return ln ? ln->userdata : NULL;
}

/**
 * scols_line_remove_child:
 * @ln: a pointer to a struct libscols_line instance
 * @child: a pointer to a struct libscols_line instance
 *
 * Removes @child as a child of @ln.
 *
 * Returns: 0, a negative value in case of an error.
 */
int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child)
{
	assert(ln);
	assert(child);

	if (!ln || !child)
		return -EINVAL;
	list_del_init(&child->ln_children);
	scols_unref_line(child);

	child->parent = NULL;
	scols_unref_line(ln);
	return 0;
}

/**
 * scols_line_add_child:
 * @ln: a pointer to a struct libscols_line instance
 * @child: a pointer to a struct libscols_line instance
 *
 * Sets @child as a child of @ln.
 *
 * Returns: 0, a negative value in case of an error.
 */
int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child)
{
	assert(ln);
	assert(child);

	if (!ln || !child)
		return -EINVAL;

	/* unref old<->parent */
	if (child->parent)
		scols_line_remove_child(child->parent, child);

	/* new reference from parent to child */
	list_add_tail(&child->ln_children, &ln->ln_branch);
	scols_ref_line(child);

	/* new reference from child to parent */
	child->parent = ln;
	scols_ref_line(ln);

	return 0;
}

/**
 * scols_line_get_parent:
 * @ln: a pointer to a struct libscols_line instance
 *
 * Returns: a pointer to @ln's parent, NULL in case it has no parent or if there was an error.
 */
struct libscols_line *scols_line_get_parent(struct libscols_line *ln)
{
	assert(ln);
	return ln ? ln->parent : NULL;
}

/**
 * scols_line_has_children:
 * @ln: a pointer to a struct libscols_line instance
 *
 * Returns: 1 if @ln has any children, otherwise 0.
 */
int scols_line_has_children(struct libscols_line *ln)
{
	assert(ln);
	return ln ? !list_empty(&ln->ln_branch) : 0;
}

/**
 * scols_line_next_child:
 * @ln: a pointer to a struct libscols_line instance
 * @itr: a pointer to a struct libscols_iter instance
 * @chld: a pointer to a pointer to a struct libscols_line instance
 *
 * Finds the next child and returns a pointer to it via @chld.
 *
 * Returns: 0, a negative value in case of an error.
 */
int scols_line_next_child(struct libscols_line *ln,
			  struct libscols_iter *itr,
			  struct libscols_line **chld)
{
	int rc = 1;

	if (!ln || !itr || !chld)
		return -EINVAL;
	*chld = NULL;

	if (!itr->head)
		SCOLS_ITER_INIT(itr, &ln->ln_branch);
	if (itr->p != itr->head) {
		SCOLS_ITER_ITERATE(itr, *chld, struct libscols_line, ln_children);
		rc = 0;
	}

	return rc;
}

/**
 * scols_line_set_color:
 * @ln: a pointer to a struct libscols_line instance
 * @color: color name or ESC sequence
 *
 * Returns: 0, a negative value in case of an error.
 */
int scols_line_set_color(struct libscols_line *ln, const char *color)
{
	char *p = NULL;

	assert(ln);
	if (!ln)
		return -EINVAL;
	if (color) {
		if (isalnum(*color)) {
			color = color_sequence_from_colorname(color);

			if (!color)
				return -EINVAL;
		}
		p = strdup(color);
		if (!p)
			return -ENOMEM;
	}

	free(ln->color);
	ln->color = p;
	return 0;
}

/**
 * scols_line_get_color:
 * @ln: a pointer to a struct libscols_line instance
 *
 * Returns: @ln's color string, NULL in case of an error.
 */
const char *scols_line_get_color(struct libscols_line *ln)
{
	assert(ln);
	return ln ? ln->color : NULL;
}

/**
 * scols_line_get_ncells:
 * @ln: a pointer to a struct libscols_line instance
 *
 * Returns: @ln's number of cells
 */
size_t scols_line_get_ncells(struct libscols_line *ln)
{
	assert(ln);
	return ln ? ln->ncells : 0;
}

/**
 * scols_line_get_cell:
 * @ln: a pointer to a struct libscols_line instance
 * @n: cell number to retrieve
 *
 * Returns: the @n-th cell in @ln, NULL in case of an error.
 */
struct libscols_cell *scols_line_get_cell(struct libscols_line *ln,
					  size_t n)
{
	assert(ln);

	if (!ln || n >= ln->ncells)
		return NULL;
	return &ln->cells[n];
}

/**
 * scols_line_set_data:
 * @ln: a pointer to a struct libscols_cell instance
 * @n: number of the cell, whose data is to be set
 * @data: actual data to set
 *
 * Returns: 0, a negative value in case of an error.
 */
int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data)
{
	struct libscols_cell *ce = scols_line_get_cell(ln, n);

	if (!ce)
		return -EINVAL;
	return scols_cell_set_data(ce, data);
}

/**
 * scols_line_refer_data:
 * @ln: a pointer to a struct libscols_cell instance
 * @n: number of the cell which will refer to @data
 * @data: actual data to refer to
 *
 * Returns: 0, a negative value in case of an error.
 */
int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data)
{
	struct libscols_cell *ce = scols_line_get_cell(ln, n);

	if (!ce)
		return -EINVAL;
	return scols_cell_refer_data(ce, data);
}

/**
 * scols_copy_line:
 * @ln: a pointer to a struct libscols_cell instance
 *
 * Returns: A newly allocated copy of @ln, NULL in case of an error.
 */
struct libscols_line *scols_copy_line(struct libscols_line *ln)
{
	struct libscols_line *ret;
	size_t i;

	assert (ln);
	if (!ln)
		return NULL;

	ret = scols_new_line();
	if (!ret)
		return NULL;
	if (scols_line_set_color(ret, ln->color))
		goto err;
	if (scols_line_alloc_cells(ret, ln->ncells))
		goto err;

	ret->userdata = ln->userdata;
	ret->ncells   = ln->ncells;
	ret->seqnum   = ln->seqnum;

	for (i = 0; i < ret->ncells; ++i) {
		if (scols_cell_copy_content(&ret->cells[i], &ln->cells[i]))
			goto err;
	}

	return ret;
err:
	scols_unref_line(ret);
	return NULL;
}