]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libsmartcols/src/line.c
6112090819a488600af2ce5c4887b99158aac5ff
[thirdparty/util-linux.git] / libsmartcols / src / line.c
1 /*
2 * line.c - functions for table handling at the line level
3 *
4 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
5 * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
6 *
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
9 */
10
11 /**
12 * SECTION: line
13 * @title: Line
14 * @short_description: line API
15 *
16 * An API to access and modify per-line data and information.
17 */
18
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <ctype.h>
24
25 #include "smartcolsP.h"
26
27 /**
28 * scols_new_line:
29 *
30 * Note that the line is allocated without cells, the cells will be allocated
31 * later when you add the line to the table. If you want to use the line
32 * without table then you have to explicitly allocate the cells by
33 * scols_line_alloc_cells().
34 *
35 * Returns: a pointer to a new struct libscols_line instance.
36 */
37 struct libscols_line *scols_new_line(void)
38 {
39 struct libscols_line *ln;
40
41 ln = calloc(1, sizeof(*ln));
42 if (!ln)
43 return NULL;
44 ln->refcount = 1;
45 INIT_LIST_HEAD(&ln->ln_lines);
46 INIT_LIST_HEAD(&ln->ln_children);
47 INIT_LIST_HEAD(&ln->ln_branch);
48 return ln;
49 }
50
51 /**
52 * scols_ref_line:
53 * @ln: a pointer to a struct libscols_line instance
54 *
55 * Increases the refcount of @ln.
56 */
57 void scols_ref_line(struct libscols_line *ln)
58 {
59 if (ln)
60 ln->refcount++;
61 }
62
63 /**
64 * scols_unref_line:
65 * @ln: a pointer to a struct libscols_line instance
66 *
67 * Decreases the refcount of @ln.
68 */
69 void scols_unref_line(struct libscols_line *ln)
70 {
71
72 if (ln && --ln->refcount <= 0) {
73 list_del(&ln->ln_lines);
74 list_del(&ln->ln_children);
75
76 scols_line_free_cells(ln);
77 free(ln->color);
78 free(ln);
79 return;
80 }
81 }
82
83 /**
84 * scols_line_free_cells:
85 * @ln: a pointer to a struct libscols_line instance
86 *
87 * Frees the allocated cells referenced to by @ln.
88 */
89 void scols_line_free_cells(struct libscols_line *ln)
90 {
91 size_t i;
92
93 if (!ln || !ln->cells)
94 return;
95
96 for (i = 0; i < ln->ncells; i++)
97 scols_reset_cell(&ln->cells[i]);
98
99 free(ln->cells);
100 ln->ncells = 0;
101 ln->cells = NULL;
102 }
103
104 /**
105 * scols_line_alloc_cells:
106 * @ln: a pointer to a struct libscols_line instance
107 * @n: the number of elements
108 *
109 * Allocates space for @n cells. This function is optional,
110 * and libsmartcols automatically allocates necessary cells
111 * according to number of columns in the table when you add
112 * the line to the table. See scols_table_add_line().
113 *
114 * Returns: 0, a negative value in case of an error.
115 */
116 int scols_line_alloc_cells(struct libscols_line *ln, size_t n)
117 {
118 struct libscols_cell *ce;
119
120 assert(ln);
121
122 if (!ln)
123 return -EINVAL;
124 if (ln->ncells == n)
125 return 0;
126
127 if (!n) {
128 scols_line_free_cells(ln);
129 return 0;
130 }
131
132 ce = realloc(ln->cells, n * sizeof(struct libscols_cell));
133 if (!ce)
134 return -errno;
135
136 if (n > ln->ncells)
137 memset(ce + ln->ncells, 0,
138 (n - ln->ncells) * sizeof(struct libscols_cell));
139
140 ln->cells = ce;
141 ln->ncells = n;
142 return 0;
143 }
144
145 /**
146 * scols_line_set_userdata:
147 * @ln: a pointer to a struct libscols_line instance
148 * @data: user data
149 *
150 * Binds @data to @ln.
151 *
152 * Returns: 0, a negative value in case of an error.
153 */
154 int scols_line_set_userdata(struct libscols_line *ln, void *data)
155 {
156 assert(ln);
157 if (!ln)
158 return -EINVAL;
159 ln->userdata = data;
160 return 0;
161 }
162
163 /**
164 * scols_line_get_userdata:
165 * @ln: a pointer to a struct libscols_line instance
166 *
167 * Returns: 0, a negative value in case of an error.
168 */
169 void *scols_line_get_userdata(struct libscols_line *ln)
170 {
171 assert(ln);
172 return ln ? ln->userdata : NULL;
173 }
174
175 /**
176 * scols_line_remove_child:
177 * @ln: a pointer to a struct libscols_line instance
178 * @child: a pointer to a struct libscols_line instance
179 *
180 * Removes @child as a child of @ln.
181 *
182 * Returns: 0, a negative value in case of an error.
183 */
184 int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child)
185 {
186 assert(ln);
187 assert(child);
188
189 if (!ln || !child)
190 return -EINVAL;
191 list_del_init(&child->ln_children);
192 scols_unref_line(child);
193
194 child->parent = NULL;
195 scols_unref_line(ln);
196 return 0;
197 }
198
199 /**
200 * scols_line_add_child:
201 * @ln: a pointer to a struct libscols_line instance
202 * @child: a pointer to a struct libscols_line instance
203 *
204 * Sets @child as a child of @ln.
205 *
206 * Returns: 0, a negative value in case of an error.
207 */
208 int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child)
209 {
210 assert(ln);
211 assert(child);
212
213 if (!ln || !child)
214 return -EINVAL;
215
216 /* unref old<->parent */
217 if (child->parent)
218 scols_line_remove_child(child->parent, child);
219
220 /* new reference from parent to child */
221 list_add_tail(&child->ln_children, &ln->ln_branch);
222 scols_ref_line(child);
223
224 /* new reference from child to parent */
225 child->parent = ln;
226 scols_ref_line(ln);
227
228 return 0;
229 }
230
231 /**
232 * scols_line_get_parent:
233 * @ln: a pointer to a struct libscols_line instance
234 *
235 * Returns: a pointer to @ln's parent, NULL in case it has no parent or if there was an error.
236 */
237 struct libscols_line *scols_line_get_parent(struct libscols_line *ln)
238 {
239 assert(ln);
240 return ln ? ln->parent : NULL;
241 }
242
243 /**
244 * scols_line_has_children:
245 * @ln: a pointer to a struct libscols_line instance
246 *
247 * Returns: 1 if @ln has any children, otherwise 0.
248 */
249 int scols_line_has_children(struct libscols_line *ln)
250 {
251 assert(ln);
252 return ln ? !list_empty(&ln->ln_branch) : 0;
253 }
254
255 /**
256 * scols_line_next_child:
257 * @ln: a pointer to a struct libscols_line instance
258 * @itr: a pointer to a struct libscols_iter instance
259 * @chld: a pointer to a pointer to a struct libscols_line instance
260 *
261 * Finds the next child and returns a pointer to it via @chld.
262 *
263 * Returns: 0, a negative value in case of an error.
264 */
265 int scols_line_next_child(struct libscols_line *ln,
266 struct libscols_iter *itr,
267 struct libscols_line **chld)
268 {
269 int rc = 1;
270
271 if (!ln || !itr || !chld)
272 return -EINVAL;
273 *chld = NULL;
274
275 if (!itr->head)
276 SCOLS_ITER_INIT(itr, &ln->ln_branch);
277 if (itr->p != itr->head) {
278 SCOLS_ITER_ITERATE(itr, *chld, struct libscols_line, ln_children);
279 rc = 0;
280 }
281
282 return rc;
283 }
284
285 /**
286 * scols_line_set_color:
287 * @ln: a pointer to a struct libscols_line instance
288 * @color: color name or ESC sequence
289 *
290 * Returns: 0, a negative value in case of an error.
291 */
292 int scols_line_set_color(struct libscols_line *ln, const char *color)
293 {
294 char *p = NULL;
295
296 assert(ln);
297 if (!ln)
298 return -EINVAL;
299 if (color) {
300 if (isalnum(*color)) {
301 color = color_sequence_from_colorname(color);
302
303 if (!color)
304 return -EINVAL;
305 }
306 p = strdup(color);
307 if (!p)
308 return -ENOMEM;
309 }
310
311 free(ln->color);
312 ln->color = p;
313 return 0;
314 }
315
316 /**
317 * scols_line_get_color:
318 * @ln: a pointer to a struct libscols_line instance
319 *
320 * Returns: @ln's color string, NULL in case of an error.
321 */
322 const char *scols_line_get_color(struct libscols_line *ln)
323 {
324 assert(ln);
325 return ln ? ln->color : NULL;
326 }
327
328 /**
329 * scols_line_get_ncells:
330 * @ln: a pointer to a struct libscols_line instance
331 *
332 * Returns: @ln's number of cells
333 */
334 size_t scols_line_get_ncells(struct libscols_line *ln)
335 {
336 assert(ln);
337 return ln ? ln->ncells : 0;
338 }
339
340 /**
341 * scols_line_get_cell:
342 * @ln: a pointer to a struct libscols_line instance
343 * @n: cell number to retrieve
344 *
345 * Returns: the @n-th cell in @ln, NULL in case of an error.
346 */
347 struct libscols_cell *scols_line_get_cell(struct libscols_line *ln,
348 size_t n)
349 {
350 assert(ln);
351
352 if (!ln || n >= ln->ncells)
353 return NULL;
354 return &ln->cells[n];
355 }
356
357 /**
358 * scols_line_get_column_cell:
359 * @ln: a pointer to a struct libscols_line instance
360 * @cl: pointer to cell
361 *
362 * Like scols_line_get_cell() by cell is referenced by column.
363 *
364 * Returns: the @n-th cell in @ln, NULL in case of an error.
365 */
366 struct libscols_cell *scols_line_get_column_cell(
367 struct libscols_line *ln,
368 struct libscols_column *cl)
369 {
370 assert(ln);
371 assert(cl);
372
373 return scols_line_get_cell(ln, cl->seqnum);
374 }
375
376 /**
377 * scols_line_set_data:
378 * @ln: a pointer to a struct libscols_cell instance
379 * @n: number of the cell, whose data is to be set
380 * @data: actual data to set
381 *
382 * Returns: 0, a negative value in case of an error.
383 */
384 int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data)
385 {
386 struct libscols_cell *ce = scols_line_get_cell(ln, n);
387
388 if (!ce)
389 return -EINVAL;
390 return scols_cell_set_data(ce, data);
391 }
392
393 /**
394 * scols_line_refer_data:
395 * @ln: a pointer to a struct libscols_cell instance
396 * @n: number of the cell which will refer to @data
397 * @data: actual data to refer to
398 *
399 * Returns: 0, a negative value in case of an error.
400 */
401 int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data)
402 {
403 struct libscols_cell *ce = scols_line_get_cell(ln, n);
404
405 if (!ce)
406 return -EINVAL;
407 return scols_cell_refer_data(ce, data);
408 }
409
410 /**
411 * scols_copy_line:
412 * @ln: a pointer to a struct libscols_cell instance
413 *
414 * Returns: A newly allocated copy of @ln, NULL in case of an error.
415 */
416 struct libscols_line *scols_copy_line(struct libscols_line *ln)
417 {
418 struct libscols_line *ret;
419 size_t i;
420
421 assert (ln);
422 if (!ln)
423 return NULL;
424
425 ret = scols_new_line();
426 if (!ret)
427 return NULL;
428 if (scols_line_set_color(ret, ln->color))
429 goto err;
430 if (scols_line_alloc_cells(ret, ln->ncells))
431 goto err;
432
433 ret->userdata = ln->userdata;
434 ret->ncells = ln->ncells;
435 ret->seqnum = ln->seqnum;
436
437 for (i = 0; i < ret->ncells; ++i) {
438 if (scols_cell_copy_content(&ret->cells[i], &ln->cells[i]))
439 goto err;
440 }
441
442 return ret;
443 err:
444 scols_unref_line(ret);
445 return NULL;
446 }
447
448