1 /*
2 * smartcolsP.h - private library header file
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
11 #ifndef _LIBSMARTCOLS_PRIVATE_H
12 #define _LIBSMARTCOLS_PRIVATE_H
13
14 #include "c.h"
15 #include "list.h"
16 #include "strutils.h"
17 #include "color-names.h"
18 #include "jsonwrt.h"
19 #include "debug.h"
20 #include "buffer.h"
21
22 #include "libsmartcols.h"
23
24 /*
25 * Debug
26 */
27 #define SCOLS_DEBUG_HELP (1 << 0)
28 #define SCOLS_DEBUG_INIT (1 << 1)
29 #define SCOLS_DEBUG_CELL (1 << 2)
30 #define SCOLS_DEBUG_LINE (1 << 3)
31 #define SCOLS_DEBUG_TAB (1 << 4)
32 #define SCOLS_DEBUG_COL (1 << 5)
33 #define SCOLS_DEBUG_BUFF (1 << 6)
34 #define SCOLS_DEBUG_GROUP (1 << 7)
35 #define SCOLS_DEBUG_ALL 0xFFFF
36
37 UL_DEBUG_DECLARE_MASK(libsmartcols);
38 #define DBG(m, x) __UL_DBG(libsmartcols, SCOLS_DEBUG_, m, x)
39 #define ON_DBG(m, x) __UL_DBG_CALL(libsmartcols, SCOLS_DEBUG_, m, x)
40 #define DBG_FLUSH __UL_DBG_FLUSH(libsmartcols, SCOLS_DEBUG_)
41
42 #define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(libsmartcols)
43 #include "debugobj.h"
44
45 #define SCOLS_BUFPTR_TREEEND 0
46
47 /*
48 * Generic iterator
49 */
50 struct libscols_iter {
51 struct list_head *p; /* current position */
52 struct list_head *head; /* start position */
53 int direction; /* SCOLS_ITER_{FOR,BACK}WARD */
54 };
55
56 /*
57 * Tree symbols
58 */
59 struct libscols_symbols {
60 int refcount;
61
62 char *tree_branch;
63 char *tree_vert;
64 char *tree_right;
65
66 char *group_vert;
67 char *group_horz;
68 char *group_first_member;
69 char *group_last_member;
70 char *group_middle_member;
71 char *group_last_child;
72 char *group_middle_child;
73
74 char *title_padding;
75 char *cell_padding;
76 };
77
78 /*
79 * Table cells
80 */
81 struct libscols_cell {
82 char *data;
83 char *color;
84 void *userdata;
85 int flags;
86 size_t width;
87 };
88
89 extern int scols_line_move_cells(struct libscols_line *ln, size_t newn, size_t oldn);
90
91 struct libscols_wstat {
92 size_t width_min;
93 size_t width_max;
94 double width_avg;
95 double width_sqr_sum;
96 double width_deviation;
97
98 size_t width_treeart;
99 };
100
101 /*
102 * Table column
103 */
104 struct libscols_column {
105 int refcount; /* reference counter */
106 size_t seqnum; /* column index */
107
108 size_t width; /* expected column width */
109 size_t width_treeart;
110 double width_hint; /* hint (N < 1 is in percent of termwidth) */
111
112 struct libscols_wstat wstat; /* private __scols_calculate() data */
113
114 int json_type; /* SCOLS_JSON_* */
115
116 int flags;
117 char *color; /* default column color */
118 char *safechars; /* do not encode this bytes */
119
120 char *pending_data;
121 size_t pending_data_sz;
122 char *pending_data_buf;
123
124 int (*cmpfunc)(struct libscols_cell *,
125 struct libscols_cell *,
126 void *); /* cells comparison function */
127 void *cmpfunc_data;
128
129 size_t (*wrap_chunksize)(const struct libscols_column *,
130 const char *, void *);
131 char *(*wrap_nextchunk)(const struct libscols_column *,
132 char *, void *);
133 void *wrapfunc_data;
134
135
136 struct libscols_cell header; /* column name with color etc. */
137 char *shellvar; /* raw colum name in shell compatible format */
138
139 struct list_head cl_columns; /* member of table->tb_columns */
140
141 struct libscols_table *table;
142
143 unsigned int is_groups : 1; /* print group chart */
144
145 };
146
147 #define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ")
148 #define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n")
149
150 enum {
151 SCOLS_GSTATE_NONE = 0, /* not activate yet */
152 SCOLS_GSTATE_FIRST_MEMBER,
153 SCOLS_GSTATE_MIDDLE_MEMBER,
154 SCOLS_GSTATE_LAST_MEMBER,
155 SCOLS_GSTATE_MIDDLE_CHILD,
156 SCOLS_GSTATE_LAST_CHILD,
157 SCOLS_GSTATE_CONT_MEMBERS,
158 SCOLS_GSTATE_CONT_CHILDREN
159 };
160
161 /*
162 * Every group needs at least 3 columns
163 */
164 #define SCOLS_GRPSET_CHUNKSIZ 3
165
166 struct libscols_group {
167 int refcount;
168
169 size_t nmembers;
170
171 struct list_head gr_members; /* head of line->ln_group */
172 struct list_head gr_children; /* head of line->ln_children */
173 struct list_head gr_groups; /* member of table->tb_groups */
174
175 int state; /* SCOLS_GSTATE_* */
176 };
177
178 /*
179 * Table line
180 */
181 struct libscols_line {
182 int refcount;
183 size_t seqnum;
184
185 void *userdata;
186 char *color; /* default line color */
187
188 struct libscols_cell *cells; /* array with data */
189 size_t ncells; /* number of cells */
190
191 struct list_head ln_lines; /* member of table->tb_lines */
192 struct list_head ln_branch; /* head of line->ln_children */
193 struct list_head ln_children; /* member of line->ln_children or group->gr_children */
194 struct list_head ln_groups; /* member of group->gr_groups */
195
196 struct libscols_line *parent;
197 struct libscols_group *parent_group; /* for group childs */
198 struct libscols_group *group; /* for group members */
199 };
200
201 enum {
202 SCOLS_FMT_HUMAN = 0, /* default, human readable */
203 SCOLS_FMT_RAW, /* space separated */
204 SCOLS_FMT_EXPORT, /* COLNAME="data" ... */
205 SCOLS_FMT_JSON /* http://en.wikipedia.org/wiki/JSON */
206 };
207
208 /*
209 * The table
210 */
211 struct libscols_table {
212 int refcount;
213 char *name; /* optional table name (for JSON) */
214 size_t ncols; /* number of columns */
215 size_t ntreecols; /* number of columns with SCOLS_FL_TREE */
216 size_t nlines; /* number of lines */
217 size_t termwidth; /* terminal width (number of columns) */
218 size_t termheight; /* terminal height (number of lines) */
219 size_t termreduce; /* extra blank space */
220 int termforce; /* SCOLS_TERMFORCE_* */
221 FILE *out; /* output stream */
222
223 char *colsep; /* column separator */
224 char *linesep; /* line separator */
225
226 struct list_head tb_columns; /* list of columns, items: column->cl_columns */
227 struct list_head tb_lines; /* list of lines; items: line->ln_lines */
228
229 struct list_head tb_groups; /* all defined groups */
230 struct libscols_group **grpset;
231 size_t grpset_size;
232
233 size_t ngrpchlds_pending; /* groups with not yet printed children */
234 struct libscols_line *walk_last_tree_root; /* last root, used by scols_walk_() */
235
236 struct libscols_column *dflt_sort_column; /* default sort column, set by scols_sort_table() */
237
238 struct libscols_symbols *symbols;
239 struct libscols_cell title; /* optional table title (for humans) */
240
241 struct ul_jsonwrt json; /* JSON formatting */
242
243 int format; /* SCOLS_FMT_* */
244
245 size_t termlines_used; /* printed line counter */
246 size_t header_next; /* where repeat header */
247
248 const char *cur_color; /* current active color when printing */
249
250 /* flags */
251 unsigned int ascii :1, /* don't use unicode */
252 colors_wanted :1, /* enable colors */
253 is_term :1, /* isatty() */
254 padding_debug :1, /* output visible padding chars */
255 is_dummy_print :1, /* printing used for width calculation only */
256 is_shellvar :1, /* shell compatible column names */
257 maxout :1, /* maximize output */
258 minout :1, /* minimize output (mutually exclusive to maxout) */
259 header_repeat :1, /* print header after libscols_table->termheight */
260 header_printed :1, /* header already printed */
261 priv_symbols :1, /* default private symbols */
262 walk_last_done :1, /* last tree root walked */
263 no_headings :1, /* don't print header */
264 no_encode :1, /* don't care about control and non-printable chars */
265 no_linesep :1, /* don't print line separator */
266 no_wrap :1; /* never wrap lines */
267 };
268
269 #define IS_ITER_FORWARD(_i) ((_i)->direction == SCOLS_ITER_FORWARD)
270 #define IS_ITER_BACKWARD(_i) ((_i)->direction == SCOLS_ITER_BACKWARD)
271
272 #define SCOLS_ITER_INIT(itr, list) \
273 do { \
274 (itr)->p = IS_ITER_FORWARD(itr) ? \
275 (list)->next : (list)->prev; \
276 (itr)->head = (list); \
277 } while(0)
278
279 #define SCOLS_ITER_ITERATE(itr, res, restype, member) \
280 do { \
281 res = list_entry((itr)->p, restype, member); \
282 (itr)->p = IS_ITER_FORWARD(itr) ? \
283 (itr)->p->next : (itr)->p->prev; \
284 } while(0)
285
286
287 static inline int scols_iter_is_last(const struct libscols_iter *itr)
288 {
289 if (!itr || !itr->head || !itr->p)
290 return 0;
291
292 return itr->p == itr->head;
293 }
294
295 /*
296 * line.c
297 */
298 int scols_line_next_group_child(struct libscols_line *ln,
299 struct libscols_iter *itr,
300 struct libscols_line **chld);
301
302
303 /*
304 * table.c
305 */
306 int scols_table_next_group(struct libscols_table *tb,
307 struct libscols_iter *itr,
308 struct libscols_group **gr);
309
310 /*
311 * grouping.c
312 */
313 void scols_ref_group(struct libscols_group *gr);
314 void scols_group_remove_children(struct libscols_group *gr);
315 void scols_group_remove_members(struct libscols_group *gr);
316 void scols_unref_group(struct libscols_group *gr);
317 void scols_groups_fix_members_order(struct libscols_table *tb);
318 int scols_groups_update_grpset(struct libscols_table *tb, struct libscols_line *ln);
319 void scols_groups_reset_state(struct libscols_table *tb);
320 struct libscols_group *scols_grpset_get_printable_children(struct libscols_table *tb);
321
322 /*
323 * walk.c
324 */
325 extern int scols_walk_tree(struct libscols_table *tb,
326 struct libscols_column *cl,
327 int (*callback)(struct libscols_table *,
328 struct libscols_line *,
329 struct libscols_column *,
330 void *),
331 void *data);
332 extern int scols_walk_is_last(struct libscols_table *tb, struct libscols_line *ln);
333
334 /*
335 * calculate.c
336 */
337 extern int __scols_calculate(struct libscols_table *tb, struct ul_buffer *buf);
338
339 /*
340 * print.c
341 */
342 extern int __cell_to_buffer(struct libscols_table *tb,
343 struct libscols_line *ln,
344 struct libscols_column *cl,
345 struct ul_buffer *buf);
346
347 void __scols_cleanup_printing(struct libscols_table *tb, struct ul_buffer *buf);
348 int __scols_initialize_printing(struct libscols_table *tb, struct ul_buffer *buf);
349 int __scols_print_tree(struct libscols_table *tb, struct ul_buffer *buf);
350 int __scols_print_table(struct libscols_table *tb, struct ul_buffer *buf);
351 int __scols_print_header(struct libscols_table *tb, struct ul_buffer *buf);
352 int __scols_print_title(struct libscols_table *tb);
353 int __scols_print_range(struct libscols_table *tb,
354 struct ul_buffer *buf,
355 struct libscols_iter *itr,
356 struct libscols_line *end);
357
358 static inline int is_tree_root(struct libscols_line *ln)
359 {
360 return ln && !ln->parent && !ln->parent_group;
361 }
362
363 static inline int is_last_tree_root(struct libscols_table *tb, struct libscols_line *ln)
364 {
365 if (!ln || !tb || tb->walk_last_tree_root != ln)
366 return 0;
367
368 return 1;
369 }
370
371 static inline int is_child(struct libscols_line *ln)
372 {
373 return ln && ln->parent;
374 }
375
376 static inline int is_last_child(struct libscols_line *ln)
377 {
378 if (!ln || !ln->parent)
379 return 0;
380
381 return list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch);
382 }
383
384 static inline int is_first_child(struct libscols_line *ln)
385 {
386 if (!ln || !ln->parent)
387 return 0;
388
389 return list_entry_is_first(&ln->ln_children, &ln->parent->ln_branch);
390 }
391
392
393 static inline int is_last_column(struct libscols_column *cl)
394 {
395 struct libscols_column *next;
396
397 if (list_entry_is_last(&cl->cl_columns, &cl->table->tb_columns))
398 return 1;
399
400 next = list_entry(cl->cl_columns.next, struct libscols_column, cl_columns);
401 if (next && scols_column_is_hidden(next) && is_last_column(next))
402 return 1;
403 return 0;
404 }
405
406 static inline int is_last_group_member(struct libscols_line *ln)
407 {
408 if (!ln || !ln->group)
409 return 0;
410
411 return list_entry_is_last(&ln->ln_groups, &ln->group->gr_members);
412 }
413
414 static inline int is_first_group_member(struct libscols_line *ln)
415 {
416 if (!ln || !ln->group)
417 return 0;
418
419 return list_entry_is_first(&ln->ln_groups, &ln->group->gr_members);
420 }
421
422 static inline int is_group_member(struct libscols_line *ln)
423 {
424 return ln && ln->group;
425 }
426
427 static inline int is_last_group_child(struct libscols_line *ln)
428 {
429 if (!ln || !ln->parent_group)
430 return 0;
431
432 return list_entry_is_last(&ln->ln_children, &ln->parent_group->gr_children);
433 }
434
435 static inline int is_group_child(struct libscols_line *ln)
436 {
437 return ln && ln->parent_group;
438 }
439
440 static inline int has_groups(struct libscols_table *tb)
441 {
442 return tb && !list_empty(&tb->tb_groups);
443 }
444
445 static inline int has_children(struct libscols_line *ln)
446 {
447 return ln && !list_empty(&ln->ln_branch);
448 }
449
450 static inline int has_group_children(struct libscols_line *ln)
451 {
452 return ln && ln->group && !list_empty(&ln->group->gr_children);
453 }
454
455 #endif /* _LIBSMARTCOLS_PRIVATE_H */