1*7c604eeaShaad /* $NetBSD: libdm-report.c,v 1.1.1.3 2009/12/02 00:26:08 haad Exp $ */
256a34939Shaad
356a34939Shaad /*
456a34939Shaad * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
556a34939Shaad * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
656a34939Shaad *
756a34939Shaad * This file is part of the device-mapper userspace tools.
856a34939Shaad *
956a34939Shaad * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad *
1356a34939Shaad * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1656a34939Shaad */
1756a34939Shaad
1856a34939Shaad #include "dmlib.h"
1956a34939Shaad
2056a34939Shaad #include <ctype.h>
2156a34939Shaad
2256a34939Shaad /*
2356a34939Shaad * Internal flags
2456a34939Shaad */
2556a34939Shaad #define RH_SORT_REQUIRED 0x00000100
2656a34939Shaad #define RH_HEADINGS_PRINTED 0x00000200
2756a34939Shaad
2856a34939Shaad struct dm_report {
2956a34939Shaad struct dm_pool *mem;
3056a34939Shaad
3156a34939Shaad uint32_t report_types;
3256a34939Shaad const char *output_field_name_prefix;
3356a34939Shaad const char *field_prefix;
3456a34939Shaad uint32_t flags;
3556a34939Shaad const char *separator;
3656a34939Shaad
3756a34939Shaad uint32_t keys_count;
3856a34939Shaad
3956a34939Shaad /* Ordered list of fields needed for this report */
4056a34939Shaad struct dm_list field_props;
4156a34939Shaad
4256a34939Shaad /* Rows of report data */
4356a34939Shaad struct dm_list rows;
4456a34939Shaad
4556a34939Shaad /* Array of field definitions */
4656a34939Shaad const struct dm_report_field_type *fields;
4756a34939Shaad const struct dm_report_object_type *types;
4856a34939Shaad
4956a34939Shaad /* To store caller private data */
5056a34939Shaad void *private;
5156a34939Shaad };
5256a34939Shaad
5356a34939Shaad /*
5456a34939Shaad * Internal per-field flags
5556a34939Shaad */
5656a34939Shaad #define FLD_HIDDEN 0x00000100
5756a34939Shaad #define FLD_SORT_KEY 0x00000200
5856a34939Shaad #define FLD_ASCENDING 0x00000400
5956a34939Shaad #define FLD_DESCENDING 0x00000800
6056a34939Shaad
6156a34939Shaad struct field_properties {
6256a34939Shaad struct dm_list list;
6356a34939Shaad uint32_t field_num;
6456a34939Shaad uint32_t sort_posn;
6556a34939Shaad int32_t width;
6656a34939Shaad const struct dm_report_object_type *type;
6756a34939Shaad uint32_t flags;
6856a34939Shaad };
6956a34939Shaad
7056a34939Shaad /*
7156a34939Shaad * Report data field
7256a34939Shaad */
7356a34939Shaad struct dm_report_field {
7456a34939Shaad struct dm_list list;
7556a34939Shaad struct field_properties *props;
7656a34939Shaad
7756a34939Shaad const char *report_string; /* Formatted ready for display */
7856a34939Shaad const void *sort_value; /* Raw value for sorting */
7956a34939Shaad };
8056a34939Shaad
8156a34939Shaad struct row {
8256a34939Shaad struct dm_list list;
8356a34939Shaad struct dm_report *rh;
8456a34939Shaad struct dm_list fields; /* Fields in display order */
8556a34939Shaad struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
8656a34939Shaad };
8756a34939Shaad
_find_type(struct dm_report * rh,uint32_t report_type)8856a34939Shaad static const struct dm_report_object_type *_find_type(struct dm_report *rh,
8956a34939Shaad uint32_t report_type)
9056a34939Shaad {
9156a34939Shaad const struct dm_report_object_type *t;
9256a34939Shaad
9356a34939Shaad for (t = rh->types; t->data_fn; t++)
9456a34939Shaad if (t->id == report_type)
9556a34939Shaad return t;
9656a34939Shaad
9756a34939Shaad return NULL;
9856a34939Shaad }
9956a34939Shaad
10056a34939Shaad /*
10156a34939Shaad * Data-munging functions to prepare each data type for display and sorting
10256a34939Shaad */
10356a34939Shaad
dm_report_field_string(struct dm_report * rh,struct dm_report_field * field,const char ** data)10456a34939Shaad int dm_report_field_string(struct dm_report *rh,
10556a34939Shaad struct dm_report_field *field, const char **data)
10656a34939Shaad {
10756a34939Shaad char *repstr;
10856a34939Shaad
10956a34939Shaad if (!(repstr = dm_pool_strdup(rh->mem, *data))) {
11056a34939Shaad log_error("dm_report_field_string: dm_pool_strdup failed");
11156a34939Shaad return 0;
11256a34939Shaad }
11356a34939Shaad
11456a34939Shaad field->report_string = repstr;
11556a34939Shaad field->sort_value = (const void *) field->report_string;
11656a34939Shaad
11756a34939Shaad return 1;
11856a34939Shaad }
11956a34939Shaad
dm_report_field_int(struct dm_report * rh,struct dm_report_field * field,const int * data)12056a34939Shaad int dm_report_field_int(struct dm_report *rh,
12156a34939Shaad struct dm_report_field *field, const int *data)
12256a34939Shaad {
12356a34939Shaad const int value = *data;
12456a34939Shaad uint64_t *sortval;
12556a34939Shaad char *repstr;
12656a34939Shaad
12756a34939Shaad if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
12856a34939Shaad log_error("dm_report_field_int: dm_pool_alloc failed");
12956a34939Shaad return 0;
13056a34939Shaad }
13156a34939Shaad
13256a34939Shaad if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
13356a34939Shaad log_error("dm_report_field_int: dm_pool_alloc failed");
13456a34939Shaad return 0;
13556a34939Shaad }
13656a34939Shaad
13756a34939Shaad if (dm_snprintf(repstr, 12, "%d", value) < 0) {
13856a34939Shaad log_error("dm_report_field_int: int too big: %d", value);
13956a34939Shaad return 0;
14056a34939Shaad }
14156a34939Shaad
14256a34939Shaad *sortval = (const uint64_t) value;
14356a34939Shaad field->sort_value = sortval;
14456a34939Shaad field->report_string = repstr;
14556a34939Shaad
14656a34939Shaad return 1;
14756a34939Shaad }
14856a34939Shaad
dm_report_field_uint32(struct dm_report * rh,struct dm_report_field * field,const uint32_t * data)14956a34939Shaad int dm_report_field_uint32(struct dm_report *rh,
15056a34939Shaad struct dm_report_field *field, const uint32_t *data)
15156a34939Shaad {
15256a34939Shaad const uint32_t value = *data;
15356a34939Shaad uint64_t *sortval;
15456a34939Shaad char *repstr;
15556a34939Shaad
15656a34939Shaad if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
15756a34939Shaad log_error("dm_report_field_uint32: dm_pool_alloc failed");
15856a34939Shaad return 0;
15956a34939Shaad }
16056a34939Shaad
16156a34939Shaad if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
16256a34939Shaad log_error("dm_report_field_uint32: dm_pool_alloc failed");
16356a34939Shaad return 0;
16456a34939Shaad }
16556a34939Shaad
16656a34939Shaad if (dm_snprintf(repstr, 11, "%u", value) < 0) {
16756a34939Shaad log_error("dm_report_field_uint32: uint32 too big: %u", value);
16856a34939Shaad return 0;
16956a34939Shaad }
17056a34939Shaad
17156a34939Shaad *sortval = (const uint64_t) value;
17256a34939Shaad field->sort_value = sortval;
17356a34939Shaad field->report_string = repstr;
17456a34939Shaad
17556a34939Shaad return 1;
17656a34939Shaad }
17756a34939Shaad
dm_report_field_int32(struct dm_report * rh,struct dm_report_field * field,const int32_t * data)17856a34939Shaad int dm_report_field_int32(struct dm_report *rh,
17956a34939Shaad struct dm_report_field *field, const int32_t *data)
18056a34939Shaad {
18156a34939Shaad const int32_t value = *data;
18256a34939Shaad uint64_t *sortval;
18356a34939Shaad char *repstr;
18456a34939Shaad
18556a34939Shaad if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
18656a34939Shaad log_error("dm_report_field_int32: dm_pool_alloc failed");
18756a34939Shaad return 0;
18856a34939Shaad }
18956a34939Shaad
19056a34939Shaad if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
19156a34939Shaad log_error("dm_report_field_int32: dm_pool_alloc failed");
19256a34939Shaad return 0;
19356a34939Shaad }
19456a34939Shaad
19556a34939Shaad if (dm_snprintf(repstr, 12, "%d", value) < 0) {
19656a34939Shaad log_error("dm_report_field_int32: int32 too big: %d", value);
19756a34939Shaad return 0;
19856a34939Shaad }
19956a34939Shaad
20056a34939Shaad *sortval = (const uint64_t) value;
20156a34939Shaad field->sort_value = sortval;
20256a34939Shaad field->report_string = repstr;
20356a34939Shaad
20456a34939Shaad return 1;
20556a34939Shaad }
20656a34939Shaad
dm_report_field_uint64(struct dm_report * rh,struct dm_report_field * field,const uint64_t * data)20756a34939Shaad int dm_report_field_uint64(struct dm_report *rh,
20856a34939Shaad struct dm_report_field *field, const uint64_t *data)
20956a34939Shaad {
21056a34939Shaad const int value = *data;
21156a34939Shaad uint64_t *sortval;
21256a34939Shaad char *repstr;
21356a34939Shaad
21456a34939Shaad if (!(repstr = dm_pool_zalloc(rh->mem, 22))) {
21556a34939Shaad log_error("dm_report_field_uint64: dm_pool_alloc failed");
21656a34939Shaad return 0;
21756a34939Shaad }
21856a34939Shaad
21956a34939Shaad if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
22056a34939Shaad log_error("dm_report_field_uint64: dm_pool_alloc failed");
22156a34939Shaad return 0;
22256a34939Shaad }
22356a34939Shaad
22456a34939Shaad if (dm_snprintf(repstr, 21, "%d", value) < 0) {
22556a34939Shaad log_error("dm_report_field_uint64: uint64 too big: %d", value);
22656a34939Shaad return 0;
22756a34939Shaad }
22856a34939Shaad
22956a34939Shaad *sortval = (const uint64_t) value;
23056a34939Shaad field->sort_value = sortval;
23156a34939Shaad field->report_string = repstr;
23256a34939Shaad
23356a34939Shaad return 1;
23456a34939Shaad }
23556a34939Shaad
23656a34939Shaad /*
23756a34939Shaad * Helper functions for custom report functions
23856a34939Shaad */
dm_report_field_set_value(struct dm_report_field * field,const void * value,const void * sortvalue)23956a34939Shaad void dm_report_field_set_value(struct dm_report_field *field, const void *value, const void *sortvalue)
24056a34939Shaad {
24156a34939Shaad field->report_string = (const char *) value;
24256a34939Shaad field->sort_value = sortvalue ? : value;
24356a34939Shaad }
24456a34939Shaad
24556a34939Shaad /*
24656a34939Shaad * show help message
24756a34939Shaad */
_display_fields(struct dm_report * rh)24856a34939Shaad static void _display_fields(struct dm_report *rh)
24956a34939Shaad {
25056a34939Shaad uint32_t f;
25156a34939Shaad const struct dm_report_object_type *type;
25256a34939Shaad const char *desc, *last_desc = "";
25356a34939Shaad size_t id_len = 0;
25456a34939Shaad
25556a34939Shaad for (f = 0; rh->fields[f].report_fn; f++)
25656a34939Shaad if (strlen(rh->fields[f].id) > id_len)
25756a34939Shaad id_len = strlen(rh->fields[f].id);
25856a34939Shaad
259bec4d750Shaad
260bec4d750Shaad for (type = rh->types; type->data_fn; type++)
261bec4d750Shaad if (strlen(type->prefix) + 3 > id_len)
262bec4d750Shaad id_len = strlen(type->prefix) + 3;
263bec4d750Shaad
26456a34939Shaad for (f = 0; rh->fields[f].report_fn; f++) {
26556a34939Shaad if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
26656a34939Shaad desc = type->desc;
26756a34939Shaad else
26856a34939Shaad desc = " ";
26956a34939Shaad if (desc != last_desc) {
27056a34939Shaad if (*last_desc)
27156a34939Shaad log_warn(" ");
27256a34939Shaad log_warn("%s Fields", desc);
27356a34939Shaad log_warn("%*.*s", (int) strlen(desc) + 7,
27456a34939Shaad (int) strlen(desc) + 7,
27556a34939Shaad "-------------------------------------------------------------------------------");
276bec4d750Shaad log_warn(" %sall%-*s - %s", type->prefix,
277bec4d750Shaad (int) (id_len - 3 - strlen(type->prefix)), "",
278bec4d750Shaad "All fields in this section.");
27956a34939Shaad }
28056a34939Shaad
28156a34939Shaad /* FIXME Add line-wrapping at terminal width (or 80 cols) */
28256a34939Shaad log_warn(" %-*s - %s", (int) id_len, rh->fields[f].id, rh->fields[f].desc);
28356a34939Shaad last_desc = desc;
28456a34939Shaad }
28556a34939Shaad }
28656a34939Shaad
28756a34939Shaad /*
28856a34939Shaad * Initialise report handle
28956a34939Shaad */
_copy_field(struct dm_report * rh,struct field_properties * dest,uint32_t field_num)29056a34939Shaad static int _copy_field(struct dm_report *rh, struct field_properties *dest,
29156a34939Shaad uint32_t field_num)
29256a34939Shaad {
29356a34939Shaad dest->field_num = field_num;
29456a34939Shaad dest->width = rh->fields[field_num].width;
29556a34939Shaad dest->flags = rh->fields[field_num].flags & DM_REPORT_FIELD_MASK;
29656a34939Shaad
29756a34939Shaad /* set object type method */
29856a34939Shaad dest->type = _find_type(rh, rh->fields[field_num].type);
29956a34939Shaad if (!dest->type) {
30056a34939Shaad log_error("dm_report: field not match: %s",
30156a34939Shaad rh->fields[field_num].id);
30256a34939Shaad return 0;
30356a34939Shaad }
30456a34939Shaad
30556a34939Shaad return 1;
30656a34939Shaad }
30756a34939Shaad
_add_field(struct dm_report * rh,uint32_t field_num,uint32_t flags)30856a34939Shaad static struct field_properties * _add_field(struct dm_report *rh,
30956a34939Shaad uint32_t field_num, uint32_t flags)
31056a34939Shaad {
31156a34939Shaad struct field_properties *fp;
31256a34939Shaad
31356a34939Shaad if (!(fp = dm_pool_zalloc(rh->mem, sizeof(struct field_properties)))) {
31456a34939Shaad log_error("dm_report: struct field_properties allocation "
31556a34939Shaad "failed");
31656a34939Shaad return NULL;
31756a34939Shaad }
31856a34939Shaad
31956a34939Shaad if (!_copy_field(rh, fp, field_num)) {
32056a34939Shaad stack;
32156a34939Shaad dm_pool_free(rh->mem, fp);
32256a34939Shaad return NULL;
32356a34939Shaad }
32456a34939Shaad
32556a34939Shaad fp->flags |= flags;
32656a34939Shaad
32756a34939Shaad /*
32856a34939Shaad * Place hidden fields at the front so dm_list_end() will
32956a34939Shaad * tell us when we've reached the last visible field.
33056a34939Shaad */
33156a34939Shaad if (fp->flags & FLD_HIDDEN)
33256a34939Shaad dm_list_add_h(&rh->field_props, &fp->list);
33356a34939Shaad else
33456a34939Shaad dm_list_add(&rh->field_props, &fp->list);
33556a34939Shaad
33656a34939Shaad return fp;
33756a34939Shaad }
33856a34939Shaad
33956a34939Shaad /*
34056a34939Shaad * Compare name1 against name2 or prefix plus name2
34156a34939Shaad * name2 is not necessarily null-terminated.
34256a34939Shaad * len2 is the length of name2.
34356a34939Shaad */
_is_same_field(const char * name1,const char * name2,size_t len2,const char * prefix)34456a34939Shaad static int _is_same_field(const char *name1, const char *name2,
34556a34939Shaad size_t len2, const char *prefix)
34656a34939Shaad {
34756a34939Shaad size_t prefix_len;
34856a34939Shaad
34956a34939Shaad /* Exact match? */
35056a34939Shaad if (!strncasecmp(name1, name2, len2) && strlen(name1) == len2)
35156a34939Shaad return 1;
35256a34939Shaad
35356a34939Shaad /* Match including prefix? */
35456a34939Shaad prefix_len = strlen(prefix);
35556a34939Shaad if (!strncasecmp(prefix, name1, prefix_len) &&
35656a34939Shaad !strncasecmp(name1 + prefix_len, name2, len2) &&
35756a34939Shaad strlen(name1) == prefix_len + len2)
35856a34939Shaad return 1;
35956a34939Shaad
36056a34939Shaad return 0;
36156a34939Shaad }
36256a34939Shaad
363bec4d750Shaad /*
364bec4d750Shaad * Check for a report type prefix + "all" match.
365bec4d750Shaad */
_all_match(struct dm_report * rh,const char * field,size_t flen)366bec4d750Shaad static uint32_t _all_match(struct dm_report *rh, const char *field, size_t flen)
367bec4d750Shaad {
368bec4d750Shaad size_t prefix_len;
369bec4d750Shaad const struct dm_report_object_type *t;
370*7c604eeaShaad char prefixed_all[32];
371bec4d750Shaad
372*7c604eeaShaad if (!strncasecmp(field, "all", 3) && flen == 3) {
373*7c604eeaShaad if (strlen(rh->field_prefix)) {
374*7c604eeaShaad strcpy(prefixed_all, rh->field_prefix);
375*7c604eeaShaad strcat(prefixed_all, "all");
376*7c604eeaShaad /*
377*7c604eeaShaad * Add also prefix to receive all attributes
378*7c604eeaShaad * (e.g.LABEL/PVS use the same prefix)
379*7c604eeaShaad */
380*7c604eeaShaad return rh->report_types |
381*7c604eeaShaad _all_match(rh, prefixed_all,
382*7c604eeaShaad strlen(prefixed_all));
383*7c604eeaShaad } else
384bec4d750Shaad return rh->report_types;
385*7c604eeaShaad }
386bec4d750Shaad
387bec4d750Shaad for (t = rh->types; t->data_fn; t++) {
388bec4d750Shaad prefix_len = strlen(t->prefix);
389bec4d750Shaad if (!strncasecmp(t->prefix, field, prefix_len) &&
390bec4d750Shaad !strncasecmp(field + prefix_len, "all", 3) &&
391bec4d750Shaad flen == prefix_len + 3)
392bec4d750Shaad return t->id;
393bec4d750Shaad }
394bec4d750Shaad
395bec4d750Shaad return 0;
396bec4d750Shaad }
397bec4d750Shaad
398bec4d750Shaad /*
399bec4d750Shaad * Add all fields with a matching type.
400bec4d750Shaad */
_add_all_fields(struct dm_report * rh,uint32_t type)401bec4d750Shaad static int _add_all_fields(struct dm_report *rh, uint32_t type)
40256a34939Shaad {
40356a34939Shaad uint32_t f;
40456a34939Shaad
405bec4d750Shaad for (f = 0; rh->fields[f].report_fn; f++)
406bec4d750Shaad if ((rh->fields[f].type & type) && !_add_field(rh, f, 0))
407bec4d750Shaad return 0;
408bec4d750Shaad
409bec4d750Shaad return 1;
410bec4d750Shaad }
411bec4d750Shaad
_field_match(struct dm_report * rh,const char * field,size_t flen,unsigned report_type_only)412bec4d750Shaad static int _field_match(struct dm_report *rh, const char *field, size_t flen,
413bec4d750Shaad unsigned report_type_only)
414bec4d750Shaad {
415bec4d750Shaad uint32_t f, type;
416bec4d750Shaad
41756a34939Shaad if (!flen)
41856a34939Shaad return 0;
41956a34939Shaad
42056a34939Shaad for (f = 0; rh->fields[f].report_fn; f++)
42156a34939Shaad if (_is_same_field(rh->fields[f].id, field, flen,
422bec4d750Shaad rh->field_prefix)) {
423bec4d750Shaad if (report_type_only) {
424bec4d750Shaad rh->report_types |= rh->fields[f].type;
425bec4d750Shaad return 1;
426bec4d750Shaad } else
42756a34939Shaad return _add_field(rh, f, 0) ? 1 : 0;
428bec4d750Shaad }
429bec4d750Shaad
430bec4d750Shaad if ((type = _all_match(rh, field, flen))) {
431bec4d750Shaad if (report_type_only) {
432bec4d750Shaad rh->report_types |= type;
433bec4d750Shaad return 1;
434bec4d750Shaad } else
435bec4d750Shaad return _add_all_fields(rh, type);
436bec4d750Shaad }
43756a34939Shaad
43856a34939Shaad return 0;
43956a34939Shaad }
44056a34939Shaad
_add_sort_key(struct dm_report * rh,uint32_t field_num,uint32_t flags,unsigned report_type_only)44156a34939Shaad static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
442bec4d750Shaad uint32_t flags, unsigned report_type_only)
44356a34939Shaad {
44456a34939Shaad struct field_properties *fp, *found = NULL;
44556a34939Shaad
44656a34939Shaad dm_list_iterate_items(fp, &rh->field_props) {
44756a34939Shaad if (fp->field_num == field_num) {
44856a34939Shaad found = fp;
44956a34939Shaad break;
45056a34939Shaad }
45156a34939Shaad }
45256a34939Shaad
453bec4d750Shaad if (!found) {
454bec4d750Shaad if (report_type_only)
455bec4d750Shaad rh->report_types |= rh->fields[field_num].type;
456bec4d750Shaad else if (!(found = _add_field(rh, field_num, FLD_HIDDEN)))
45756a34939Shaad return_0;
458bec4d750Shaad }
459bec4d750Shaad
460bec4d750Shaad if (report_type_only)
461bec4d750Shaad return 1;
46256a34939Shaad
46356a34939Shaad if (found->flags & FLD_SORT_KEY) {
46456a34939Shaad log_error("dm_report: Ignoring duplicate sort field: %s",
46556a34939Shaad rh->fields[field_num].id);
46656a34939Shaad return 1;
46756a34939Shaad }
46856a34939Shaad
46956a34939Shaad found->flags |= FLD_SORT_KEY;
47056a34939Shaad found->sort_posn = rh->keys_count++;
47156a34939Shaad found->flags |= flags;
47256a34939Shaad
47356a34939Shaad return 1;
47456a34939Shaad }
47556a34939Shaad
_key_match(struct dm_report * rh,const char * key,size_t len,unsigned report_type_only)476bec4d750Shaad static int _key_match(struct dm_report *rh, const char *key, size_t len,
477bec4d750Shaad unsigned report_type_only)
47856a34939Shaad {
47956a34939Shaad uint32_t f;
48056a34939Shaad uint32_t flags;
48156a34939Shaad
48256a34939Shaad if (!len)
48356a34939Shaad return 0;
48456a34939Shaad
48556a34939Shaad if (*key == '+') {
48656a34939Shaad key++;
48756a34939Shaad len--;
48856a34939Shaad flags = FLD_ASCENDING;
48956a34939Shaad } else if (*key == '-') {
49056a34939Shaad key++;
49156a34939Shaad len--;
49256a34939Shaad flags = FLD_DESCENDING;
49356a34939Shaad } else
49456a34939Shaad flags = FLD_ASCENDING;
49556a34939Shaad
49656a34939Shaad if (!len) {
49756a34939Shaad log_error("dm_report: Missing sort field name");
49856a34939Shaad return 0;
49956a34939Shaad }
50056a34939Shaad
50156a34939Shaad for (f = 0; rh->fields[f].report_fn; f++)
50256a34939Shaad if (_is_same_field(rh->fields[f].id, key, len,
50356a34939Shaad rh->field_prefix))
504bec4d750Shaad return _add_sort_key(rh, f, flags, report_type_only);
50556a34939Shaad
50656a34939Shaad return 0;
50756a34939Shaad }
50856a34939Shaad
_parse_fields(struct dm_report * rh,const char * format,unsigned report_type_only)509bec4d750Shaad static int _parse_fields(struct dm_report *rh, const char *format,
510bec4d750Shaad unsigned report_type_only)
51156a34939Shaad {
51256a34939Shaad const char *ws; /* Word start */
51356a34939Shaad const char *we = format; /* Word end */
51456a34939Shaad
51556a34939Shaad while (*we) {
51656a34939Shaad /* Allow consecutive commas */
51756a34939Shaad while (*we && *we == ',')
51856a34939Shaad we++;
51956a34939Shaad
52056a34939Shaad /* start of the field name */
52156a34939Shaad ws = we;
52256a34939Shaad while (*we && *we != ',')
52356a34939Shaad we++;
52456a34939Shaad
525bec4d750Shaad if (!_field_match(rh, ws, (size_t) (we - ws), report_type_only)) {
52656a34939Shaad _display_fields(rh);
52756a34939Shaad log_warn(" ");
52856a34939Shaad if (strcasecmp(ws, "help") && strcmp(ws, "?"))
52956a34939Shaad log_error("Unrecognised field: %.*s",
53056a34939Shaad (int) (we - ws), ws);
53156a34939Shaad return 0;
53256a34939Shaad }
53356a34939Shaad }
53456a34939Shaad
53556a34939Shaad return 1;
53656a34939Shaad }
53756a34939Shaad
_parse_keys(struct dm_report * rh,const char * keys,unsigned report_type_only)538bec4d750Shaad static int _parse_keys(struct dm_report *rh, const char *keys,
539bec4d750Shaad unsigned report_type_only)
54056a34939Shaad {
54156a34939Shaad const char *ws; /* Word start */
54256a34939Shaad const char *we = keys; /* Word end */
54356a34939Shaad
54456a34939Shaad while (*we) {
54556a34939Shaad /* Allow consecutive commas */
54656a34939Shaad while (*we && *we == ',')
54756a34939Shaad we++;
54856a34939Shaad ws = we;
54956a34939Shaad while (*we && *we != ',')
55056a34939Shaad we++;
551bec4d750Shaad if (!_key_match(rh, ws, (size_t) (we - ws), report_type_only)) {
55256a34939Shaad log_error("dm_report: Unrecognised field: %.*s",
55356a34939Shaad (int) (we - ws), ws);
55456a34939Shaad return 0;
55556a34939Shaad }
55656a34939Shaad }
55756a34939Shaad
55856a34939Shaad return 1;
55956a34939Shaad }
56056a34939Shaad
dm_report_init(uint32_t * report_types,const struct dm_report_object_type * types,const struct dm_report_field_type * fields,const char * output_fields,const char * output_separator,uint32_t output_flags,const char * sort_keys,void * private)56156a34939Shaad struct dm_report *dm_report_init(uint32_t *report_types,
56256a34939Shaad const struct dm_report_object_type *types,
56356a34939Shaad const struct dm_report_field_type *fields,
56456a34939Shaad const char *output_fields,
56556a34939Shaad const char *output_separator,
56656a34939Shaad uint32_t output_flags,
56756a34939Shaad const char *sort_keys,
56856a34939Shaad void *private)
56956a34939Shaad {
57056a34939Shaad struct dm_report *rh;
57156a34939Shaad const struct dm_report_object_type *type;
57256a34939Shaad
57356a34939Shaad if (!(rh = dm_malloc(sizeof(*rh)))) {
57456a34939Shaad log_error("dm_report_init: dm_malloc failed");
57556a34939Shaad return 0;
57656a34939Shaad }
57756a34939Shaad memset(rh, 0, sizeof(*rh));
57856a34939Shaad
57956a34939Shaad /*
580bec4d750Shaad * rh->report_types is updated in _parse_fields() and _parse_keys()
58156a34939Shaad * to contain all types corresponding to the fields specified by
582bec4d750Shaad * fields or keys.
58356a34939Shaad */
58456a34939Shaad if (report_types)
58556a34939Shaad rh->report_types = *report_types;
58656a34939Shaad
58756a34939Shaad rh->separator = output_separator;
58856a34939Shaad rh->fields = fields;
58956a34939Shaad rh->types = types;
59056a34939Shaad rh->private = private;
59156a34939Shaad
59256a34939Shaad rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK;
59356a34939Shaad
59456a34939Shaad /* With columns_as_rows we must buffer and not align. */
59556a34939Shaad if (output_flags & DM_REPORT_OUTPUT_COLUMNS_AS_ROWS) {
59656a34939Shaad if (!(output_flags & DM_REPORT_OUTPUT_BUFFERED))
59756a34939Shaad rh->flags |= DM_REPORT_OUTPUT_BUFFERED;
59856a34939Shaad if (output_flags & DM_REPORT_OUTPUT_ALIGNED)
59956a34939Shaad rh->flags &= ~DM_REPORT_OUTPUT_ALIGNED;
60056a34939Shaad }
60156a34939Shaad
60256a34939Shaad if (output_flags & DM_REPORT_OUTPUT_BUFFERED)
60356a34939Shaad rh->flags |= RH_SORT_REQUIRED;
60456a34939Shaad
60556a34939Shaad dm_list_init(&rh->field_props);
60656a34939Shaad dm_list_init(&rh->rows);
60756a34939Shaad
60856a34939Shaad if ((type = _find_type(rh, rh->report_types)) && type->prefix)
60956a34939Shaad rh->field_prefix = type->prefix;
61056a34939Shaad else
61156a34939Shaad rh->field_prefix = "";
61256a34939Shaad
61356a34939Shaad if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
61456a34939Shaad log_error("dm_report_init: allocation of memory pool failed");
61556a34939Shaad dm_free(rh);
61656a34939Shaad return NULL;
61756a34939Shaad }
61856a34939Shaad
619bec4d750Shaad /*
620bec4d750Shaad * To keep the code needed to add the "all" field to a minimum, we parse
621bec4d750Shaad * the field lists twice. The first time we only update the report type.
622bec4d750Shaad * FIXME Use one pass instead and expand the "all" field afterwards.
623bec4d750Shaad */
624bec4d750Shaad if (!_parse_fields(rh, output_fields, 1) ||
625bec4d750Shaad !_parse_keys(rh, sort_keys, 1)) {
62656a34939Shaad dm_report_free(rh);
62756a34939Shaad return NULL;
62856a34939Shaad }
62956a34939Shaad
630bec4d750Shaad /* Generate list of fields for output based on format string & flags */
631bec4d750Shaad if (!_parse_fields(rh, output_fields, 0) ||
632bec4d750Shaad !_parse_keys(rh, sort_keys, 0)) {
63356a34939Shaad dm_report_free(rh);
63456a34939Shaad return NULL;
63556a34939Shaad }
63656a34939Shaad
63756a34939Shaad /* Return updated types value for further compatility check by caller */
63856a34939Shaad if (report_types)
63956a34939Shaad *report_types = rh->report_types;
64056a34939Shaad
64156a34939Shaad return rh;
64256a34939Shaad }
64356a34939Shaad
dm_report_free(struct dm_report * rh)64456a34939Shaad void dm_report_free(struct dm_report *rh)
64556a34939Shaad {
64656a34939Shaad dm_pool_destroy(rh->mem);
64756a34939Shaad dm_free(rh);
64856a34939Shaad }
64956a34939Shaad
_toupperstr(char * str)65056a34939Shaad static char *_toupperstr(char *str)
65156a34939Shaad {
65256a34939Shaad char *u = str;
65356a34939Shaad
65456a34939Shaad do
65556a34939Shaad *u = toupper(*u);
65656a34939Shaad while (*u++);
65756a34939Shaad
65856a34939Shaad return str;
65956a34939Shaad }
66056a34939Shaad
dm_report_set_output_field_name_prefix(struct dm_report * rh,const char * output_field_name_prefix)66156a34939Shaad int dm_report_set_output_field_name_prefix(struct dm_report *rh, const char *output_field_name_prefix)
66256a34939Shaad {
66356a34939Shaad char *prefix;
66456a34939Shaad
66556a34939Shaad if (!(prefix = dm_pool_strdup(rh->mem, output_field_name_prefix))) {
66656a34939Shaad log_error("dm_report_set_output_field_name_prefix: dm_pool_strdup failed");
66756a34939Shaad return 0;
66856a34939Shaad }
66956a34939Shaad
67056a34939Shaad rh->output_field_name_prefix = _toupperstr(prefix);
67156a34939Shaad
67256a34939Shaad return 1;
67356a34939Shaad }
67456a34939Shaad
67556a34939Shaad /*
67656a34939Shaad * Create a row of data for an object
67756a34939Shaad */
_report_get_field_data(struct dm_report * rh,struct field_properties * fp,void * object)67856a34939Shaad static void * _report_get_field_data(struct dm_report *rh,
67956a34939Shaad struct field_properties *fp, void *object)
68056a34939Shaad {
68156a34939Shaad void *ret = fp->type->data_fn(object);
68256a34939Shaad
68356a34939Shaad if (!ret)
68456a34939Shaad return NULL;
68556a34939Shaad
68656a34939Shaad return ret + rh->fields[fp->field_num].offset;
68756a34939Shaad }
68856a34939Shaad
dm_report_object(struct dm_report * rh,void * object)68956a34939Shaad int dm_report_object(struct dm_report *rh, void *object)
69056a34939Shaad {
69156a34939Shaad struct field_properties *fp;
69256a34939Shaad struct row *row;
69356a34939Shaad struct dm_report_field *field;
69456a34939Shaad void *data = NULL;
69556a34939Shaad
69656a34939Shaad if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
69756a34939Shaad log_error("dm_report_object: struct row allocation failed");
69856a34939Shaad return 0;
69956a34939Shaad }
70056a34939Shaad
70156a34939Shaad row->rh = rh;
70256a34939Shaad
70356a34939Shaad if ((rh->flags & RH_SORT_REQUIRED) &&
70456a34939Shaad !(row->sort_fields =
70556a34939Shaad dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) *
70656a34939Shaad rh->keys_count))) {
70756a34939Shaad log_error("dm_report_object: "
70856a34939Shaad "row sort value structure allocation failed");
70956a34939Shaad return 0;
71056a34939Shaad }
71156a34939Shaad
71256a34939Shaad dm_list_init(&row->fields);
71356a34939Shaad dm_list_add(&rh->rows, &row->list);
71456a34939Shaad
71556a34939Shaad /* For each field to be displayed, call its report_fn */
71656a34939Shaad dm_list_iterate_items(fp, &rh->field_props) {
71756a34939Shaad if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
71856a34939Shaad log_error("dm_report_object: "
71956a34939Shaad "struct dm_report_field allocation failed");
72056a34939Shaad return 0;
72156a34939Shaad }
72256a34939Shaad field->props = fp;
72356a34939Shaad
72456a34939Shaad data = _report_get_field_data(rh, fp, object);
72556a34939Shaad if (!data)
72656a34939Shaad return 0;
72756a34939Shaad
72856a34939Shaad if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
72956a34939Shaad field, data,
73056a34939Shaad rh->private)) {
73156a34939Shaad log_error("dm_report_object: "
73256a34939Shaad "report function failed for field %s",
73356a34939Shaad rh->fields[fp->field_num].id);
73456a34939Shaad return 0;
73556a34939Shaad }
73656a34939Shaad
73756a34939Shaad if ((strlen(field->report_string) > field->props->width))
73856a34939Shaad field->props->width = strlen(field->report_string);
73956a34939Shaad
74056a34939Shaad if ((rh->flags & RH_SORT_REQUIRED) &&
74156a34939Shaad (field->props->flags & FLD_SORT_KEY)) {
74256a34939Shaad (*row->sort_fields)[field->props->sort_posn] = field;
74356a34939Shaad }
74456a34939Shaad dm_list_add(&row->fields, &field->list);
74556a34939Shaad }
74656a34939Shaad
74756a34939Shaad if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
74856a34939Shaad return dm_report_output(rh);
74956a34939Shaad
75056a34939Shaad return 1;
75156a34939Shaad }
75256a34939Shaad
75356a34939Shaad /*
75456a34939Shaad * Print row of headings
75556a34939Shaad */
_report_headings(struct dm_report * rh)75656a34939Shaad static int _report_headings(struct dm_report *rh)
75756a34939Shaad {
75856a34939Shaad struct field_properties *fp;
75956a34939Shaad const char *heading;
76056a34939Shaad char buf[1024];
76156a34939Shaad
76256a34939Shaad if (rh->flags & RH_HEADINGS_PRINTED)
76356a34939Shaad return 1;
76456a34939Shaad
76556a34939Shaad rh->flags |= RH_HEADINGS_PRINTED;
76656a34939Shaad
76756a34939Shaad if (!(rh->flags & DM_REPORT_OUTPUT_HEADINGS))
76856a34939Shaad return 1;
76956a34939Shaad
77056a34939Shaad if (!dm_pool_begin_object(rh->mem, 128)) {
77156a34939Shaad log_error("dm_report: "
77256a34939Shaad "dm_pool_begin_object failed for headings");
77356a34939Shaad return 0;
77456a34939Shaad }
77556a34939Shaad
77656a34939Shaad /* First heading line */
77756a34939Shaad dm_list_iterate_items(fp, &rh->field_props) {
77856a34939Shaad if (fp->flags & FLD_HIDDEN)
77956a34939Shaad continue;
78056a34939Shaad
78156a34939Shaad heading = rh->fields[fp->field_num].heading;
78256a34939Shaad if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
78356a34939Shaad if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
78456a34939Shaad fp->width, fp->width, heading) < 0) {
78556a34939Shaad log_error("dm_report: snprintf heading failed");
78656a34939Shaad goto bad;
78756a34939Shaad }
78856a34939Shaad if (!dm_pool_grow_object(rh->mem, buf, fp->width)) {
78956a34939Shaad log_error("dm_report: Failed to generate report headings for printing");
79056a34939Shaad goto bad;
79156a34939Shaad }
79256a34939Shaad } else if (!dm_pool_grow_object(rh->mem, heading, 0)) {
79356a34939Shaad log_error("dm_report: Failed to generate report headings for printing");
79456a34939Shaad goto bad;
79556a34939Shaad }
79656a34939Shaad
79756a34939Shaad if (!dm_list_end(&rh->field_props, &fp->list))
79856a34939Shaad if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
79956a34939Shaad log_error("dm_report: Failed to generate report headings for printing");
80056a34939Shaad goto bad;
80156a34939Shaad }
80256a34939Shaad }
80356a34939Shaad if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
80456a34939Shaad log_error("dm_report: Failed to generate report headings for printing");
80556a34939Shaad goto bad;
80656a34939Shaad }
80756a34939Shaad log_print("%s", (char *) dm_pool_end_object(rh->mem));
80856a34939Shaad
80956a34939Shaad return 1;
81056a34939Shaad
81156a34939Shaad bad:
81256a34939Shaad dm_pool_abandon_object(rh->mem);
81356a34939Shaad return 0;
81456a34939Shaad }
81556a34939Shaad
81656a34939Shaad /*
81756a34939Shaad * Sort rows of data
81856a34939Shaad */
_row_compare(const void * a,const void * b)81956a34939Shaad static int _row_compare(const void *a, const void *b)
82056a34939Shaad {
82156a34939Shaad const struct row *rowa = *(const struct row **) a;
82256a34939Shaad const struct row *rowb = *(const struct row **) b;
82356a34939Shaad const struct dm_report_field *sfa, *sfb;
82456a34939Shaad uint32_t cnt;
82556a34939Shaad
82656a34939Shaad for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
82756a34939Shaad sfa = (*rowa->sort_fields)[cnt];
82856a34939Shaad sfb = (*rowb->sort_fields)[cnt];
82956a34939Shaad if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) {
83056a34939Shaad const uint64_t numa =
83156a34939Shaad *(const uint64_t *) sfa->sort_value;
83256a34939Shaad const uint64_t numb =
83356a34939Shaad *(const uint64_t *) sfb->sort_value;
83456a34939Shaad
83556a34939Shaad if (numa == numb)
83656a34939Shaad continue;
83756a34939Shaad
83856a34939Shaad if (sfa->props->flags & FLD_ASCENDING) {
83956a34939Shaad return (numa > numb) ? 1 : -1;
84056a34939Shaad } else { /* FLD_DESCENDING */
84156a34939Shaad return (numa < numb) ? 1 : -1;
84256a34939Shaad }
84356a34939Shaad } else { /* DM_REPORT_FIELD_TYPE_STRING */
84456a34939Shaad const char *stra = (const char *) sfa->sort_value;
84556a34939Shaad const char *strb = (const char *) sfb->sort_value;
84656a34939Shaad int cmp = strcmp(stra, strb);
84756a34939Shaad
84856a34939Shaad if (!cmp)
84956a34939Shaad continue;
85056a34939Shaad
85156a34939Shaad if (sfa->props->flags & FLD_ASCENDING) {
85256a34939Shaad return (cmp > 0) ? 1 : -1;
85356a34939Shaad } else { /* FLD_DESCENDING */
85456a34939Shaad return (cmp < 0) ? 1 : -1;
85556a34939Shaad }
85656a34939Shaad }
85756a34939Shaad }
85856a34939Shaad
85956a34939Shaad return 0; /* Identical */
86056a34939Shaad }
86156a34939Shaad
_sort_rows(struct dm_report * rh)86256a34939Shaad static int _sort_rows(struct dm_report *rh)
86356a34939Shaad {
86456a34939Shaad struct row *(*rows)[];
86556a34939Shaad uint32_t count = 0;
86656a34939Shaad struct row *row;
86756a34939Shaad
86856a34939Shaad if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
86956a34939Shaad dm_list_size(&rh->rows)))) {
87056a34939Shaad log_error("dm_report: sort array allocation failed");
87156a34939Shaad return 0;
87256a34939Shaad }
87356a34939Shaad
87456a34939Shaad dm_list_iterate_items(row, &rh->rows)
87556a34939Shaad (*rows)[count++] = row;
87656a34939Shaad
87756a34939Shaad qsort(rows, count, sizeof(**rows), _row_compare);
87856a34939Shaad
87956a34939Shaad dm_list_init(&rh->rows);
88056a34939Shaad while (count--)
88156a34939Shaad dm_list_add_h(&rh->rows, &(*rows)[count]->list);
88256a34939Shaad
88356a34939Shaad return 1;
88456a34939Shaad }
88556a34939Shaad
88656a34939Shaad /*
88756a34939Shaad * Produce report output
88856a34939Shaad */
_output_field(struct dm_report * rh,struct dm_report_field * field)88956a34939Shaad static int _output_field(struct dm_report *rh, struct dm_report_field *field)
89056a34939Shaad {
89156a34939Shaad char *field_id;
89256a34939Shaad int32_t width;
89356a34939Shaad uint32_t align;
89456a34939Shaad const char *repstr;
89556a34939Shaad char buf[4096];
89656a34939Shaad
89756a34939Shaad if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
89856a34939Shaad if (!(field_id = strdup(rh->fields[field->props->field_num].id))) {
89956a34939Shaad log_error("dm_report: Failed to copy field name");
90056a34939Shaad return 0;
90156a34939Shaad }
90256a34939Shaad
90356a34939Shaad if (!dm_pool_grow_object(rh->mem, rh->output_field_name_prefix, 0)) {
90456a34939Shaad log_error("dm_report: Unable to extend output line");
90556a34939Shaad return 0;
90656a34939Shaad }
90756a34939Shaad
90856a34939Shaad if (!dm_pool_grow_object(rh->mem, _toupperstr(field_id), 0)) {
90956a34939Shaad log_error("dm_report: Unable to extend output line");
91056a34939Shaad return 0;
91156a34939Shaad }
91256a34939Shaad
91356a34939Shaad free(field_id);
91456a34939Shaad
91556a34939Shaad if (!dm_pool_grow_object(rh->mem, "=", 1)) {
91656a34939Shaad log_error("dm_report: Unable to extend output line");
91756a34939Shaad return 0;
91856a34939Shaad }
91956a34939Shaad
92056a34939Shaad if (!(rh->flags & DM_REPORT_OUTPUT_FIELD_UNQUOTED) &&
92156a34939Shaad !dm_pool_grow_object(rh->mem, "\'", 1)) {
92256a34939Shaad log_error("dm_report: Unable to extend output line");
92356a34939Shaad return 0;
92456a34939Shaad }
92556a34939Shaad }
92656a34939Shaad
92756a34939Shaad repstr = field->report_string;
92856a34939Shaad width = field->props->width;
92956a34939Shaad if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
93056a34939Shaad if (!dm_pool_grow_object(rh->mem, repstr, 0)) {
93156a34939Shaad log_error("dm_report: Unable to extend output line");
93256a34939Shaad return 0;
93356a34939Shaad }
93456a34939Shaad } else {
93556a34939Shaad if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
93656a34939Shaad align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ?
93756a34939Shaad DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
93856a34939Shaad if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
93956a34939Shaad if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
94056a34939Shaad width, width, repstr) < 0) {
94156a34939Shaad log_error("dm_report: left-aligned snprintf() failed");
94256a34939Shaad return 0;
94356a34939Shaad }
94456a34939Shaad if (!dm_pool_grow_object(rh->mem, buf, width)) {
94556a34939Shaad log_error("dm_report: Unable to extend output line");
94656a34939Shaad return 0;
94756a34939Shaad }
94856a34939Shaad } else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
94956a34939Shaad if (dm_snprintf(buf, sizeof(buf), "%*.*s",
95056a34939Shaad width, width, repstr) < 0) {
95156a34939Shaad log_error("dm_report: right-aligned snprintf() failed");
95256a34939Shaad return 0;
95356a34939Shaad }
95456a34939Shaad if (!dm_pool_grow_object(rh->mem, buf, width)) {
95556a34939Shaad log_error("dm_report: Unable to extend output line");
95656a34939Shaad return 0;
95756a34939Shaad }
95856a34939Shaad }
95956a34939Shaad }
96056a34939Shaad
96156a34939Shaad if ((rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) &&
96256a34939Shaad !(rh->flags & DM_REPORT_OUTPUT_FIELD_UNQUOTED))
96356a34939Shaad if (!dm_pool_grow_object(rh->mem, "\'", 1)) {
96456a34939Shaad log_error("dm_report: Unable to extend output line");
96556a34939Shaad return 0;
96656a34939Shaad }
96756a34939Shaad
96856a34939Shaad return 1;
96956a34939Shaad }
97056a34939Shaad
_output_as_rows(struct dm_report * rh)97156a34939Shaad static int _output_as_rows(struct dm_report *rh)
97256a34939Shaad {
97356a34939Shaad struct field_properties *fp;
97456a34939Shaad struct dm_report_field *field;
97556a34939Shaad struct row *row;
97656a34939Shaad
97756a34939Shaad if (!dm_pool_begin_object(rh->mem, 512)) {
97856a34939Shaad log_error("dm_report: Unable to allocate output line");
97956a34939Shaad return 0;
98056a34939Shaad }
98156a34939Shaad
98256a34939Shaad dm_list_iterate_items(fp, &rh->field_props) {
98356a34939Shaad if (fp->flags & FLD_HIDDEN) {
98456a34939Shaad dm_list_iterate_items(row, &rh->rows) {
98556a34939Shaad field = dm_list_item(dm_list_first(&row->fields), struct dm_report_field);
98656a34939Shaad dm_list_del(&field->list);
98756a34939Shaad }
98856a34939Shaad continue;
98956a34939Shaad }
99056a34939Shaad
99156a34939Shaad if ((rh->flags & DM_REPORT_OUTPUT_HEADINGS)) {
99256a34939Shaad if (!dm_pool_grow_object(rh->mem, rh->fields[fp->field_num].heading, 0)) {
99356a34939Shaad log_error("dm_report: Failed to extend row for field name");
99456a34939Shaad goto bad;
99556a34939Shaad }
99656a34939Shaad if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
99756a34939Shaad log_error("dm_report: Failed to extend row with separator");
99856a34939Shaad goto bad;
99956a34939Shaad }
100056a34939Shaad }
100156a34939Shaad
100256a34939Shaad dm_list_iterate_items(row, &rh->rows) {
100356a34939Shaad if ((field = dm_list_item(dm_list_first(&row->fields), struct dm_report_field))) {
100456a34939Shaad if (!_output_field(rh, field))
100556a34939Shaad goto bad;
100656a34939Shaad dm_list_del(&field->list);
100756a34939Shaad }
100856a34939Shaad
100956a34939Shaad if (!dm_list_end(&rh->rows, &row->list))
101056a34939Shaad if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
101156a34939Shaad log_error("dm_report: Unable to extend output line");
101256a34939Shaad goto bad;
101356a34939Shaad }
101456a34939Shaad }
101556a34939Shaad
101656a34939Shaad if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
101756a34939Shaad log_error("dm_report: Failed to terminate row");
101856a34939Shaad goto bad;
101956a34939Shaad }
102056a34939Shaad log_print("%s", (char *) dm_pool_end_object(rh->mem));
102156a34939Shaad }
102256a34939Shaad
102356a34939Shaad return 1;
102456a34939Shaad
102556a34939Shaad bad:
102656a34939Shaad dm_pool_abandon_object(rh->mem);
102756a34939Shaad return 0;
102856a34939Shaad }
102956a34939Shaad
_output_as_columns(struct dm_report * rh)103056a34939Shaad static int _output_as_columns(struct dm_report *rh)
103156a34939Shaad {
103256a34939Shaad struct dm_list *fh, *rowh, *ftmp, *rtmp;
103356a34939Shaad struct row *row = NULL;
103456a34939Shaad struct dm_report_field *field;
103556a34939Shaad
103656a34939Shaad /* If headings not printed yet, calculate field widths and print them */
103756a34939Shaad if (!(rh->flags & RH_HEADINGS_PRINTED))
103856a34939Shaad _report_headings(rh);
103956a34939Shaad
104056a34939Shaad /* Print and clear buffer */
104156a34939Shaad dm_list_iterate_safe(rowh, rtmp, &rh->rows) {
104256a34939Shaad if (!dm_pool_begin_object(rh->mem, 512)) {
104356a34939Shaad log_error("dm_report: Unable to allocate output line");
104456a34939Shaad return 0;
104556a34939Shaad }
104656a34939Shaad row = dm_list_item(rowh, struct row);
104756a34939Shaad dm_list_iterate_safe(fh, ftmp, &row->fields) {
104856a34939Shaad field = dm_list_item(fh, struct dm_report_field);
104956a34939Shaad if (field->props->flags & FLD_HIDDEN)
105056a34939Shaad continue;
105156a34939Shaad
105256a34939Shaad if (!_output_field(rh, field))
105356a34939Shaad goto bad;
105456a34939Shaad
105556a34939Shaad if (!dm_list_end(&row->fields, fh))
105656a34939Shaad if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
105756a34939Shaad log_error("dm_report: Unable to extend output line");
105856a34939Shaad goto bad;
105956a34939Shaad }
106056a34939Shaad
106156a34939Shaad dm_list_del(&field->list);
106256a34939Shaad }
106356a34939Shaad if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
106456a34939Shaad log_error("dm_report: Unable to terminate output line");
106556a34939Shaad goto bad;
106656a34939Shaad }
106756a34939Shaad log_print("%s", (char *) dm_pool_end_object(rh->mem));
106856a34939Shaad dm_list_del(&row->list);
106956a34939Shaad }
107056a34939Shaad
107156a34939Shaad if (row)
107256a34939Shaad dm_pool_free(rh->mem, row);
107356a34939Shaad
107456a34939Shaad return 1;
107556a34939Shaad
107656a34939Shaad bad:
107756a34939Shaad dm_pool_abandon_object(rh->mem);
107856a34939Shaad return 0;
107956a34939Shaad }
108056a34939Shaad
dm_report_output(struct dm_report * rh)108156a34939Shaad int dm_report_output(struct dm_report *rh)
108256a34939Shaad {
108356a34939Shaad if (dm_list_empty(&rh->rows))
108456a34939Shaad return 1;
108556a34939Shaad
108656a34939Shaad if ((rh->flags & RH_SORT_REQUIRED))
108756a34939Shaad _sort_rows(rh);
108856a34939Shaad
108956a34939Shaad if ((rh->flags & DM_REPORT_OUTPUT_COLUMNS_AS_ROWS))
109056a34939Shaad return _output_as_rows(rh);
109156a34939Shaad else
109256a34939Shaad return _output_as_columns(rh);
109356a34939Shaad }
1094