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