]>
Commit | Line | Data |
---|---|---|
1577b259 KZ |
1 | /* |
2 | * column.c - functions for table handling at the column level | |
3 | * | |
4 | * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com> | |
5 | * Copyright (C) 2014 Karel Zak <kzak@redhat.com> | |
6 | * | |
7 | * This file may be redistributed under the terms of the | |
8 | * GNU Lesser General Public License. | |
9 | */ | |
10 | ||
1d90bcb1 OO |
11 | /** |
12 | * SECTION: column | |
13 | * @title: Column | |
2473b711 | 14 | * @short_description: defines output columns formats, headers, etc. |
1d90bcb1 OO |
15 | * |
16 | * An API to access and modify per-column data and information. | |
17 | */ | |
18 | ||
ce44112b | 19 | |
1577b259 KZ |
20 | #include <stdlib.h> |
21 | #include <unistd.h> | |
22 | #include <string.h> | |
35958d0c | 23 | #include <ctype.h> |
1577b259 | 24 | |
949ea05f KZ |
25 | #include "mbsalign.h" |
26 | ||
1577b259 KZ |
27 | #include "smartcolsP.h" |
28 | ||
1d90bcb1 OO |
29 | /** |
30 | * scols_new_column: | |
31 | * | |
32 | * Allocates space for a new column. | |
33 | * | |
bfc6941a | 34 | * Returns: a pointer to a new struct libscols_column instance, NULL in case of an ENOMEM error. |
1d90bcb1 | 35 | */ |
1577b259 KZ |
36 | struct libscols_column *scols_new_column(void) |
37 | { | |
38 | struct libscols_column *cl; | |
39 | ||
40 | cl = calloc(1, sizeof(*cl)); | |
41 | if (!cl) | |
42 | return NULL; | |
710ed55d | 43 | DBG(COL, ul_debugobj(cl, "alloc")); |
1577b259 KZ |
44 | cl->refcount = 1; |
45 | INIT_LIST_HEAD(&cl->cl_columns); | |
46 | return cl; | |
47 | } | |
48 | ||
1d90bcb1 OO |
49 | /** |
50 | * scols_ref_column: | |
51 | * @cl: a pointer to a struct libscols_column instance | |
52 | * | |
53 | * Increases the refcount of @cl. | |
54 | */ | |
1577b259 KZ |
55 | void scols_ref_column(struct libscols_column *cl) |
56 | { | |
57 | if (cl) | |
58 | cl->refcount++; | |
59 | } | |
60 | ||
1d90bcb1 OO |
61 | /** |
62 | * scols_unref_column: | |
63 | * @cl: a pointer to a struct libscols_column instance | |
64 | * | |
3175f035 KZ |
65 | * Decreases the refcount of @cl. When the count falls to zero, the instance |
66 | * is automatically deallocated. | |
1d90bcb1 | 67 | */ |
1577b259 KZ |
68 | void scols_unref_column(struct libscols_column *cl) |
69 | { | |
70 | if (cl && --cl->refcount <= 0) { | |
710ed55d | 71 | DBG(COL, ul_debugobj(cl, "dealloc")); |
1577b259 KZ |
72 | list_del(&cl->cl_columns); |
73 | scols_reset_cell(&cl->header); | |
74 | free(cl->color); | |
68a7f92b | 75 | free(cl->safechars); |
d94c5198 | 76 | free(cl->pending_data_buf); |
1577b259 KZ |
77 | free(cl); |
78 | } | |
79 | } | |
80 | ||
1d90bcb1 OO |
81 | /** |
82 | * scols_copy_column: | |
83 | * @cl: a pointer to a struct libscols_column instance | |
84 | * | |
710ed55d | 85 | * Creates a new column and copies @cl's data over to it. |
1d90bcb1 OO |
86 | * |
87 | * Returns: a pointer to a new struct libscols_column instance. | |
88 | */ | |
1577b259 KZ |
89 | struct libscols_column *scols_copy_column(const struct libscols_column *cl) |
90 | { | |
91 | struct libscols_column *ret; | |
92 | ||
1577b259 KZ |
93 | if (!cl) |
94 | return NULL; | |
95 | ret = scols_new_column(); | |
96 | if (!ret) | |
97 | return NULL; | |
1577b259 | 98 | |
63c9c05d | 99 | DBG(COL, ul_debugobj(cl, "copy")); |
710ed55d | 100 | |
74bd28ad | 101 | if (scols_column_set_color(ret, cl->color)) |
1577b259 | 102 | goto err; |
74bd28ad | 103 | if (scols_cell_copy_content(&ret->header, &cl->header)) |
1577b259 KZ |
104 | goto err; |
105 | ||
106 | ret->width = cl->width; | |
107 | ret->width_min = cl->width_min; | |
108 | ret->width_max = cl->width_max; | |
109 | ret->width_avg = cl->width_avg; | |
110 | ret->width_hint = cl->width_hint; | |
8b992cb5 | 111 | ret->flags = cl->flags; |
1577b259 KZ |
112 | ret->is_extreme = cl->is_extreme; |
113 | ||
114 | return ret; | |
115 | err: | |
116 | scols_unref_column(ret); | |
117 | return NULL; | |
118 | } | |
119 | ||
1d90bcb1 OO |
120 | /** |
121 | * scols_column_set_whint: | |
122 | * @cl: a pointer to a struct libscols_column instance | |
123 | * @whint: a width hint | |
124 | * | |
cbe3e495 | 125 | * Sets the width hint of column @cl to @whint. See scols_table_new_column(). |
1d90bcb1 OO |
126 | * |
127 | * Returns: 0, a negative value in case of an error. | |
128 | */ | |
1577b259 KZ |
129 | int scols_column_set_whint(struct libscols_column *cl, double whint) |
130 | { | |
1577b259 KZ |
131 | if (!cl) |
132 | return -EINVAL; | |
133 | ||
134 | cl->width_hint = whint; | |
135 | return 0; | |
136 | } | |
137 | ||
1d90bcb1 OO |
138 | /** |
139 | * scols_column_get_whint: | |
140 | * @cl: a pointer to a struct libscols_column instance | |
141 | * | |
142 | * Returns: The width hint of column @cl, a negative value in case of an error. | |
143 | */ | |
f7a9ea28 | 144 | double scols_column_get_whint(const struct libscols_column *cl) |
1577b259 | 145 | { |
d4275a4b | 146 | return cl->width_hint; |
1577b259 KZ |
147 | } |
148 | ||
1d90bcb1 OO |
149 | /** |
150 | * scols_column_set_flags: | |
151 | * @cl: a pointer to a struct libscols_column instance | |
152 | * @flags: a flag mask | |
153 | * | |
154 | * Sets the flags of @cl to @flags. | |
155 | * | |
156 | * Returns: 0, a negative value in case of an error. | |
157 | */ | |
8b992cb5 OO |
158 | int scols_column_set_flags(struct libscols_column *cl, int flags) |
159 | { | |
8b992cb5 OO |
160 | if (!cl) |
161 | return -EINVAL; | |
162 | ||
d10fa7e6 IG |
163 | if (cl->table) { |
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--; | |
168 | } | |
169 | ||
8b992cb5 OO |
170 | cl->flags = flags; |
171 | return 0; | |
172 | } | |
173 | ||
b2c871f9 KZ |
174 | /** |
175 | * scols_column_set_json_type: | |
176 | * @cl: a pointer to a struct libscols_column instance | |
177 | * @type: SCOLS_JSON_* type | |
178 | * | |
179 | * Sets the type used for JSON formatting, the default is SCOLS_JSON_STRING. | |
180 | * | |
181 | * Returns: 0, a negative value in case of an error. | |
182 | * | |
183 | * Since: 2.33 | |
184 | */ | |
185 | int scols_column_set_json_type(struct libscols_column *cl, int type) | |
186 | { | |
187 | if (!cl) | |
188 | return -EINVAL; | |
189 | ||
190 | cl->json_type = type; | |
191 | return 0; | |
192 | ||
193 | } | |
194 | ||
195 | /** | |
196 | * scols_column_get_json_type: | |
197 | * @cl: a pointer to a struct libscols_column instance | |
198 | * | |
199 | * Note that SCOLS_JSON_BOOLEAN interprets NULL, empty strings, '0', 'N' and | |
200 | * 'n' as "false"; and everything else as "true". | |
201 | * | |
202 | * Returns: JSON type used for formatting or a negative value in case of an error. | |
203 | * | |
204 | * Since: 2.33 | |
205 | */ | |
206 | int scols_column_get_json_type(const struct libscols_column *cl) | |
207 | { | |
208 | return cl ? cl->json_type : -EINVAL; | |
209 | } | |
210 | ||
211 | ||
949ea05f KZ |
212 | /** |
213 | * scols_column_get_table: | |
214 | * @cl: a pointer to a struct libscols_column instance | |
215 | * | |
216 | * Returns: pointer to the table where columns is used | |
217 | */ | |
68a7f92b | 218 | struct libscols_table *scols_column_get_table(const struct libscols_column *cl) |
949ea05f KZ |
219 | { |
220 | return cl->table; | |
221 | } | |
222 | ||
1d90bcb1 OO |
223 | /** |
224 | * scols_column_get_flags: | |
225 | * @cl: a pointer to a struct libscols_column instance | |
226 | * | |
227 | * Returns: The flag mask of @cl, a negative value in case of an error. | |
228 | */ | |
f7a9ea28 | 229 | int scols_column_get_flags(const struct libscols_column *cl) |
8b992cb5 | 230 | { |
d4275a4b | 231 | return cl->flags; |
8b992cb5 OO |
232 | } |
233 | ||
1d90bcb1 | 234 | /** |
e2310281 | 235 | * scols_column_get_header: |
1d90bcb1 OO |
236 | * @cl: a pointer to a struct libscols_column instance |
237 | * | |
238 | * Returns: A pointer to a struct libscols_cell instance, representing the | |
239 | * header info of column @cl or NULL in case of an error. | |
240 | */ | |
74bd28ad | 241 | struct libscols_cell *scols_column_get_header(struct libscols_column *cl) |
1577b259 | 242 | { |
d4275a4b | 243 | return &cl->header; |
1577b259 KZ |
244 | } |
245 | ||
1d90bcb1 OO |
246 | /** |
247 | * scols_column_set_color: | |
248 | * @cl: a pointer to a struct libscols_column instance | |
618a1d6d | 249 | * @color: color name or ESC sequence |
1d90bcb1 | 250 | * |
1577b259 KZ |
251 | * The default color for data cells and column header. |
252 | * | |
253 | * If you want to set header specific color then use scols_column_get_header() | |
254 | * and scols_cell_set_color(). | |
255 | * | |
256 | * If you want to set data cell specific color the use scols_line_get_cell() + | |
257 | * scols_cell_set_color(). | |
1d90bcb1 OO |
258 | * |
259 | * Returns: 0, a negative value in case of an error. | |
1577b259 | 260 | */ |
618a1d6d | 261 | int scols_column_set_color(struct libscols_column *cl, const char *color) |
1577b259 | 262 | { |
618a1d6d IG |
263 | if (color && isalpha(*color)) { |
264 | color = color_sequence_from_colorname(color); | |
265 | if (!color) | |
8fcdce8f | 266 | return -EINVAL; |
1577b259 | 267 | } |
618a1d6d | 268 | return strdup_to_struct_member(cl, color, color); |
1577b259 KZ |
269 | } |
270 | ||
1d90bcb1 OO |
271 | /** |
272 | * scols_column_get_color: | |
273 | * @cl: a pointer to a struct libscols_column instance | |
274 | * | |
275 | * Returns: The current color setting of the column @cl. | |
276 | */ | |
f7a9ea28 | 277 | const char *scols_column_get_color(const struct libscols_column *cl) |
1577b259 | 278 | { |
d4275a4b | 279 | return cl->color; |
1577b259 KZ |
280 | } |
281 | ||
949ea05f KZ |
282 | /** |
283 | * scols_wrapnl_nextchunk: | |
284 | * @cl: a pointer to a struct libscols_column instance | |
285 | * @data: string | |
81b176c4 | 286 | * @userdata: callback private data |
949ea05f | 287 | * |
68a7f92b | 288 | * This is built-in function for scols_column_set_wrapfunc(). This function |
949ea05f KZ |
289 | * terminates the current chunk by \0 and returns pointer to the begin of |
290 | * the next chunk. The chunks are based on \n. | |
291 | * | |
292 | * For example for data "AAA\nBBB\nCCC" the next chunk is "BBB". | |
293 | * | |
294 | * Returns: next chunk | |
3f47320a KZ |
295 | * |
296 | * Since: 2.29 | |
949ea05f KZ |
297 | */ |
298 | char *scols_wrapnl_nextchunk(const struct libscols_column *cl __attribute__((unused)), | |
299 | char *data, | |
300 | void *userdata __attribute__((unused))) | |
301 | { | |
302 | char *p = data ? strchr(data, '\n') : NULL; | |
303 | ||
304 | if (p) { | |
305 | *p = '\0'; | |
306 | return p + 1; | |
307 | } | |
308 | return NULL; | |
309 | } | |
310 | ||
311 | /** | |
312 | * scols_wrapnl_chunksize: | |
313 | * @cl: a pointer to a struct libscols_column instance | |
314 | * @data: string | |
81b176c4 | 315 | * @userdata: callback private data |
949ea05f KZ |
316 | * |
317 | * Analyzes @data and returns size of the largest chunk. The chunks are based | |
318 | * on \n. For example for data "AAA\nBBB\nCCCC" the largest chunk size is 4. | |
319 | * | |
320 | * Note that the size has to be based on number of terminal cells rather than | |
321 | * bytes to support multu-byte output. | |
322 | * | |
323 | * Returns: size of the largest chunk. | |
3f47320a KZ |
324 | * |
325 | * Since: 2.29 | |
949ea05f KZ |
326 | */ |
327 | size_t scols_wrapnl_chunksize(const struct libscols_column *cl __attribute__((unused)), | |
328 | const char *data, | |
329 | void *userdata __attribute__((unused))) | |
330 | { | |
331 | size_t sum = 0; | |
332 | ||
333 | while (data && *data) { | |
1b504263 | 334 | const char *p; |
949ea05f KZ |
335 | size_t sz; |
336 | ||
337 | p = strchr(data, '\n'); | |
338 | if (p) { | |
339 | sz = mbs_safe_nwidth(data, p - data, NULL); | |
340 | p++; | |
341 | } else | |
342 | sz = mbs_safe_width(data); | |
343 | ||
344 | sum = max(sum, sz); | |
f4d37838 | 345 | data = p; |
949ea05f KZ |
346 | } |
347 | ||
348 | return sum; | |
349 | } | |
57a86f9b KZ |
350 | |
351 | /** | |
352 | * scols_column_set_cmpfunc: | |
353 | * @cl: column | |
354 | * @cmp: pointer to compare function | |
355 | * @data: private data for cmp function | |
356 | * | |
357 | * Returns: 0, a negative value in case of an error. | |
358 | */ | |
359 | int scols_column_set_cmpfunc(struct libscols_column *cl, | |
360 | int (*cmp)(struct libscols_cell *, | |
361 | struct libscols_cell *, | |
362 | void *), | |
363 | void *data) | |
364 | { | |
57a86f9b KZ |
365 | if (!cl) |
366 | return -EINVAL; | |
367 | ||
368 | cl->cmpfunc = cmp; | |
369 | cl->cmpfunc_data = data; | |
370 | return 0; | |
371 | } | |
372 | ||
949ea05f KZ |
373 | /** |
374 | * scols_column_set_wrapfunc: | |
375 | * @cl: a pointer to a struct libscols_column instance | |
376 | * @wrap_chunksize: function to return size of the largest chink of data | |
377 | * @wrap_nextchunk: function to return next zero terminated data | |
81b176c4 | 378 | * @userdata: optional stuff for callbacks |
949ea05f KZ |
379 | * |
380 | * Extends SCOLS_FL_WRAP and allows to set custom wrap function. The default | |
381 | * is to wrap by column size, but you can create functions to wrap for example | |
382 | * after \n or after words, etc. | |
383 | * | |
384 | * Returns: 0, a negative value in case of an error. | |
3f47320a KZ |
385 | * |
386 | * Since: 2.29 | |
949ea05f KZ |
387 | */ |
388 | int scols_column_set_wrapfunc(struct libscols_column *cl, | |
389 | size_t (*wrap_chunksize)(const struct libscols_column *, | |
390 | const char *, | |
391 | void *), | |
392 | char * (*wrap_nextchunk)(const struct libscols_column *, | |
393 | char *, | |
394 | void *), | |
81b176c4 | 395 | void *userdata) |
949ea05f KZ |
396 | { |
397 | if (!cl) | |
398 | return -EINVAL; | |
399 | ||
400 | cl->wrap_nextchunk = wrap_nextchunk; | |
401 | cl->wrap_chunksize = wrap_chunksize; | |
81b176c4 | 402 | cl->wrapfunc_data = userdata; |
949ea05f KZ |
403 | return 0; |
404 | } | |
405 | ||
406 | /** | |
407 | * scols_column_set_safechars: | |
408 | * @cl: a pointer to a struct libscols_column instance | |
409 | * @safe: safe characters (e.g. "\n\t") | |
410 | * | |
411 | * Use for bytes you don't want to encode on output. This is for example | |
412 | * necessary if you want to use custom wrap function based on \n, in this case | |
413 | * you have to set "\n" as a safe char. | |
414 | * | |
415 | * Returns: 0, a negative value in case of an error. | |
3f47320a KZ |
416 | * |
417 | * Since: 2.29 | |
949ea05f KZ |
418 | */ |
419 | int scols_column_set_safechars(struct libscols_column *cl, const char *safe) | |
420 | { | |
68a7f92b | 421 | return strdup_to_struct_member(cl, safechars, safe); |
949ea05f KZ |
422 | } |
423 | ||
424 | /** | |
425 | * scols_column_get_safechars: | |
426 | * @cl: a pointer to a struct libscols_column instance | |
427 | * | |
428 | * Returns: safe chars | |
3f47320a KZ |
429 | * |
430 | * Since: 2.29 | |
949ea05f KZ |
431 | */ |
432 | const char *scols_column_get_safechars(const struct libscols_column *cl) | |
433 | { | |
434 | return cl->safechars; | |
435 | } | |
436 | ||
82053f5e KZ |
437 | /** |
438 | * scols_column_get_width: | |
439 | * @cl: a pointer to a struct libscols_column instance | |
440 | * | |
441 | * Important note: the column width is unknown until library starts printing | |
442 | * (width is calculated before printing). The function is usable for example in | |
443 | * nextchunk() callback specified by scols_column_set_wrapfunc(). | |
444 | * | |
445 | * See also scols_column_get_whint(), it returns wanted size (!= final size). | |
446 | * | |
447 | * Returns: column width | |
448 | * | |
449 | * Since: 2.29 | |
450 | */ | |
451 | size_t scols_column_get_width(const struct libscols_column *cl) | |
452 | { | |
453 | return cl->width; | |
454 | } | |
455 | ||
6d6b6d18 KZ |
456 | /** |
457 | * scols_column_is_hidden: | |
458 | * @cl: a pointer to a struct libscols_column instance | |
459 | * | |
460 | * Gets the value of @cl's flag hidden. | |
461 | * | |
d4275a4b | 462 | * Returns: 0 or 1 |
982034c3 KZ |
463 | * |
464 | * Since: 2.27 | |
6d6b6d18 | 465 | */ |
f7a9ea28 | 466 | int scols_column_is_hidden(const struct libscols_column *cl) |
6d6b6d18 | 467 | { |
d4275a4b | 468 | return cl->flags & SCOLS_FL_HIDDEN ? 1 : 0; |
6d6b6d18 KZ |
469 | } |
470 | ||
8a38a8d3 OO |
471 | /** |
472 | * scols_column_is_trunc: | |
1d90bcb1 | 473 | * @cl: a pointer to a struct libscols_column instance |
8a38a8d3 | 474 | * |
1d90bcb1 | 475 | * Gets the value of @cl's flag trunc. |
8a38a8d3 | 476 | * |
d4275a4b | 477 | * Returns: 0 or 1 |
8a38a8d3 | 478 | */ |
f7a9ea28 | 479 | int scols_column_is_trunc(const struct libscols_column *cl) |
8a38a8d3 | 480 | { |
d4275a4b | 481 | return cl->flags & SCOLS_FL_TRUNC ? 1 : 0; |
8a38a8d3 OO |
482 | } |
483 | /** | |
484 | * scols_column_is_tree: | |
1d90bcb1 | 485 | * @cl: a pointer to a struct libscols_column instance |
8a38a8d3 | 486 | * |
1d90bcb1 | 487 | * Gets the value of @cl's flag tree. |
8a38a8d3 | 488 | * |
d4275a4b | 489 | * Returns: 0 or 1 |
8a38a8d3 | 490 | */ |
f7a9ea28 | 491 | int scols_column_is_tree(const struct libscols_column *cl) |
8a38a8d3 | 492 | { |
d4275a4b | 493 | return cl->flags & SCOLS_FL_TREE ? 1 : 0; |
8a38a8d3 OO |
494 | } |
495 | /** | |
496 | * scols_column_is_right: | |
1d90bcb1 | 497 | * @cl: a pointer to a struct libscols_column instance |
8a38a8d3 | 498 | * |
1d90bcb1 | 499 | * Gets the value of @cl's flag right. |
8a38a8d3 | 500 | * |
d4275a4b | 501 | * Returns: 0 or 1 |
8a38a8d3 | 502 | */ |
f7a9ea28 | 503 | int scols_column_is_right(const struct libscols_column *cl) |
8a38a8d3 | 504 | { |
d4275a4b | 505 | return cl->flags & SCOLS_FL_RIGHT ? 1 : 0; |
8a38a8d3 OO |
506 | } |
507 | /** | |
508 | * scols_column_is_strict_width: | |
1d90bcb1 | 509 | * @cl: a pointer to a struct libscols_column instance |
8a38a8d3 | 510 | * |
1d90bcb1 | 511 | * Gets the value of @cl's flag strict_width. |
8a38a8d3 | 512 | * |
d4275a4b | 513 | * Returns: 0 or 1 |
8a38a8d3 | 514 | */ |
f7a9ea28 | 515 | int scols_column_is_strict_width(const struct libscols_column *cl) |
8a38a8d3 | 516 | { |
d4275a4b | 517 | return cl->flags & SCOLS_FL_STRICTWIDTH ? 1 : 0; |
8a38a8d3 OO |
518 | } |
519 | /** | |
0925a9dd | 520 | * scols_column_is_noextremes: |
1d90bcb1 | 521 | * @cl: a pointer to a struct libscols_column instance |
8a38a8d3 | 522 | * |
1d90bcb1 | 523 | * Gets the value of @cl's flag no_extremes. |
8a38a8d3 | 524 | * |
d4275a4b | 525 | * Returns: 0 or 1 |
8a38a8d3 | 526 | */ |
f7a9ea28 | 527 | int scols_column_is_noextremes(const struct libscols_column *cl) |
8a38a8d3 | 528 | { |
d4275a4b | 529 | return cl->flags & SCOLS_FL_NOEXTREMES ? 1 : 0; |
8a38a8d3 | 530 | } |
a6404093 IG |
531 | /** |
532 | * scols_column_is_wrap: | |
533 | * @cl: a pointer to a struct libscols_column instance | |
534 | * | |
535 | * Gets the value of @cl's flag wrap. | |
536 | * | |
d4275a4b | 537 | * Returns: 0 or 1 |
2f09ae9d KZ |
538 | * |
539 | * Since: 2.28 | |
a6404093 | 540 | */ |
f7a9ea28 | 541 | int scols_column_is_wrap(const struct libscols_column *cl) |
a6404093 | 542 | { |
d4275a4b | 543 | return cl->flags & SCOLS_FL_WRAP ? 1 : 0; |
a6404093 | 544 | } |
ff471d89 | 545 | /** |
949ea05f | 546 | * scols_column_is_customwrap: |
ff471d89 KZ |
547 | * @cl: a pointer to a struct libscols_column instance |
548 | * | |
d4275a4b | 549 | * Returns: 0 or 1 |
ff471d89 KZ |
550 | * |
551 | * Since: 2.29 | |
552 | */ | |
949ea05f | 553 | int scols_column_is_customwrap(const struct libscols_column *cl) |
ff471d89 | 554 | { |
949ea05f KZ |
555 | return (cl->flags & SCOLS_FL_WRAP) |
556 | && cl->wrap_chunksize | |
557 | && cl->wrap_nextchunk ? 1 : 0; | |
ff471d89 | 558 | } |