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
25 #define RH_SORT_REQUIRED 0x00000100
26 #define RH_HEADINGS_PRINTED 0x00000200
31 uint32_t report_types
;
32 const char *output_field_name_prefix
;
33 const char *field_prefix
;
35 const char *separator
;
39 /* Ordered list of fields needed for this report */
40 struct dm_list field_props
;
42 /* Rows of report data */
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 */
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
{
66 const struct dm_report_object_type
*type
;
73 struct dm_report_field
{
75 struct field_properties
*props
;
77 const char *report_string
; /* Formatted ready for display */
78 const void *sort_value
; /* Raw value for sorting */
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
,
91 const struct dm_report_object_type
*t
;
93 for (t
= rh
->types
; t
->data_fn
; t
++)
94 if (t
->id
== report_type
)
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
)
109 if (!(repstr
= dm_pool_strdup(rh
->mem
, *data
))) {
110 log_error("dm_report_field_string: dm_pool_strdup failed");
114 field
->report_string
= repstr
;
115 field
->sort_value
= (const void *) field
->report_string
;
120 int dm_report_field_int(struct dm_report
*rh
,
121 struct dm_report_field
*field
, const int *data
)
123 const int value
= *data
;
127 if (!(repstr
= dm_pool_zalloc(rh
->mem
, 13))) {
128 log_error("dm_report_field_int: dm_pool_alloc failed");
132 if (!(sortval
= dm_pool_alloc(rh
->mem
, sizeof(int64_t)))) {
133 log_error("dm_report_field_int: dm_pool_alloc failed");
137 if (dm_snprintf(repstr
, 12, "%d", value
) < 0) {
138 log_error("dm_report_field_int: int too big: %d", value
);
142 *sortval
= (const uint64_t) value
;
143 field
->sort_value
= sortval
;
144 field
->report_string
= repstr
;
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
;
156 if (!(repstr
= dm_pool_zalloc(rh
->mem
, 12))) {
157 log_error("dm_report_field_uint32: dm_pool_alloc failed");
161 if (!(sortval
= dm_pool_alloc(rh
->mem
, sizeof(uint64_t)))) {
162 log_error("dm_report_field_uint32: dm_pool_alloc failed");
166 if (dm_snprintf(repstr
, 11, "%u", value
) < 0) {
167 log_error("dm_report_field_uint32: uint32 too big: %u", value
);
171 *sortval
= (const uint64_t) value
;
172 field
->sort_value
= sortval
;
173 field
->report_string
= repstr
;
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
;
185 if (!(repstr
= dm_pool_zalloc(rh
->mem
, 13))) {
186 log_error("dm_report_field_int32: dm_pool_alloc failed");
190 if (!(sortval
= dm_pool_alloc(rh
->mem
, sizeof(int64_t)))) {
191 log_error("dm_report_field_int32: dm_pool_alloc failed");
195 if (dm_snprintf(repstr
, 12, "%d", value
) < 0) {
196 log_error("dm_report_field_int32: int32 too big: %d", value
);
200 *sortval
= (const uint64_t) value
;
201 field
->sort_value
= sortval
;
202 field
->report_string
= repstr
;
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
;
214 if (!(repstr
= dm_pool_zalloc(rh
->mem
, 22))) {
215 log_error("dm_report_field_uint64: dm_pool_alloc failed");
219 if (!(sortval
= dm_pool_alloc(rh
->mem
, sizeof(uint64_t)))) {
220 log_error("dm_report_field_uint64: dm_pool_alloc failed");
224 if (dm_snprintf(repstr
, 21, "%d", value
) < 0) {
225 log_error("dm_report_field_uint64: uint64 too big: %d", value
);
229 *sortval
= (const uint64_t) value
;
230 field
->sort_value
= sortval
;
231 field
->report_string
= repstr
;
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
;
248 static void _display_fields(struct dm_report
*rh
)
251 const struct dm_report_object_type
*type
;
252 const char *desc
, *last_desc
= "";
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
)
269 if (desc
!= last_desc
) {
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
);
288 * Initialise report handle
290 static int _copy_field(struct dm_report
*rh
, struct field_properties
*dest
,
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
);
300 log_error("dm_report: field not match: %s",
301 rh
->fields
[field_num
].id
);
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 "
319 if (!_copy_field(rh
, fp
, field_num
)) {
321 dm_pool_free(rh
->mem
, fp
);
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
);
334 dm_list_add(&rh
->field_props
, &fp
->list
);
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
)
350 if (!strncasecmp(name1
, name2
, len2
) && strlen(name1
) == len2
)
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
)
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
)
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
));
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)
399 * Add all fields with a matching type.
401 static int _add_all_fields(struct dm_report
*rh
, uint32_t type
)
405 for (f
= 0; rh
->fields
[f
].report_fn
; f
++)
406 if ((rh
->fields
[f
].type
& type
) && !_add_field(rh
, f
, 0))
412 static int _field_match(struct dm_report
*rh
, const char *field
, size_t flen
,
413 unsigned report_type_only
)
420 for (f
= 0; rh
->fields
[f
].report_fn
; f
++)
421 if (_is_same_field(rh
->fields
[f
].id
, field
, flen
,
423 if (report_type_only
) {
424 rh
->report_types
|= rh
->fields
[f
].type
;
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
;
435 return _add_all_fields(rh
, type
);
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
) {
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
)))
460 if (report_type_only
)
463 if (found
->flags
& FLD_SORT_KEY
) {
464 log_error("dm_report: Ignoring duplicate sort field: %s",
465 rh
->fields
[field_num
].id
);
469 found
->flags
|= FLD_SORT_KEY
;
470 found
->sort_posn
= rh
->keys_count
++;
471 found
->flags
|= flags
;
476 static int _key_match(struct dm_report
*rh
, const char *key
, size_t len
,
477 unsigned report_type_only
)
488 flags
= FLD_ASCENDING
;
489 } else if (*key
== '-') {
492 flags
= FLD_DESCENDING
;
494 flags
= FLD_ASCENDING
;
497 log_error("dm_report: Missing sort field name");
501 for (f
= 0; rh
->fields
[f
].report_fn
; f
++)
502 if (_is_same_field(rh
->fields
[f
].id
, key
, len
,
504 return _add_sort_key(rh
, f
, flags
, report_type_only
);
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 */
516 /* Allow consecutive commas */
517 while (*we
&& *we
== ',')
520 /* start of the field name */
522 while (*we
&& *we
!= ',')
525 if (!_field_match(rh
, ws
, (size_t) (we
- ws
), report_type_only
)) {
528 if (strcasecmp(ws
, "help") && strcmp(ws
, "?"))
529 log_error("Unrecognised field: %.*s",
530 (int) (we
- ws
), ws
);
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 */
545 /* Allow consecutive commas */
546 while (*we
&& *we
== ',')
549 while (*we
&& *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
);
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
,
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");
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
585 rh
->report_types
= *report_types
;
587 rh
->separator
= output_separator
;
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
;
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");
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)) {
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)) {
637 /* Return updated types value for further compatility check by caller */
639 *report_types
= rh
->report_types
;
644 void dm_report_free(struct dm_report
*rh
)
646 dm_pool_destroy(rh
->mem
);
650 static char *_toupperstr(char *str
)
661 int dm_report_set_output_field_name_prefix(struct dm_report
*rh
, const char *output_field_name_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");
670 rh
->output_field_name_prefix
= _toupperstr(prefix
);
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
);
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
;
693 struct dm_report_field
*field
;
696 if (!(row
= dm_pool_zalloc(rh
->mem
, sizeof(*row
)))) {
697 log_error("dm_report_object: struct row allocation failed");
703 if ((rh
->flags
& RH_SORT_REQUIRED
) &&
705 dm_pool_zalloc(rh
->mem
, sizeof(struct dm_report_field
*) *
707 log_error("dm_report_object: "
708 "row sort value structure allocation failed");
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");
724 data
= _report_get_field_data(rh
, fp
, object
);
728 if (!rh
->fields
[fp
->field_num
].report_fn(rh
, rh
->mem
,
731 log_error("dm_report_object: "
732 "report function failed for field %s",
733 rh
->fields
[fp
->field_num
].id
);
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
);
754 * Print row of headings
756 static int _report_headings(struct dm_report
*rh
)
758 struct field_properties
*fp
;
762 if (rh
->flags
& RH_HEADINGS_PRINTED
)
765 rh
->flags
|= RH_HEADINGS_PRINTED
;
767 if (!(rh
->flags
& DM_REPORT_OUTPUT_HEADINGS
))
770 if (!dm_pool_begin_object(rh
->mem
, 128)) {
771 log_error("dm_report: "
772 "dm_pool_begin_object failed for headings");
776 /* First heading line */
777 dm_list_iterate_items(fp
, &rh
->field_props
) {
778 if (fp
->flags
& FLD_HIDDEN
)
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");
788 if (!dm_pool_grow_object(rh
->mem
, buf
, fp
->width
)) {
789 log_error("dm_report: Failed to generate report headings for printing");
792 } else if (!dm_pool_grow_object(rh
->mem
, heading
, 0)) {
793 log_error("dm_report: Failed to generate report headings for printing");
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");
803 if (!dm_pool_grow_object(rh
->mem
, "\0", 1)) {
804 log_error("dm_report: Failed to generate report headings for printing");
807 log_print("%s", (char *) dm_pool_end_object(rh
->mem
));
812 dm_pool_abandon_object(rh
->mem
);
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
;
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
;
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
);
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
)[];
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");
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
);
881 dm_list_add_h(&rh
->rows
, &(*rows
)[count
]->list
);
887 * Produce report output
889 static int _output_field(struct dm_report
*rh
, struct dm_report_field
*field
)
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");
903 if (!dm_pool_grow_object(rh
->mem
, rh
->output_field_name_prefix
, 0)) {
904 log_error("dm_report: Unable to extend output line");
908 if (!dm_pool_grow_object(rh
->mem
, _toupperstr(field_id
), 0)) {
909 log_error("dm_report: Unable to extend output line");
915 if (!dm_pool_grow_object(rh
->mem
, "=", 1)) {
916 log_error("dm_report: Unable to extend output line");
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");
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");
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");
944 if (!dm_pool_grow_object(rh
->mem
, buf
, width
)) {
945 log_error("dm_report: Unable to extend output line");
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");
954 if (!dm_pool_grow_object(rh
->mem
, buf
, width
)) {
955 log_error("dm_report: Unable to extend output line");
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");
971 static int _output_as_rows(struct dm_report
*rh
)
973 struct field_properties
*fp
;
974 struct dm_report_field
*field
;
977 if (!dm_pool_begin_object(rh
->mem
, 512)) {
978 log_error("dm_report: Unable to allocate output line");
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
);
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");
996 if (!dm_pool_grow_object(rh
->mem
, rh
->separator
, 0)) {
997 log_error("dm_report: Failed to extend row with separator");
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
))
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");
1016 if (!dm_pool_grow_object(rh
->mem
, "\0", 1)) {
1017 log_error("dm_report: Failed to terminate row");
1020 log_print("%s", (char *) dm_pool_end_object(rh
->mem
));
1026 dm_pool_abandon_object(rh
->mem
);
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");
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
)
1052 if (!_output_field(rh
, field
))
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");
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");
1067 log_print("%s", (char *) dm_pool_end_object(rh
->mem
));
1068 dm_list_del(&row
->list
);
1072 dm_pool_free(rh
->mem
, row
);
1077 dm_pool_abandon_object(rh
->mem
);
1081 int dm_report_output(struct dm_report
*rh
)
1083 if (dm_list_empty(&rh
->rows
))
1086 if ((rh
->flags
& RH_SORT_REQUIRED
))
1089 if ((rh
->flags
& DM_REPORT_OUTPUT_COLUMNS_AS_ROWS
))
1090 return _output_as_rows(rh
);
1092 return _output_as_columns(rh
);