Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / libdm / libdm-report.c
blob23a301c74dece6c5c941cc9da7b3639a6ec7a94e
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of the device-mapper userspace tools.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #include "dmlib.h"
20 #include <ctype.h>
23 * Internal flags
25 #define RH_SORT_REQUIRED 0x00000100
26 #define RH_HEADINGS_PRINTED 0x00000200
28 struct dm_report {
29 struct dm_pool *mem;
31 uint32_t report_types;
32 const char *output_field_name_prefix;
33 const char *field_prefix;
34 uint32_t flags;
35 const char *separator;
37 uint32_t keys_count;
39 /* Ordered list of fields needed for this report */
40 struct dm_list field_props;
42 /* Rows of report data */
43 struct dm_list rows;
45 /* Array of field definitions */
46 const struct dm_report_field_type *fields;
47 const struct dm_report_object_type *types;
49 /* To store caller private data */
50 void *private;
54 * Internal per-field flags
56 #define FLD_HIDDEN 0x00000100
57 #define FLD_SORT_KEY 0x00000200
58 #define FLD_ASCENDING 0x00000400
59 #define FLD_DESCENDING 0x00000800
61 struct field_properties {
62 struct dm_list list;
63 uint32_t field_num;
64 uint32_t sort_posn;
65 int32_t width;
66 const struct dm_report_object_type *type;
67 uint32_t flags;
71 * Report data field
73 struct dm_report_field {
74 struct dm_list list;
75 struct field_properties *props;
77 const char *report_string; /* Formatted ready for display */
78 const void *sort_value; /* Raw value for sorting */
81 struct row {
82 struct dm_list list;
83 struct dm_report *rh;
84 struct dm_list fields; /* Fields in display order */
85 struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
88 static const struct dm_report_object_type *_find_type(struct dm_report *rh,
89 uint32_t report_type)
91 const struct dm_report_object_type *t;
93 for (t = rh->types; t->data_fn; t++)
94 if (t->id == report_type)
95 return t;
97 return NULL;
101 * Data-munging functions to prepare each data type for display and sorting
104 int dm_report_field_string(struct dm_report *rh,
105 struct dm_report_field *field, const char **data)
107 char *repstr;
109 if (!(repstr = dm_pool_strdup(rh->mem, *data))) {
110 log_error("dm_report_field_string: dm_pool_strdup failed");
111 return 0;
114 field->report_string = repstr;
115 field->sort_value = (const void *) field->report_string;
117 return 1;
120 int dm_report_field_int(struct dm_report *rh,
121 struct dm_report_field *field, const int *data)
123 const int value = *data;
124 uint64_t *sortval;
125 char *repstr;
127 if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
128 log_error("dm_report_field_int: dm_pool_alloc failed");
129 return 0;
132 if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
133 log_error("dm_report_field_int: dm_pool_alloc failed");
134 return 0;
137 if (dm_snprintf(repstr, 12, "%d", value) < 0) {
138 log_error("dm_report_field_int: int too big: %d", value);
139 return 0;
142 *sortval = (const uint64_t) value;
143 field->sort_value = sortval;
144 field->report_string = repstr;
146 return 1;
149 int dm_report_field_uint32(struct dm_report *rh,
150 struct dm_report_field *field, const uint32_t *data)
152 const uint32_t value = *data;
153 uint64_t *sortval;
154 char *repstr;
156 if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
157 log_error("dm_report_field_uint32: dm_pool_alloc failed");
158 return 0;
161 if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
162 log_error("dm_report_field_uint32: dm_pool_alloc failed");
163 return 0;
166 if (dm_snprintf(repstr, 11, "%u", value) < 0) {
167 log_error("dm_report_field_uint32: uint32 too big: %u", value);
168 return 0;
171 *sortval = (const uint64_t) value;
172 field->sort_value = sortval;
173 field->report_string = repstr;
175 return 1;
178 int dm_report_field_int32(struct dm_report *rh,
179 struct dm_report_field *field, const int32_t *data)
181 const int32_t value = *data;
182 uint64_t *sortval;
183 char *repstr;
185 if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
186 log_error("dm_report_field_int32: dm_pool_alloc failed");
187 return 0;
190 if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
191 log_error("dm_report_field_int32: dm_pool_alloc failed");
192 return 0;
195 if (dm_snprintf(repstr, 12, "%d", value) < 0) {
196 log_error("dm_report_field_int32: int32 too big: %d", value);
197 return 0;
200 *sortval = (const uint64_t) value;
201 field->sort_value = sortval;
202 field->report_string = repstr;
204 return 1;
207 int dm_report_field_uint64(struct dm_report *rh,
208 struct dm_report_field *field, const uint64_t *data)
210 const int value = *data;
211 uint64_t *sortval;
212 char *repstr;
214 if (!(repstr = dm_pool_zalloc(rh->mem, 22))) {
215 log_error("dm_report_field_uint64: dm_pool_alloc failed");
216 return 0;
219 if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
220 log_error("dm_report_field_uint64: dm_pool_alloc failed");
221 return 0;
224 if (dm_snprintf(repstr, 21, "%d", value) < 0) {
225 log_error("dm_report_field_uint64: uint64 too big: %d", value);
226 return 0;
229 *sortval = (const uint64_t) value;
230 field->sort_value = sortval;
231 field->report_string = repstr;
233 return 1;
237 * Helper functions for custom report functions
239 void dm_report_field_set_value(struct dm_report_field *field, const void *value, const void *sortvalue)
241 field->report_string = (const char *) value;
242 field->sort_value = sortvalue ? : value;
246 * show help message
248 static void _display_fields(struct dm_report *rh)
250 uint32_t f;
251 const struct dm_report_object_type *type;
252 const char *desc, *last_desc = "";
253 size_t id_len = 0;
255 for (f = 0; rh->fields[f].report_fn; f++)
256 if (strlen(rh->fields[f].id) > id_len)
257 id_len = strlen(rh->fields[f].id);
260 for (type = rh->types; type->data_fn; type++)
261 if (strlen(type->prefix) + 3 > id_len)
262 id_len = strlen(type->prefix) + 3;
264 for (f = 0; rh->fields[f].report_fn; f++) {
265 if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
266 desc = type->desc;
267 else
268 desc = " ";
269 if (desc != last_desc) {
270 if (*last_desc)
271 log_warn(" ");
272 log_warn("%s Fields", desc);
273 log_warn("%*.*s", (int) strlen(desc) + 7,
274 (int) strlen(desc) + 7,
275 "-------------------------------------------------------------------------------");
276 log_warn(" %sall%-*s - %s", type->prefix,
277 (int) (id_len - 3 - strlen(type->prefix)), "",
278 "All fields in this section.");
281 /* FIXME Add line-wrapping at terminal width (or 80 cols) */
282 log_warn(" %-*s - %s", (int) id_len, rh->fields[f].id, rh->fields[f].desc);
283 last_desc = desc;
288 * Initialise report handle
290 static int _copy_field(struct dm_report *rh, struct field_properties *dest,
291 uint32_t field_num)
293 dest->field_num = field_num;
294 dest->width = rh->fields[field_num].width;
295 dest->flags = rh->fields[field_num].flags & DM_REPORT_FIELD_MASK;
297 /* set object type method */
298 dest->type = _find_type(rh, rh->fields[field_num].type);
299 if (!dest->type) {
300 log_error("dm_report: field not match: %s",
301 rh->fields[field_num].id);
302 return 0;
305 return 1;
308 static struct field_properties * _add_field(struct dm_report *rh,
309 uint32_t field_num, uint32_t flags)
311 struct field_properties *fp;
313 if (!(fp = dm_pool_zalloc(rh->mem, sizeof(struct field_properties)))) {
314 log_error("dm_report: struct field_properties allocation "
315 "failed");
316 return NULL;
319 if (!_copy_field(rh, fp, field_num)) {
320 stack;
321 dm_pool_free(rh->mem, fp);
322 return NULL;
325 fp->flags |= flags;
328 * Place hidden fields at the front so dm_list_end() will
329 * tell us when we've reached the last visible field.
331 if (fp->flags & FLD_HIDDEN)
332 dm_list_add_h(&rh->field_props, &fp->list);
333 else
334 dm_list_add(&rh->field_props, &fp->list);
336 return fp;
340 * Compare name1 against name2 or prefix plus name2
341 * name2 is not necessarily null-terminated.
342 * len2 is the length of name2.
344 static int _is_same_field(const char *name1, const char *name2,
345 size_t len2, const char *prefix)
347 size_t prefix_len;
349 /* Exact match? */
350 if (!strncasecmp(name1, name2, len2) && strlen(name1) == len2)
351 return 1;
353 /* Match including prefix? */
354 prefix_len = strlen(prefix);
355 if (!strncasecmp(prefix, name1, prefix_len) &&
356 !strncasecmp(name1 + prefix_len, name2, len2) &&
357 strlen(name1) == prefix_len + len2)
358 return 1;
360 return 0;
364 * Check for a report type prefix + "all" match.
366 static uint32_t _all_match(struct dm_report *rh, const char *field, size_t flen)
368 size_t prefix_len;
369 const struct dm_report_object_type *t;
370 char prefixed_all[32];
372 if (!strncasecmp(field, "all", 3) && flen == 3) {
373 if (strlen(rh->field_prefix)) {
374 strcpy(prefixed_all, rh->field_prefix);
375 strcat(prefixed_all, "all");
377 * Add also prefix to receive all attributes
378 * (e.g.LABEL/PVS use the same prefix)
380 return rh->report_types |
381 _all_match(rh, prefixed_all,
382 strlen(prefixed_all));
383 } else
384 return rh->report_types;
387 for (t = rh->types; t->data_fn; t++) {
388 prefix_len = strlen(t->prefix);
389 if (!strncasecmp(t->prefix, field, prefix_len) &&
390 !strncasecmp(field + prefix_len, "all", 3) &&
391 flen == prefix_len + 3)
392 return t->id;
395 return 0;
399 * Add all fields with a matching type.
401 static int _add_all_fields(struct dm_report *rh, uint32_t type)
403 uint32_t f;
405 for (f = 0; rh->fields[f].report_fn; f++)
406 if ((rh->fields[f].type & type) && !_add_field(rh, f, 0))
407 return 0;
409 return 1;
412 static int _field_match(struct dm_report *rh, const char *field, size_t flen,
413 unsigned report_type_only)
415 uint32_t f, type;
417 if (!flen)
418 return 0;
420 for (f = 0; rh->fields[f].report_fn; f++)
421 if (_is_same_field(rh->fields[f].id, field, flen,
422 rh->field_prefix)) {
423 if (report_type_only) {
424 rh->report_types |= rh->fields[f].type;
425 return 1;
426 } else
427 return _add_field(rh, f, 0) ? 1 : 0;
430 if ((type = _all_match(rh, field, flen))) {
431 if (report_type_only) {
432 rh->report_types |= type;
433 return 1;
434 } else
435 return _add_all_fields(rh, type);
438 return 0;
441 static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
442 uint32_t flags, unsigned report_type_only)
444 struct field_properties *fp, *found = NULL;
446 dm_list_iterate_items(fp, &rh->field_props) {
447 if (fp->field_num == field_num) {
448 found = fp;
449 break;
453 if (!found) {
454 if (report_type_only)
455 rh->report_types |= rh->fields[field_num].type;
456 else if (!(found = _add_field(rh, field_num, FLD_HIDDEN)))
457 return_0;
460 if (report_type_only)
461 return 1;
463 if (found->flags & FLD_SORT_KEY) {
464 log_error("dm_report: Ignoring duplicate sort field: %s",
465 rh->fields[field_num].id);
466 return 1;
469 found->flags |= FLD_SORT_KEY;
470 found->sort_posn = rh->keys_count++;
471 found->flags |= flags;
473 return 1;
476 static int _key_match(struct dm_report *rh, const char *key, size_t len,
477 unsigned report_type_only)
479 uint32_t f;
480 uint32_t flags;
482 if (!len)
483 return 0;
485 if (*key == '+') {
486 key++;
487 len--;
488 flags = FLD_ASCENDING;
489 } else if (*key == '-') {
490 key++;
491 len--;
492 flags = FLD_DESCENDING;
493 } else
494 flags = FLD_ASCENDING;
496 if (!len) {
497 log_error("dm_report: Missing sort field name");
498 return 0;
501 for (f = 0; rh->fields[f].report_fn; f++)
502 if (_is_same_field(rh->fields[f].id, key, len,
503 rh->field_prefix))
504 return _add_sort_key(rh, f, flags, report_type_only);
506 return 0;
509 static int _parse_fields(struct dm_report *rh, const char *format,
510 unsigned report_type_only)
512 const char *ws; /* Word start */
513 const char *we = format; /* Word end */
515 while (*we) {
516 /* Allow consecutive commas */
517 while (*we && *we == ',')
518 we++;
520 /* start of the field name */
521 ws = we;
522 while (*we && *we != ',')
523 we++;
525 if (!_field_match(rh, ws, (size_t) (we - ws), report_type_only)) {
526 _display_fields(rh);
527 log_warn(" ");
528 if (strcasecmp(ws, "help") && strcmp(ws, "?"))
529 log_error("Unrecognised field: %.*s",
530 (int) (we - ws), ws);
531 return 0;
535 return 1;
538 static int _parse_keys(struct dm_report *rh, const char *keys,
539 unsigned report_type_only)
541 const char *ws; /* Word start */
542 const char *we = keys; /* Word end */
544 while (*we) {
545 /* Allow consecutive commas */
546 while (*we && *we == ',')
547 we++;
548 ws = we;
549 while (*we && *we != ',')
550 we++;
551 if (!_key_match(rh, ws, (size_t) (we - ws), report_type_only)) {
552 log_error("dm_report: Unrecognised field: %.*s",
553 (int) (we - ws), ws);
554 return 0;
558 return 1;
561 struct dm_report *dm_report_init(uint32_t *report_types,
562 const struct dm_report_object_type *types,
563 const struct dm_report_field_type *fields,
564 const char *output_fields,
565 const char *output_separator,
566 uint32_t output_flags,
567 const char *sort_keys,
568 void *private)
570 struct dm_report *rh;
571 const struct dm_report_object_type *type;
573 if (!(rh = dm_malloc(sizeof(*rh)))) {
574 log_error("dm_report_init: dm_malloc failed");
575 return 0;
577 memset(rh, 0, sizeof(*rh));
580 * rh->report_types is updated in _parse_fields() and _parse_keys()
581 * to contain all types corresponding to the fields specified by
582 * fields or keys.
584 if (report_types)
585 rh->report_types = *report_types;
587 rh->separator = output_separator;
588 rh->fields = fields;
589 rh->types = types;
590 rh->private = private;
592 rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK;
594 /* With columns_as_rows we must buffer and not align. */
595 if (output_flags & DM_REPORT_OUTPUT_COLUMNS_AS_ROWS) {
596 if (!(output_flags & DM_REPORT_OUTPUT_BUFFERED))
597 rh->flags |= DM_REPORT_OUTPUT_BUFFERED;
598 if (output_flags & DM_REPORT_OUTPUT_ALIGNED)
599 rh->flags &= ~DM_REPORT_OUTPUT_ALIGNED;
602 if (output_flags & DM_REPORT_OUTPUT_BUFFERED)
603 rh->flags |= RH_SORT_REQUIRED;
605 dm_list_init(&rh->field_props);
606 dm_list_init(&rh->rows);
608 if ((type = _find_type(rh, rh->report_types)) && type->prefix)
609 rh->field_prefix = type->prefix;
610 else
611 rh->field_prefix = "";
613 if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
614 log_error("dm_report_init: allocation of memory pool failed");
615 dm_free(rh);
616 return NULL;
620 * To keep the code needed to add the "all" field to a minimum, we parse
621 * the field lists twice. The first time we only update the report type.
622 * FIXME Use one pass instead and expand the "all" field afterwards.
624 if (!_parse_fields(rh, output_fields, 1) ||
625 !_parse_keys(rh, sort_keys, 1)) {
626 dm_report_free(rh);
627 return NULL;
630 /* Generate list of fields for output based on format string & flags */
631 if (!_parse_fields(rh, output_fields, 0) ||
632 !_parse_keys(rh, sort_keys, 0)) {
633 dm_report_free(rh);
634 return NULL;
637 /* Return updated types value for further compatility check by caller */
638 if (report_types)
639 *report_types = rh->report_types;
641 return rh;
644 void dm_report_free(struct dm_report *rh)
646 dm_pool_destroy(rh->mem);
647 dm_free(rh);
650 static char *_toupperstr(char *str)
652 char *u = str;
655 *u = toupper(*u);
656 while (*u++);
658 return str;
661 int dm_report_set_output_field_name_prefix(struct dm_report *rh, const char *output_field_name_prefix)
663 char *prefix;
665 if (!(prefix = dm_pool_strdup(rh->mem, output_field_name_prefix))) {
666 log_error("dm_report_set_output_field_name_prefix: dm_pool_strdup failed");
667 return 0;
670 rh->output_field_name_prefix = _toupperstr(prefix);
672 return 1;
676 * Create a row of data for an object
678 static void * _report_get_field_data(struct dm_report *rh,
679 struct field_properties *fp, void *object)
681 void *ret = fp->type->data_fn(object);
683 if (!ret)
684 return NULL;
686 return ret + rh->fields[fp->field_num].offset;
689 int dm_report_object(struct dm_report *rh, void *object)
691 struct field_properties *fp;
692 struct row *row;
693 struct dm_report_field *field;
694 void *data = NULL;
696 if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
697 log_error("dm_report_object: struct row allocation failed");
698 return 0;
701 row->rh = rh;
703 if ((rh->flags & RH_SORT_REQUIRED) &&
704 !(row->sort_fields =
705 dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) *
706 rh->keys_count))) {
707 log_error("dm_report_object: "
708 "row sort value structure allocation failed");
709 return 0;
712 dm_list_init(&row->fields);
713 dm_list_add(&rh->rows, &row->list);
715 /* For each field to be displayed, call its report_fn */
716 dm_list_iterate_items(fp, &rh->field_props) {
717 if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
718 log_error("dm_report_object: "
719 "struct dm_report_field allocation failed");
720 return 0;
722 field->props = fp;
724 data = _report_get_field_data(rh, fp, object);
725 if (!data)
726 return 0;
728 if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
729 field, data,
730 rh->private)) {
731 log_error("dm_report_object: "
732 "report function failed for field %s",
733 rh->fields[fp->field_num].id);
734 return 0;
737 if ((strlen(field->report_string) > field->props->width))
738 field->props->width = strlen(field->report_string);
740 if ((rh->flags & RH_SORT_REQUIRED) &&
741 (field->props->flags & FLD_SORT_KEY)) {
742 (*row->sort_fields)[field->props->sort_posn] = field;
744 dm_list_add(&row->fields, &field->list);
747 if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
748 return dm_report_output(rh);
750 return 1;
754 * Print row of headings
756 static int _report_headings(struct dm_report *rh)
758 struct field_properties *fp;
759 const char *heading;
760 char buf[1024];
762 if (rh->flags & RH_HEADINGS_PRINTED)
763 return 1;
765 rh->flags |= RH_HEADINGS_PRINTED;
767 if (!(rh->flags & DM_REPORT_OUTPUT_HEADINGS))
768 return 1;
770 if (!dm_pool_begin_object(rh->mem, 128)) {
771 log_error("dm_report: "
772 "dm_pool_begin_object failed for headings");
773 return 0;
776 /* First heading line */
777 dm_list_iterate_items(fp, &rh->field_props) {
778 if (fp->flags & FLD_HIDDEN)
779 continue;
781 heading = rh->fields[fp->field_num].heading;
782 if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
783 if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
784 fp->width, fp->width, heading) < 0) {
785 log_error("dm_report: snprintf heading failed");
786 goto bad;
788 if (!dm_pool_grow_object(rh->mem, buf, fp->width)) {
789 log_error("dm_report: Failed to generate report headings for printing");
790 goto bad;
792 } else if (!dm_pool_grow_object(rh->mem, heading, 0)) {
793 log_error("dm_report: Failed to generate report headings for printing");
794 goto bad;
797 if (!dm_list_end(&rh->field_props, &fp->list))
798 if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
799 log_error("dm_report: Failed to generate report headings for printing");
800 goto bad;
803 if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
804 log_error("dm_report: Failed to generate report headings for printing");
805 goto bad;
807 log_print("%s", (char *) dm_pool_end_object(rh->mem));
809 return 1;
811 bad:
812 dm_pool_abandon_object(rh->mem);
813 return 0;
817 * Sort rows of data
819 static int _row_compare(const void *a, const void *b)
821 const struct row *rowa = *(const struct row **) a;
822 const struct row *rowb = *(const struct row **) b;
823 const struct dm_report_field *sfa, *sfb;
824 uint32_t cnt;
826 for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
827 sfa = (*rowa->sort_fields)[cnt];
828 sfb = (*rowb->sort_fields)[cnt];
829 if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) {
830 const uint64_t numa =
831 *(const uint64_t *) sfa->sort_value;
832 const uint64_t numb =
833 *(const uint64_t *) sfb->sort_value;
835 if (numa == numb)
836 continue;
838 if (sfa->props->flags & FLD_ASCENDING) {
839 return (numa > numb) ? 1 : -1;
840 } else { /* FLD_DESCENDING */
841 return (numa < numb) ? 1 : -1;
843 } else { /* DM_REPORT_FIELD_TYPE_STRING */
844 const char *stra = (const char *) sfa->sort_value;
845 const char *strb = (const char *) sfb->sort_value;
846 int cmp = strcmp(stra, strb);
848 if (!cmp)
849 continue;
851 if (sfa->props->flags & FLD_ASCENDING) {
852 return (cmp > 0) ? 1 : -1;
853 } else { /* FLD_DESCENDING */
854 return (cmp < 0) ? 1 : -1;
859 return 0; /* Identical */
862 static int _sort_rows(struct dm_report *rh)
864 struct row *(*rows)[];
865 uint32_t count = 0;
866 struct row *row;
868 if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
869 dm_list_size(&rh->rows)))) {
870 log_error("dm_report: sort array allocation failed");
871 return 0;
874 dm_list_iterate_items(row, &rh->rows)
875 (*rows)[count++] = row;
877 qsort(rows, count, sizeof(**rows), _row_compare);
879 dm_list_init(&rh->rows);
880 while (count--)
881 dm_list_add_h(&rh->rows, &(*rows)[count]->list);
883 return 1;
887 * Produce report output
889 static int _output_field(struct dm_report *rh, struct dm_report_field *field)
891 char *field_id;
892 int32_t width;
893 uint32_t align;
894 const char *repstr;
895 char buf[4096];
897 if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
898 if (!(field_id = strdup(rh->fields[field->props->field_num].id))) {
899 log_error("dm_report: Failed to copy field name");
900 return 0;
903 if (!dm_pool_grow_object(rh->mem, rh->output_field_name_prefix, 0)) {
904 log_error("dm_report: Unable to extend output line");
905 return 0;
908 if (!dm_pool_grow_object(rh->mem, _toupperstr(field_id), 0)) {
909 log_error("dm_report: Unable to extend output line");
910 return 0;
913 free(field_id);
915 if (!dm_pool_grow_object(rh->mem, "=", 1)) {
916 log_error("dm_report: Unable to extend output line");
917 return 0;
920 if (!(rh->flags & DM_REPORT_OUTPUT_FIELD_UNQUOTED) &&
921 !dm_pool_grow_object(rh->mem, "\'", 1)) {
922 log_error("dm_report: Unable to extend output line");
923 return 0;
927 repstr = field->report_string;
928 width = field->props->width;
929 if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
930 if (!dm_pool_grow_object(rh->mem, repstr, 0)) {
931 log_error("dm_report: Unable to extend output line");
932 return 0;
934 } else {
935 if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
936 align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ?
937 DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
938 if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
939 if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
940 width, width, repstr) < 0) {
941 log_error("dm_report: left-aligned snprintf() failed");
942 return 0;
944 if (!dm_pool_grow_object(rh->mem, buf, width)) {
945 log_error("dm_report: Unable to extend output line");
946 return 0;
948 } else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
949 if (dm_snprintf(buf, sizeof(buf), "%*.*s",
950 width, width, repstr) < 0) {
951 log_error("dm_report: right-aligned snprintf() failed");
952 return 0;
954 if (!dm_pool_grow_object(rh->mem, buf, width)) {
955 log_error("dm_report: Unable to extend output line");
956 return 0;
961 if ((rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) &&
962 !(rh->flags & DM_REPORT_OUTPUT_FIELD_UNQUOTED))
963 if (!dm_pool_grow_object(rh->mem, "\'", 1)) {
964 log_error("dm_report: Unable to extend output line");
965 return 0;
968 return 1;
971 static int _output_as_rows(struct dm_report *rh)
973 struct field_properties *fp;
974 struct dm_report_field *field;
975 struct row *row;
977 if (!dm_pool_begin_object(rh->mem, 512)) {
978 log_error("dm_report: Unable to allocate output line");
979 return 0;
982 dm_list_iterate_items(fp, &rh->field_props) {
983 if (fp->flags & FLD_HIDDEN) {
984 dm_list_iterate_items(row, &rh->rows) {
985 field = dm_list_item(dm_list_first(&row->fields), struct dm_report_field);
986 dm_list_del(&field->list);
988 continue;
991 if ((rh->flags & DM_REPORT_OUTPUT_HEADINGS)) {
992 if (!dm_pool_grow_object(rh->mem, rh->fields[fp->field_num].heading, 0)) {
993 log_error("dm_report: Failed to extend row for field name");
994 goto bad;
996 if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
997 log_error("dm_report: Failed to extend row with separator");
998 goto bad;
1002 dm_list_iterate_items(row, &rh->rows) {
1003 if ((field = dm_list_item(dm_list_first(&row->fields), struct dm_report_field))) {
1004 if (!_output_field(rh, field))
1005 goto bad;
1006 dm_list_del(&field->list);
1009 if (!dm_list_end(&rh->rows, &row->list))
1010 if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
1011 log_error("dm_report: Unable to extend output line");
1012 goto bad;
1016 if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
1017 log_error("dm_report: Failed to terminate row");
1018 goto bad;
1020 log_print("%s", (char *) dm_pool_end_object(rh->mem));
1023 return 1;
1025 bad:
1026 dm_pool_abandon_object(rh->mem);
1027 return 0;
1030 static int _output_as_columns(struct dm_report *rh)
1032 struct dm_list *fh, *rowh, *ftmp, *rtmp;
1033 struct row *row = NULL;
1034 struct dm_report_field *field;
1036 /* If headings not printed yet, calculate field widths and print them */
1037 if (!(rh->flags & RH_HEADINGS_PRINTED))
1038 _report_headings(rh);
1040 /* Print and clear buffer */
1041 dm_list_iterate_safe(rowh, rtmp, &rh->rows) {
1042 if (!dm_pool_begin_object(rh->mem, 512)) {
1043 log_error("dm_report: Unable to allocate output line");
1044 return 0;
1046 row = dm_list_item(rowh, struct row);
1047 dm_list_iterate_safe(fh, ftmp, &row->fields) {
1048 field = dm_list_item(fh, struct dm_report_field);
1049 if (field->props->flags & FLD_HIDDEN)
1050 continue;
1052 if (!_output_field(rh, field))
1053 goto bad;
1055 if (!dm_list_end(&row->fields, fh))
1056 if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
1057 log_error("dm_report: Unable to extend output line");
1058 goto bad;
1061 dm_list_del(&field->list);
1063 if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
1064 log_error("dm_report: Unable to terminate output line");
1065 goto bad;
1067 log_print("%s", (char *) dm_pool_end_object(rh->mem));
1068 dm_list_del(&row->list);
1071 if (row)
1072 dm_pool_free(rh->mem, row);
1074 return 1;
1076 bad:
1077 dm_pool_abandon_object(rh->mem);
1078 return 0;
1081 int dm_report_output(struct dm_report *rh)
1083 if (dm_list_empty(&rh->rows))
1084 return 1;
1086 if ((rh->flags & RH_SORT_REQUIRED))
1087 _sort_rows(rh);
1089 if ((rh->flags & DM_REPORT_OUTPUT_COLUMNS_AS_ROWS))
1090 return _output_as_rows(rh);
1091 else
1092 return _output_as_columns(rh);