LCOV - code coverage report
Current view: top level - misc/kabi/lvm2.git/libdm - libdm-report.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 113 509 22.2 %
Date: 2010-04-13 Functions: 12 31 38.7 %
Branches: 66 480 13.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
       3                 :            :  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
       4                 :            :  *
       5                 :            :  * This file is part of the device-mapper userspace tools.
       6                 :            :  *
       7                 :            :  * This copyrighted material is made available to anyone wishing to use,
       8                 :            :  * modify, copy, or redistribute it subject to the terms and conditions
       9                 :            :  * of the GNU Lesser General Public License v.2.1.
      10                 :            :  *
      11                 :            :  * You should have received a copy of the GNU Lesser General Public License
      12                 :            :  * along with this program; if not, write to the Free Software Foundation,
      13                 :            :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "dmlib.h"
      17                 :            : 
      18                 :            : #include <ctype.h>
      19                 :            : 
      20                 :            : /*
      21                 :            :  * Internal flags
      22                 :            :  */
      23                 :            : #define RH_SORT_REQUIRED        0x00000100
      24                 :            : #define RH_HEADINGS_PRINTED     0x00000200
      25                 :            : 
      26                 :            : struct dm_report {
      27                 :            :         struct dm_pool *mem;
      28                 :            : 
      29                 :            :         /* To report all available types */
      30                 :            : #define REPORT_TYPES_ALL        UINT32_MAX
      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;
      36                 :            : 
      37                 :            :         uint32_t keys_count;
      38                 :            : 
      39                 :            :         /* Ordered list of fields needed for this report */
      40                 :            :         struct dm_list field_props;
      41                 :            : 
      42                 :            :         /* Rows of report data */
      43                 :            :         struct dm_list rows;
      44                 :            : 
      45                 :            :         /* Array of field definitions */
      46                 :            :         const struct dm_report_field_type *fields;
      47                 :            :         const struct dm_report_object_type *types;
      48                 :            : 
      49                 :            :         /* To store caller private data */
      50                 :            :         void *private;
      51                 :            : };
      52                 :            : 
      53                 :            : /*
      54                 :            :  * Internal per-field flags
      55                 :            :  */
      56                 :            : #define FLD_HIDDEN      0x00000100
      57                 :            : #define FLD_SORT_KEY    0x00000200
      58                 :            : #define FLD_ASCENDING   0x00000400
      59                 :            : #define FLD_DESCENDING  0x00000800
      60                 :            : 
      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;
      68                 :            : };
      69                 :            : 
      70                 :            : /*
      71                 :            :  * Report data field
      72                 :            :  */
      73                 :            : struct dm_report_field {
      74                 :            :         struct dm_list list;
      75                 :            :         struct field_properties *props;
      76                 :            : 
      77                 :            :         const char *report_string;      /* Formatted ready for display */
      78                 :            :         const void *sort_value;         /* Raw value for sorting */
      79                 :            : };
      80                 :            : 
      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 */
      86                 :            : };
      87                 :            : 
      88                 :          7 : static const struct dm_report_object_type *_find_type(struct dm_report *rh,
      89                 :            :                                                       uint32_t report_type)
      90                 :            : {
      91                 :            :         const struct dm_report_object_type *t;
      92                 :            : 
      93         [ +  - ]:         22 :         for (t = rh->types; t->data_fn; t++)
      94         [ +  + ]:         22 :                 if (t->id == report_type)
      95                 :          7 :                         return t;
      96                 :            : 
      97                 :          7 :         return NULL;
      98                 :            : }
      99                 :            : 
     100                 :            : /*
     101                 :            :  * Data-munging functions to prepare each data type for display and sorting
     102                 :            :  */
     103                 :            : 
     104                 :          0 : int dm_report_field_string(struct dm_report *rh,
     105                 :            :                            struct dm_report_field *field, const char **data)
     106                 :            : {
     107                 :            :         char *repstr;
     108                 :            : 
     109         [ #  # ]:          0 :         if (!(repstr = dm_pool_strdup(rh->mem, *data))) {
     110         [ #  # ]:          0 :                 log_error("dm_report_field_string: dm_pool_strdup failed");
     111                 :          0 :                 return 0;
     112                 :            :         }
     113                 :            : 
     114                 :          0 :         field->report_string = repstr;
     115                 :          0 :         field->sort_value = (const void *) field->report_string;
     116                 :            : 
     117                 :          0 :         return 1;
     118                 :            : }
     119                 :            : 
     120                 :          0 : int dm_report_field_int(struct dm_report *rh,
     121                 :            :                         struct dm_report_field *field, const int *data)
     122                 :            : {
     123                 :          0 :         const int value = *data;
     124                 :            :         uint64_t *sortval;
     125                 :            :         char *repstr;
     126                 :            : 
     127         [ #  # ]:          0 :         if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
     128         [ #  # ]:          0 :                 log_error("dm_report_field_int: dm_pool_alloc failed");
     129                 :          0 :                 return 0;
     130                 :            :         }
     131                 :            : 
     132         [ #  # ]:          0 :         if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
     133         [ #  # ]:          0 :                 log_error("dm_report_field_int: dm_pool_alloc failed");
     134                 :          0 :                 return 0;
     135                 :            :         }
     136                 :            : 
     137         [ #  # ]:          0 :         if (dm_snprintf(repstr, 12, "%d", value) < 0) {
     138         [ #  # ]:          0 :                 log_error("dm_report_field_int: int too big: %d", value);
     139                 :          0 :                 return 0;
     140                 :            :         }
     141                 :            : 
     142                 :          0 :         *sortval = (const uint64_t) value;
     143                 :          0 :         field->sort_value = sortval;
     144                 :          0 :         field->report_string = repstr;
     145                 :            : 
     146                 :          0 :         return 1;
     147                 :            : }
     148                 :            : 
     149                 :          0 : int dm_report_field_uint32(struct dm_report *rh,
     150                 :            :                            struct dm_report_field *field, const uint32_t *data)
     151                 :            : {
     152                 :          0 :         const uint32_t value = *data;
     153                 :            :         uint64_t *sortval;
     154                 :            :         char *repstr;
     155                 :            : 
     156         [ #  # ]:          0 :         if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
     157         [ #  # ]:          0 :                 log_error("dm_report_field_uint32: dm_pool_alloc failed");
     158                 :          0 :                 return 0;
     159                 :            :         }
     160                 :            : 
     161         [ #  # ]:          0 :         if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
     162         [ #  # ]:          0 :                 log_error("dm_report_field_uint32: dm_pool_alloc failed");
     163                 :          0 :                 return 0;
     164                 :            :         }
     165                 :            : 
     166         [ #  # ]:          0 :         if (dm_snprintf(repstr, 11, "%u", value) < 0) {
     167         [ #  # ]:          0 :                 log_error("dm_report_field_uint32: uint32 too big: %u", value);
     168                 :          0 :                 return 0;
     169                 :            :         }
     170                 :            : 
     171                 :          0 :         *sortval = (const uint64_t) value;
     172                 :          0 :         field->sort_value = sortval;
     173                 :          0 :         field->report_string = repstr;
     174                 :            : 
     175                 :          0 :         return 1;
     176                 :            : }
     177                 :            : 
     178                 :          0 : int dm_report_field_int32(struct dm_report *rh,
     179                 :            :                           struct dm_report_field *field, const int32_t *data)
     180                 :            : {
     181                 :          0 :         const int32_t value = *data;
     182                 :            :         uint64_t *sortval;
     183                 :            :         char *repstr;
     184                 :            : 
     185         [ #  # ]:          0 :         if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
     186         [ #  # ]:          0 :                 log_error("dm_report_field_int32: dm_pool_alloc failed");
     187                 :          0 :                 return 0;
     188                 :            :         }
     189                 :            : 
     190         [ #  # ]:          0 :         if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
     191         [ #  # ]:          0 :                 log_error("dm_report_field_int32: dm_pool_alloc failed");
     192                 :          0 :                 return 0;
     193                 :            :         }
     194                 :            : 
     195         [ #  # ]:          0 :         if (dm_snprintf(repstr, 12, "%d", value) < 0) {
     196         [ #  # ]:          0 :                 log_error("dm_report_field_int32: int32 too big: %d", value);
     197                 :          0 :                 return 0;
     198                 :            :         }
     199                 :            : 
     200                 :          0 :         *sortval = (const uint64_t) value;
     201                 :          0 :         field->sort_value = sortval;
     202                 :          0 :         field->report_string = repstr;
     203                 :            : 
     204                 :          0 :         return 1;
     205                 :            : }
     206                 :            : 
     207                 :          0 : int dm_report_field_uint64(struct dm_report *rh,
     208                 :            :                            struct dm_report_field *field, const uint64_t *data)
     209                 :            : {
     210                 :          0 :         const uint64_t value = *data;
     211                 :            :         uint64_t *sortval;
     212                 :            :         char *repstr;
     213                 :            : 
     214         [ #  # ]:          0 :         if (!(repstr = dm_pool_zalloc(rh->mem, 22))) {
     215         [ #  # ]:          0 :                 log_error("dm_report_field_uint64: dm_pool_alloc failed");
     216                 :          0 :                 return 0;
     217                 :            :         }
     218                 :            : 
     219         [ #  # ]:          0 :         if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
     220         [ #  # ]:          0 :                 log_error("dm_report_field_uint64: dm_pool_alloc failed");
     221                 :          0 :                 return 0;
     222                 :            :         }
     223                 :            : 
     224         [ #  # ]:          0 :         if (dm_snprintf(repstr, 21, "%" PRIu64 , value) < 0) {
     225         [ #  # ]:          0 :                 log_error("dm_report_field_uint64: uint64 too big: %" PRIu64, value);
     226                 :          0 :                 return 0;
     227                 :            :         }
     228                 :            : 
     229                 :          0 :         *sortval = value;
     230                 :          0 :         field->sort_value = sortval;
     231                 :          0 :         field->report_string = repstr;
     232                 :            : 
     233                 :          0 :         return 1;
     234                 :            : }
     235                 :            : 
     236                 :            : /*
     237                 :            :  * Helper functions for custom report functions
     238                 :            :  */
     239                 :          0 : void dm_report_field_set_value(struct dm_report_field *field, const void *value, const void *sortvalue)
     240                 :            : {
     241                 :          0 :         field->report_string = (const char *) value;
     242         [ #  # ]:          0 :         field->sort_value = sortvalue ? : value;
     243                 :          0 : }
     244                 :            : 
     245                 :            : /*
     246                 :            :  * show help message
     247                 :            :  */
     248                 :          0 : static void _display_fields(struct dm_report *rh)
     249                 :            : {
     250                 :            :         uint32_t f;
     251                 :            :         const struct dm_report_object_type *type;
     252                 :          0 :         const char *desc, *last_desc = "";
     253                 :          0 :         size_t id_len = 0;
     254                 :            : 
     255         [ #  # ]:          0 :         for (f = 0; rh->fields[f].report_fn; f++)
     256         [ #  # ]:          0 :                 if (strlen(rh->fields[f].id) > id_len)
     257                 :          0 :                         id_len = strlen(rh->fields[f].id);
     258                 :            : 
     259                 :            : 
     260         [ #  # ]:          0 :         for (type = rh->types; type->data_fn; type++)
     261         [ #  # ]:          0 :                 if (strlen(type->prefix) + 3 > id_len)
     262                 :          0 :                         id_len = strlen(type->prefix) + 3;
     263                 :            : 
     264         [ #  # ]:          0 :         for (f = 0; rh->fields[f].report_fn; f++) {
     265 [ #  # ][ #  # ]:          0 :                 if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
     266                 :          0 :                         desc = type->desc;
     267                 :            :                 else
     268                 :          0 :                         desc = " ";
     269         [ #  # ]:          0 :                 if (desc != last_desc) {
     270         [ #  # ]:          0 :                         if (*last_desc)
     271         [ #  # ]:          0 :                                 log_warn(" ");
     272         [ #  # ]:          0 :                         log_warn("%s Fields", desc);
     273         [ #  # ]:          0 :                         log_warn("%*.*s", (int) strlen(desc) + 7,
     274                 :            :                                  (int) strlen(desc) + 7,
     275                 :            :                                  "-------------------------------------------------------------------------------");
     276         [ #  # ]:          0 :                         log_warn("  %sall%-*s - %s", type->prefix,
     277                 :            :                                  (int) (id_len - 3 - strlen(type->prefix)), "",
     278                 :            :                                  "All fields in this section.");
     279                 :            :                 }
     280                 :            : 
     281                 :            :                 /* FIXME Add line-wrapping at terminal width (or 80 cols) */
     282         [ #  # ]:          0 :                 log_warn("  %-*s - %s", (int) id_len, rh->fields[f].id, rh->fields[f].desc);
     283                 :          0 :                 last_desc = desc;
     284                 :            :         }
     285                 :          0 : }
     286                 :            : 
     287                 :            : /*
     288                 :            :  * Initialise report handle
     289                 :            :  */
     290                 :          6 : static int _copy_field(struct dm_report *rh, struct field_properties *dest,
     291                 :            :                        uint32_t field_num)
     292                 :            : {
     293                 :          6 :         dest->field_num = field_num;
     294                 :          6 :         dest->width = rh->fields[field_num].width;
     295                 :          6 :         dest->flags = rh->fields[field_num].flags & DM_REPORT_FIELD_MASK;
     296                 :            : 
     297                 :            :         /* set object type method */
     298                 :          6 :         dest->type = _find_type(rh, rh->fields[field_num].type);
     299         [ -  + ]:          6 :         if (!dest->type) {
     300         [ #  # ]:          0 :                 log_error("dm_report: field not match: %s",
     301                 :            :                           rh->fields[field_num].id);
     302                 :          0 :                 return 0;
     303                 :            :         }
     304                 :            : 
     305                 :          6 :         return 1;
     306                 :            : }
     307                 :            : 
     308                 :          6 : static struct field_properties * _add_field(struct dm_report *rh,
     309                 :            :                                             uint32_t field_num, uint32_t flags)
     310                 :            : {
     311                 :            :         struct field_properties *fp;
     312                 :            : 
     313         [ -  + ]:          6 :         if (!(fp = dm_pool_zalloc(rh->mem, sizeof(struct field_properties)))) {
     314         [ #  # ]:          0 :                 log_error("dm_report: struct field_properties allocation "
     315                 :            :                           "failed");
     316                 :          0 :                 return NULL;
     317                 :            :         }
     318                 :            : 
     319         [ -  + ]:          6 :         if (!_copy_field(rh, fp, field_num)) {
     320         [ #  # ]:          0 :                 stack;
     321                 :          0 :                 dm_pool_free(rh->mem, fp);
     322                 :          0 :                 return NULL;
     323                 :            :         }
     324                 :            : 
     325                 :          6 :         fp->flags |= flags;
     326                 :            : 
     327                 :            :         /*
     328                 :            :          * Place hidden fields at the front so dm_list_end() will
     329                 :            :          * tell us when we've reached the last visible field.
     330                 :            :          */
     331         [ -  + ]:          6 :         if (fp->flags & FLD_HIDDEN)
     332                 :          0 :                 dm_list_add_h(&rh->field_props, &fp->list);
     333                 :            :         else
     334                 :          6 :                 dm_list_add(&rh->field_props, &fp->list);
     335                 :            : 
     336                 :          6 :         return fp;
     337                 :            : }
     338                 :            : 
     339                 :            : /*
     340                 :            :  * Compare name1 against name2 or prefix plus name2
     341                 :            :  * name2 is not necessarily null-terminated.
     342                 :            :  * len2 is the length of name2.
     343                 :            :  */
     344                 :        390 : static int _is_same_field(const char *name1, const char *name2,
     345                 :            :                           size_t len2, const char *prefix)
     346                 :            : {
     347                 :            :         size_t prefix_len;
     348                 :            : 
     349                 :            :         /* Exact match? */
     350 [ +  + ][ +  - ]:        390 :         if (!strncasecmp(name1, name2, len2) && strlen(name1) == len2)
     351                 :         14 :                 return 1;
     352                 :            : 
     353                 :            :         /* Match including prefix? */
     354                 :        376 :         prefix_len = strlen(prefix);
     355 [ +  + ][ -  + ]:        376 :         if (!strncasecmp(prefix, name1, prefix_len) &&
                 [ #  # ]
     356                 :         72 :             !strncasecmp(name1 + prefix_len, name2, len2) &&
     357                 :          0 :             strlen(name1) == prefix_len + len2)
     358                 :          0 :                 return 1;
     359                 :            : 
     360                 :        390 :         return 0;
     361                 :            : }
     362                 :            : 
     363                 :            : /*
     364                 :            :  * Check for a report type prefix + "all" match.
     365                 :            :  */
     366                 :          0 : static uint32_t _all_match(struct dm_report *rh, const char *field, size_t flen)
     367                 :            : {
     368                 :            :         size_t prefix_len;
     369                 :            :         const struct dm_report_object_type *t;
     370                 :            :         char prefixed_all[32];
     371                 :            : 
     372 [ #  # ][ #  # ]:          0 :         if (!strncasecmp(field, "all", 3) && flen == 3) {
     373         [ #  # ]:          0 :                 if (strlen(rh->field_prefix)) {
     374                 :          0 :                         strcpy(prefixed_all, rh->field_prefix);
     375                 :          0 :                         strcat(prefixed_all, "all");
     376                 :            :                         /*
     377                 :            :                          * Add also prefix to receive all attributes
     378                 :            :                          * (e.g.LABEL/PVS use the same prefix)
     379                 :            :                          */
     380                 :          0 :                         return rh->report_types |
     381                 :            :                                _all_match(rh, prefixed_all,
     382                 :            :                                           strlen(prefixed_all));
     383                 :            :                 } else
     384         [ #  # ]:          0 :                         return (rh->report_types)
     385                 :            :                                 ? rh->report_types : REPORT_TYPES_ALL;
     386                 :            :         }
     387                 :            : 
     388         [ #  # ]:          0 :         for (t = rh->types; t->data_fn; t++) {
     389                 :          0 :                 prefix_len = strlen(t->prefix);
     390 [ #  # ][ #  # ]:          0 :                 if (!strncasecmp(t->prefix, field, prefix_len) &&
                 [ #  # ]
     391                 :          0 :                     !strncasecmp(field + prefix_len, "all", 3) &&
     392                 :          0 :                     flen == prefix_len + 3)
     393                 :          0 :                         return t->id;
     394                 :            :         }
     395                 :            : 
     396                 :          0 :         return 0;
     397                 :            : }
     398                 :            : 
     399                 :            : /*
     400                 :            :  * Add all fields with a matching type.
     401                 :            :  */
     402                 :          0 : static int _add_all_fields(struct dm_report *rh, uint32_t type)
     403                 :            : {
     404                 :            :         uint32_t f;
     405                 :            : 
     406         [ #  # ]:          0 :         for (f = 0; rh->fields[f].report_fn; f++)
     407 [ #  # ][ #  # ]:          0 :                 if ((rh->fields[f].type & type) && !_add_field(rh, f, 0))
     408                 :          0 :                         return 0;
     409                 :            : 
     410                 :          0 :         return 1;
     411                 :            : }
     412                 :            : 
     413                 :         12 : static int _field_match(struct dm_report *rh, const char *field, size_t flen,
     414                 :            :                         unsigned report_type_only)
     415                 :            : {
     416                 :            :         uint32_t f, type;
     417                 :            : 
     418         [ -  + ]:         12 :         if (!flen)
     419                 :          0 :                 return 0;
     420                 :            : 
     421         [ +  - ]:        342 :         for (f = 0; rh->fields[f].report_fn; f++)
     422         [ +  + ]:        342 :                 if (_is_same_field(rh->fields[f].id, field, flen,
     423                 :            :                                    rh->field_prefix)) {
     424         [ +  + ]:         12 :                         if (report_type_only) {
     425                 :          6 :                                 rh->report_types |= rh->fields[f].type;
     426                 :          6 :                                 return 1;
     427                 :            :                         } else
     428                 :          6 :                                 return _add_field(rh, f, 0) ? 1 : 0;
     429                 :            :                 }
     430                 :            : 
     431         [ #  # ]:          0 :         if ((type = _all_match(rh, field, flen))) {
     432         [ #  # ]:          0 :                 if (report_type_only) {
     433                 :          0 :                         rh->report_types |= type;
     434                 :          0 :                         return 1;
     435                 :            :                 } else
     436                 :          0 :                         return  _add_all_fields(rh, type);
     437                 :            :         }
     438                 :            : 
     439                 :         12 :         return 0;
     440                 :            : }
     441                 :            : 
     442                 :          2 : static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
     443                 :            :                          uint32_t flags, unsigned report_type_only)
     444                 :            : {
     445                 :          2 :         struct field_properties *fp, *found = NULL;
     446                 :            : 
     447         [ +  + ]:          2 :         dm_list_iterate_items(fp, &rh->field_props) {
     448         [ +  - ]:          1 :                 if (fp->field_num == field_num) {
     449                 :          1 :                         found = fp;
     450                 :          1 :                         break;
     451                 :            :                 }
     452                 :            :         }
     453                 :            : 
     454         [ +  + ]:          2 :         if (!found) {
     455         [ +  - ]:          1 :                 if (report_type_only)
     456                 :          1 :                         rh->report_types |= rh->fields[field_num].type;
     457         [ #  # ]:          0 :                 else if (!(found = _add_field(rh, field_num, FLD_HIDDEN)))
     458         [ #  # ]:          0 :                         return_0;
     459                 :            :         }
     460                 :            : 
     461         [ +  + ]:          2 :         if (report_type_only)
     462                 :          1 :                 return 1;
     463                 :            : 
     464         [ -  + ]:          1 :         if (found->flags & FLD_SORT_KEY) {
     465         [ #  # ]:          0 :                 log_error("dm_report: Ignoring duplicate sort field: %s",
     466                 :            :                           rh->fields[field_num].id);
     467                 :          0 :                 return 1;
     468                 :            :         }
     469                 :            : 
     470                 :          1 :         found->flags |= FLD_SORT_KEY;
     471                 :          1 :         found->sort_posn = rh->keys_count++;
     472                 :          1 :         found->flags |= flags;
     473                 :            : 
     474                 :          2 :         return 1;
     475                 :            : }
     476                 :            : 
     477                 :          2 : static int _key_match(struct dm_report *rh, const char *key, size_t len,
     478                 :            :                       unsigned report_type_only)
     479                 :            : {
     480                 :            :         uint32_t f;
     481                 :            :         uint32_t flags;
     482                 :            : 
     483         [ -  + ]:          2 :         if (!len)
     484                 :          0 :                 return 0;
     485                 :            : 
     486         [ -  + ]:          2 :         if (*key == '+') {
     487                 :          0 :                 key++;
     488                 :          0 :                 len--;
     489                 :          0 :                 flags = FLD_ASCENDING;
     490         [ -  + ]:          2 :         } else if (*key == '-') {
     491                 :          0 :                 key++;
     492                 :          0 :                 len--;
     493                 :          0 :                 flags = FLD_DESCENDING;
     494                 :            :         } else
     495                 :          2 :                 flags = FLD_ASCENDING;
     496                 :            : 
     497         [ -  + ]:          2 :         if (!len) {
     498         [ #  # ]:          0 :                 log_error("dm_report: Missing sort field name");
     499                 :          0 :                 return 0;
     500                 :            :         }
     501                 :            : 
     502         [ +  - ]:         48 :         for (f = 0; rh->fields[f].report_fn; f++)
     503         [ +  + ]:         48 :                 if (_is_same_field(rh->fields[f].id, key, len,
     504                 :            :                                    rh->field_prefix))
     505                 :          2 :                         return _add_sort_key(rh, f, flags, report_type_only);
     506                 :            : 
     507                 :          2 :         return 0;
     508                 :            : }
     509                 :            : 
     510                 :          2 : static int _parse_fields(struct dm_report *rh, const char *format,
     511                 :            :                          unsigned report_type_only)
     512                 :            : {
     513                 :            :         const char *ws;         /* Word start */
     514                 :          2 :         const char *we = format;        /* Word end */
     515                 :            : 
     516         [ +  + ]:         14 :         while (*we) {
     517                 :            :                 /* Allow consecutive commas */
     518 [ +  - ][ +  + ]:         22 :                 while (*we && *we == ',')
     519                 :         10 :                         we++;
     520                 :            : 
     521                 :            :                 /* start of the field name */
     522                 :         12 :                 ws = we;
     523 [ +  + ][ +  + ]:         94 :                 while (*we && *we != ',')
     524                 :         82 :                         we++;
     525                 :            : 
     526         [ -  + ]:         12 :                 if (!_field_match(rh, ws, (size_t) (we - ws), report_type_only)) {
     527                 :          0 :                         _display_fields(rh);
     528         [ #  # ]:          0 :                         log_warn(" ");
     529 [ #  # ][ #  # ]:          0 :                         if (strcasecmp(ws, "help") && strcmp(ws, "?"))
     530         [ #  # ]:          0 :                                 log_error("Unrecognised field: %.*s",
     531                 :            :                                           (int) (we - ws), ws);
     532                 :          0 :                         return 0;
     533                 :            :                 }
     534                 :            :         }
     535                 :            : 
     536                 :          2 :         return 1;
     537                 :            : }
     538                 :            : 
     539                 :          2 : static int _parse_keys(struct dm_report *rh, const char *keys,
     540                 :            :                        unsigned report_type_only)
     541                 :            : {
     542                 :            :         const char *ws;         /* Word start */
     543                 :          2 :         const char *we = keys;  /* Word end */
     544                 :            : 
     545         [ +  + ]:          4 :         while (*we) {
     546                 :            :                 /* Allow consecutive commas */
     547 [ +  - ][ -  + ]:          2 :                 while (*we && *we == ',')
     548                 :          0 :                         we++;
     549                 :          2 :                 ws = we;
     550 [ +  + ][ +  - ]:         16 :                 while (*we && *we != ',')
     551                 :         14 :                         we++;
     552         [ -  + ]:          2 :                 if (!_key_match(rh, ws, (size_t) (we - ws), report_type_only)) {
     553         [ #  # ]:          0 :                         log_error("dm_report: Unrecognised field: %.*s",
     554                 :            :                                   (int) (we - ws), ws);
     555                 :          0 :                         return 0;
     556                 :            :                 }
     557                 :            :         }
     558                 :            : 
     559                 :          2 :         return 1;
     560                 :            : }
     561                 :            : 
     562                 :          1 : struct dm_report *dm_report_init(uint32_t *report_types,
     563                 :            :                                  const struct dm_report_object_type *types,
     564                 :            :                                  const struct dm_report_field_type *fields,
     565                 :            :                                  const char *output_fields,
     566                 :            :                                  const char *output_separator,
     567                 :            :                                  uint32_t output_flags,
     568                 :            :                                  const char *sort_keys,
     569                 :            :                                  void *private)
     570                 :            : {
     571                 :            :         struct dm_report *rh;
     572                 :            :         const struct dm_report_object_type *type;
     573                 :            : 
     574         [ -  + ]:          1 :         if (!(rh = dm_malloc(sizeof(*rh)))) {
     575         [ #  # ]:          0 :                 log_error("dm_report_init: dm_malloc failed");
     576                 :          0 :                 return 0;
     577                 :            :         }
     578                 :          1 :         memset(rh, 0, sizeof(*rh));
     579                 :            : 
     580                 :            :         /*
     581                 :            :          * rh->report_types is updated in _parse_fields() and _parse_keys()
     582                 :            :          * to contain all types corresponding to the fields specified by
     583                 :            :          * fields or keys.
     584                 :            :          */
     585         [ +  - ]:          1 :         if (report_types)
     586                 :          1 :                 rh->report_types = *report_types;
     587                 :            : 
     588                 :          1 :         rh->separator = output_separator;
     589                 :          1 :         rh->fields = fields;
     590                 :          1 :         rh->types = types;
     591                 :          1 :         rh->private = private;
     592                 :            : 
     593                 :          1 :         rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK;
     594                 :            : 
     595                 :            :         /* With columns_as_rows we must buffer and not align. */
     596         [ -  + ]:          1 :         if (output_flags & DM_REPORT_OUTPUT_COLUMNS_AS_ROWS) {
     597         [ #  # ]:          0 :                 if (!(output_flags & DM_REPORT_OUTPUT_BUFFERED))
     598                 :          0 :                         rh->flags |= DM_REPORT_OUTPUT_BUFFERED;
     599         [ #  # ]:          0 :                 if (output_flags & DM_REPORT_OUTPUT_ALIGNED)
     600                 :          0 :                         rh->flags &= ~DM_REPORT_OUTPUT_ALIGNED;
     601                 :            :         }
     602                 :            : 
     603         [ +  - ]:          1 :         if (output_flags & DM_REPORT_OUTPUT_BUFFERED)
     604                 :          1 :                 rh->flags |= RH_SORT_REQUIRED;
     605                 :            : 
     606                 :          1 :         dm_list_init(&rh->field_props);
     607                 :          1 :         dm_list_init(&rh->rows);
     608                 :            : 
     609   [ +  -  +  - ]:          1 :         if ((type = _find_type(rh, rh->report_types)) && type->prefix)
     610                 :          1 :                 rh->field_prefix = type->prefix;
     611                 :            :         else
     612                 :          0 :                 rh->field_prefix = "";
     613                 :            : 
     614         [ -  + ]:          1 :         if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
     615         [ #  # ]:          0 :                 log_error("dm_report_init: allocation of memory pool failed");
     616                 :          0 :                 dm_free(rh);
     617                 :          0 :                 return NULL;
     618                 :            :         }
     619                 :            : 
     620                 :            :         /*
     621                 :            :          * To keep the code needed to add the "all" field to a minimum, we parse
     622                 :            :          * the field lists twice.  The first time we only update the report type.
     623                 :            :          * FIXME Use one pass instead and expand the "all" field afterwards.
     624                 :            :          */
     625   [ +  -  -  + ]:          2 :         if (!_parse_fields(rh, output_fields, 1) ||
     626                 :          1 :             !_parse_keys(rh, sort_keys, 1)) {
     627                 :          0 :                 dm_report_free(rh);
     628                 :          0 :                 return NULL;
     629                 :            :         }
     630                 :            : 
     631                 :            :         /* Generate list of fields for output based on format string & flags */
     632   [ +  -  -  + ]:          2 :         if (!_parse_fields(rh, output_fields, 0) ||
     633                 :          1 :             !_parse_keys(rh, sort_keys, 0)) {
     634                 :          0 :                 dm_report_free(rh);
     635                 :          0 :                 return NULL;
     636                 :            :         }
     637                 :            : 
     638                 :            :         /* Return updated types value for further compatility check by caller */
     639         [ +  - ]:          1 :         if (report_types)
     640                 :          1 :                 *report_types = rh->report_types;
     641                 :            : 
     642                 :          1 :         return rh;
     643                 :            : }
     644                 :            : 
     645                 :          1 : void dm_report_free(struct dm_report *rh)
     646                 :            : {
     647                 :          1 :         dm_pool_destroy(rh->mem);
     648                 :          1 :         dm_free(rh);
     649                 :          1 : }
     650                 :            : 
     651                 :          0 : static char *_toupperstr(char *str)
     652                 :            : {
     653                 :          0 :         char *u = str;
     654                 :            : 
     655                 :            :         do
     656                 :          0 :                 *u = toupper(*u);
     657         [ #  # ]:          0 :         while (*u++);
     658                 :            : 
     659                 :          0 :         return str;
     660                 :            : }
     661                 :            : 
     662                 :          0 : int dm_report_set_output_field_name_prefix(struct dm_report *rh, const char *output_field_name_prefix)
     663                 :            : {
     664                 :            :         char *prefix;
     665                 :            : 
     666         [ #  # ]:          0 :         if (!(prefix = dm_pool_strdup(rh->mem, output_field_name_prefix))) {
     667         [ #  # ]:          0 :                 log_error("dm_report_set_output_field_name_prefix: dm_pool_strdup failed");
     668                 :          0 :                 return 0;
     669                 :            :         }
     670                 :            : 
     671                 :          0 :         rh->output_field_name_prefix = _toupperstr(prefix);
     672                 :            :         
     673                 :          0 :         return 1;
     674                 :            : }
     675                 :            : 
     676                 :            : /*
     677                 :            :  * Create a row of data for an object
     678                 :            :  */
     679                 :          0 : static void * _report_get_field_data(struct dm_report *rh,
     680                 :            :                               struct field_properties *fp, void *object)
     681                 :            : {
     682                 :          0 :         void *ret = fp->type->data_fn(object);
     683                 :            : 
     684         [ #  # ]:          0 :         if (!ret)
     685                 :          0 :                 return NULL;
     686                 :            : 
     687                 :          0 :         return ret + rh->fields[fp->field_num].offset;
     688                 :            : }
     689                 :            : 
     690                 :          0 : int dm_report_object(struct dm_report *rh, void *object)
     691                 :            : {
     692                 :            :         struct field_properties *fp;
     693                 :            :         struct row *row;
     694                 :            :         struct dm_report_field *field;
     695                 :          0 :         void *data = NULL;
     696                 :            : 
     697         [ #  # ]:          0 :         if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
     698         [ #  # ]:          0 :                 log_error("dm_report_object: struct row allocation failed");
     699                 :          0 :                 return 0;
     700                 :            :         }
     701                 :            : 
     702                 :          0 :         row->rh = rh;
     703                 :            : 
     704   [ #  #  #  # ]:          0 :         if ((rh->flags & RH_SORT_REQUIRED) &&
     705                 :          0 :             !(row->sort_fields =
     706                 :          0 :                 dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) *
     707                 :            :                                rh->keys_count))) {
     708         [ #  # ]:          0 :                 log_error("dm_report_object: "
     709                 :            :                           "row sort value structure allocation failed");
     710                 :          0 :                 return 0;
     711                 :            :         }
     712                 :            : 
     713                 :          0 :         dm_list_init(&row->fields);
     714                 :          0 :         dm_list_add(&rh->rows, &row->list);
     715                 :            : 
     716                 :            :         /* For each field to be displayed, call its report_fn */
     717         [ #  # ]:          0 :         dm_list_iterate_items(fp, &rh->field_props) {
     718         [ #  # ]:          0 :                 if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
     719         [ #  # ]:          0 :                         log_error("dm_report_object: "
     720                 :            :                                   "struct dm_report_field allocation failed");
     721                 :          0 :                         return 0;
     722                 :            :                 }
     723                 :          0 :                 field->props = fp;
     724                 :            : 
     725                 :          0 :                 data = _report_get_field_data(rh, fp, object);
     726         [ #  # ]:          0 :                 if (!data)
     727                 :          0 :                         return 0;
     728                 :            : 
     729         [ #  # ]:          0 :                 if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
     730                 :            :                                                          field, data,
     731                 :            :                                                          rh->private)) {
     732         [ #  # ]:          0 :                         log_error("dm_report_object: "
     733                 :            :                                   "report function failed for field %s",
     734                 :            :                                   rh->fields[fp->field_num].id);
     735                 :          0 :                         return 0;
     736                 :            :                 }
     737                 :            : 
     738         [ #  # ]:          0 :                 if ((strlen(field->report_string) > field->props->width))
     739                 :          0 :                         field->props->width = strlen(field->report_string);
     740                 :            : 
     741 [ #  # ][ #  # ]:          0 :                 if ((rh->flags & RH_SORT_REQUIRED) &&
     742                 :          0 :                     (field->props->flags & FLD_SORT_KEY)) {
     743                 :          0 :                         (*row->sort_fields)[field->props->sort_posn] = field;
     744                 :            :                 }
     745                 :          0 :                 dm_list_add(&row->fields, &field->list);
     746                 :            :         }
     747                 :            : 
     748         [ #  # ]:          0 :         if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
     749                 :          0 :                 return dm_report_output(rh);
     750                 :            : 
     751                 :          0 :         return 1;
     752                 :            : }
     753                 :            : 
     754                 :            : /*
     755                 :            :  * Print row of headings
     756                 :            :  */
     757                 :          0 : static int _report_headings(struct dm_report *rh)
     758                 :            : {
     759                 :            :         struct field_properties *fp;
     760                 :            :         const char *heading;
     761                 :            :         char buf[1024];
     762                 :            : 
     763         [ #  # ]:          0 :         if (rh->flags & RH_HEADINGS_PRINTED)
     764                 :          0 :                 return 1;
     765                 :            : 
     766                 :          0 :         rh->flags |= RH_HEADINGS_PRINTED;
     767                 :            : 
     768         [ #  # ]:          0 :         if (!(rh->flags & DM_REPORT_OUTPUT_HEADINGS))
     769                 :          0 :                 return 1;
     770                 :            : 
     771         [ #  # ]:          0 :         if (!dm_pool_begin_object(rh->mem, 128)) {
     772         [ #  # ]:          0 :                 log_error("dm_report: "
     773                 :            :                           "dm_pool_begin_object failed for headings");
     774                 :          0 :                 return 0;
     775                 :            :         }
     776                 :            : 
     777                 :            :         /* First heading line */
     778         [ #  # ]:          0 :         dm_list_iterate_items(fp, &rh->field_props) {
     779         [ #  # ]:          0 :                 if (fp->flags & FLD_HIDDEN)
     780                 :          0 :                         continue;
     781                 :            : 
     782                 :          0 :                 heading = rh->fields[fp->field_num].heading;
     783         [ #  # ]:          0 :                 if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
     784         [ #  # ]:          0 :                         if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
     785                 :            :                                          fp->width, fp->width, heading) < 0) {
     786         [ #  # ]:          0 :                                 log_error("dm_report: snprintf heading failed");
     787                 :          0 :                                 goto bad;
     788                 :            :                         }
     789         [ #  # ]:          0 :                         if (!dm_pool_grow_object(rh->mem, buf, fp->width)) {
     790         [ #  # ]:          0 :                                 log_error("dm_report: Failed to generate report headings for printing");
     791                 :          0 :                                 goto bad;
     792                 :            :                         }
     793         [ #  # ]:          0 :                 } else if (!dm_pool_grow_object(rh->mem, heading, 0)) {
     794         [ #  # ]:          0 :                         log_error("dm_report: Failed to generate report headings for printing");
     795                 :          0 :                         goto bad;
     796                 :            :                 }
     797                 :            : 
     798         [ #  # ]:          0 :                 if (!dm_list_end(&rh->field_props, &fp->list))
     799         [ #  # ]:          0 :                         if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
     800         [ #  # ]:          0 :                                 log_error("dm_report: Failed to generate report headings for printing");
     801                 :          0 :                                 goto bad;
     802                 :            :                         }
     803                 :            :         }
     804         [ #  # ]:          0 :         if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
     805         [ #  # ]:          0 :                 log_error("dm_report: Failed to generate report headings for printing");
     806                 :          0 :                 goto bad;
     807                 :            :         }
     808         [ #  # ]:          0 :         log_print("%s", (char *) dm_pool_end_object(rh->mem));
     809                 :            : 
     810                 :          0 :         return 1;
     811                 :            : 
     812                 :            :       bad:
     813                 :          0 :         dm_pool_abandon_object(rh->mem);
     814                 :          0 :         return 0;
     815                 :            : }
     816                 :            : 
     817                 :            : /*
     818                 :            :  * Sort rows of data
     819                 :            :  */
     820                 :          0 : static int _row_compare(const void *a, const void *b)
     821                 :            : {
     822                 :          0 :         const struct row *rowa = *(const struct row * const *) a;
     823                 :          0 :         const struct row *rowb = *(const struct row * const *) b;
     824                 :            :         const struct dm_report_field *sfa, *sfb;
     825                 :            :         uint32_t cnt;
     826                 :            : 
     827         [ #  # ]:          0 :         for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
     828                 :          0 :                 sfa = (*rowa->sort_fields)[cnt];
     829                 :          0 :                 sfb = (*rowb->sort_fields)[cnt];
     830         [ #  # ]:          0 :                 if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) {
     831                 :            :                         const uint64_t numa =
     832                 :          0 :                             *(const uint64_t *) sfa->sort_value;
     833                 :            :                         const uint64_t numb =
     834                 :          0 :                             *(const uint64_t *) sfb->sort_value;
     835                 :            : 
     836         [ #  # ]:          0 :                         if (numa == numb)
     837                 :          0 :                                 continue;
     838                 :            : 
     839         [ #  # ]:          0 :                         if (sfa->props->flags & FLD_ASCENDING) {
     840         [ #  # ]:          0 :                                 return (numa > numb) ? 1 : -1;
     841                 :            :                         } else {        /* FLD_DESCENDING */
     842         [ #  # ]:          0 :                                 return (numa < numb) ? 1 : -1;
     843                 :            :                         }
     844                 :            :                 } else {        /* DM_REPORT_FIELD_TYPE_STRING */
     845                 :          0 :                         const char *stra = (const char *) sfa->sort_value;
     846                 :          0 :                         const char *strb = (const char *) sfb->sort_value;
     847                 :          0 :                         int cmp = strcmp(stra, strb);
     848                 :            : 
     849         [ #  # ]:          0 :                         if (!cmp)
     850                 :          0 :                                 continue;
     851                 :            : 
     852         [ #  # ]:          0 :                         if (sfa->props->flags & FLD_ASCENDING) {
     853         [ #  # ]:          0 :                                 return (cmp > 0) ? 1 : -1;
     854                 :            :                         } else {        /* FLD_DESCENDING */
     855         [ #  # ]:          0 :                                 return (cmp < 0) ? 1 : -1;
     856                 :            :                         }
     857                 :            :                 }
     858                 :            :         }
     859                 :            : 
     860                 :          0 :         return 0;               /* Identical */
     861                 :            : }
     862                 :            : 
     863                 :          0 : static int _sort_rows(struct dm_report *rh)
     864                 :            : {
     865                 :            :         struct row *(*rows)[];
     866                 :          0 :         uint32_t count = 0;
     867                 :            :         struct row *row;
     868                 :            : 
     869         [ #  # ]:          0 :         if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
     870                 :          0 :                                 dm_list_size(&rh->rows)))) {
     871         [ #  # ]:          0 :                 log_error("dm_report: sort array allocation failed");
     872                 :          0 :                 return 0;
     873                 :            :         }
     874                 :            : 
     875         [ #  # ]:          0 :         dm_list_iterate_items(row, &rh->rows)
     876                 :          0 :                 (*rows)[count++] = row;
     877                 :            : 
     878                 :          0 :         qsort(rows, count, sizeof(**rows), _row_compare);
     879                 :            : 
     880                 :          0 :         dm_list_init(&rh->rows);
     881         [ #  # ]:          0 :         while (count--)
     882                 :          0 :                 dm_list_add_h(&rh->rows, &(*rows)[count]->list);
     883                 :            : 
     884                 :          0 :         return 1;
     885                 :            : }
     886                 :            : 
     887                 :            : /*
     888                 :            :  * Produce report output
     889                 :            :  */
     890                 :          0 : static int _output_field(struct dm_report *rh, struct dm_report_field *field)
     891                 :            : {
     892                 :            :         char *field_id;
     893                 :            :         int32_t width;
     894                 :            :         uint32_t align;
     895                 :            :         const char *repstr;
     896                 :            :         char buf[4096];
     897                 :            : 
     898         [ #  # ]:          0 :         if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
     899         [ #  # ]:          0 :                 if (!(field_id = strdup(rh->fields[field->props->field_num].id))) {
     900         [ #  # ]:          0 :                         log_error("dm_report: Failed to copy field name");
     901                 :          0 :                         return 0;
     902                 :            :                 }
     903                 :            : 
     904         [ #  # ]:          0 :                 if (!dm_pool_grow_object(rh->mem, rh->output_field_name_prefix, 0)) {
     905         [ #  # ]:          0 :                         log_error("dm_report: Unable to extend output line");
     906                 :          0 :                         return 0;
     907                 :            :                 }
     908                 :            : 
     909         [ #  # ]:          0 :                 if (!dm_pool_grow_object(rh->mem, _toupperstr(field_id), 0)) {
     910         [ #  # ]:          0 :                         log_error("dm_report: Unable to extend output line");
     911                 :          0 :                         return 0;
     912                 :            :                 }
     913                 :            : 
     914                 :          0 :                 free(field_id);
     915                 :            : 
     916         [ #  # ]:          0 :                 if (!dm_pool_grow_object(rh->mem, "=", 1)) {
     917         [ #  # ]:          0 :                         log_error("dm_report: Unable to extend output line");
     918                 :          0 :                         return 0;
     919                 :            :                 }
     920                 :            : 
     921   [ #  #  #  # ]:          0 :                 if (!(rh->flags & DM_REPORT_OUTPUT_FIELD_UNQUOTED) &&
     922                 :          0 :                     !dm_pool_grow_object(rh->mem, "\'", 1)) {
     923         [ #  # ]:          0 :                         log_error("dm_report: Unable to extend output line");
     924                 :          0 :                         return 0;
     925                 :            :                 }
     926                 :            :         }
     927                 :            : 
     928                 :          0 :         repstr = field->report_string;
     929                 :          0 :         width = field->props->width;
     930         [ #  # ]:          0 :         if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
     931         [ #  # ]:          0 :                 if (!dm_pool_grow_object(rh->mem, repstr, 0)) {
     932         [ #  # ]:          0 :                         log_error("dm_report: Unable to extend output line");
     933                 :          0 :                         return 0;
     934                 :            :                 }
     935                 :            :         } else {
     936         [ #  # ]:          0 :                 if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
     937         [ #  # ]:          0 :                         align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ? 
     938                 :            :                                 DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
     939         [ #  # ]:          0 :                 if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
     940         [ #  # ]:          0 :                         if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
     941                 :            :                                          width, width, repstr) < 0) {
     942         [ #  # ]:          0 :                                 log_error("dm_report: left-aligned snprintf() failed");
     943                 :          0 :                                 return 0;
     944                 :            :                         }
     945         [ #  # ]:          0 :                         if (!dm_pool_grow_object(rh->mem, buf, width)) {
     946         [ #  # ]:          0 :                                 log_error("dm_report: Unable to extend output line");
     947                 :          0 :                                 return 0;
     948                 :            :                         }
     949         [ #  # ]:          0 :                 } else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
     950         [ #  # ]:          0 :                         if (dm_snprintf(buf, sizeof(buf), "%*.*s",
     951                 :            :                                          width, width, repstr) < 0) {
     952         [ #  # ]:          0 :                                 log_error("dm_report: right-aligned snprintf() failed");
     953                 :          0 :                                 return 0;
     954                 :            :                         }
     955         [ #  # ]:          0 :                         if (!dm_pool_grow_object(rh->mem, buf, width)) {
     956         [ #  # ]:          0 :                                 log_error("dm_report: Unable to extend output line");
     957                 :          0 :                                 return 0;
     958                 :            :                         }
     959                 :            :                 }
     960                 :            :         }
     961                 :            : 
     962 [ #  # ][ #  # ]:          0 :         if ((rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) &&
     963                 :          0 :             !(rh->flags & DM_REPORT_OUTPUT_FIELD_UNQUOTED))
     964         [ #  # ]:          0 :                 if (!dm_pool_grow_object(rh->mem, "\'", 1)) {
     965         [ #  # ]:          0 :                         log_error("dm_report: Unable to extend output line");
     966                 :          0 :                         return 0;
     967                 :            :                 }
     968                 :            : 
     969                 :          0 :         return 1;
     970                 :            : }
     971                 :            : 
     972                 :          0 : static int _output_as_rows(struct dm_report *rh)
     973                 :            : {
     974                 :            :         struct field_properties *fp;
     975                 :            :         struct dm_report_field *field;
     976                 :            :         struct row *row;
     977                 :            : 
     978         [ #  # ]:          0 :         if (!dm_pool_begin_object(rh->mem, 512)) {
     979         [ #  # ]:          0 :                 log_error("dm_report: Unable to allocate output line");
     980                 :          0 :                 return 0;
     981                 :            :         }
     982                 :            : 
     983         [ #  # ]:          0 :         dm_list_iterate_items(fp, &rh->field_props) {
     984         [ #  # ]:          0 :                 if (fp->flags & FLD_HIDDEN) {
     985         [ #  # ]:          0 :                         dm_list_iterate_items(row, &rh->rows) {
     986                 :          0 :                                 field = dm_list_item(dm_list_first(&row->fields), struct dm_report_field);
     987                 :          0 :                                 dm_list_del(&field->list);
     988                 :            :                         }
     989                 :          0 :                         continue;
     990                 :            :                 }
     991                 :            : 
     992         [ #  # ]:          0 :                 if ((rh->flags & DM_REPORT_OUTPUT_HEADINGS)) {
     993         [ #  # ]:          0 :                         if (!dm_pool_grow_object(rh->mem, rh->fields[fp->field_num].heading, 0)) {
     994         [ #  # ]:          0 :                                 log_error("dm_report: Failed to extend row for field name");
     995                 :          0 :                                 goto bad;
     996                 :            :                         }
     997         [ #  # ]:          0 :                         if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
     998         [ #  # ]:          0 :                                 log_error("dm_report: Failed to extend row with separator");
     999                 :          0 :                                 goto bad;
    1000                 :            :                         }
    1001                 :            :                 }
    1002                 :            : 
    1003         [ #  # ]:          0 :                 dm_list_iterate_items(row, &rh->rows) {
    1004         [ #  # ]:          0 :                         if ((field = dm_list_item(dm_list_first(&row->fields), struct dm_report_field))) {
    1005         [ #  # ]:          0 :                                 if (!_output_field(rh, field))
    1006                 :          0 :                                         goto bad;
    1007                 :          0 :                                 dm_list_del(&field->list);
    1008                 :            :                         }
    1009                 :            : 
    1010         [ #  # ]:          0 :                         if (!dm_list_end(&rh->rows, &row->list))
    1011         [ #  # ]:          0 :                                 if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
    1012         [ #  # ]:          0 :                                         log_error("dm_report: Unable to extend output line");
    1013                 :          0 :                                         goto bad;
    1014                 :            :                                 }
    1015                 :            :                 }
    1016                 :            : 
    1017         [ #  # ]:          0 :                 if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
    1018         [ #  # ]:          0 :                         log_error("dm_report: Failed to terminate row");
    1019                 :          0 :                         goto bad;
    1020                 :            :                 }
    1021         [ #  # ]:          0 :                 log_print("%s", (char *) dm_pool_end_object(rh->mem));
    1022                 :            :         }
    1023                 :            : 
    1024                 :          0 :         return 1;
    1025                 :            : 
    1026                 :            :       bad:
    1027                 :          0 :         dm_pool_abandon_object(rh->mem);
    1028                 :          0 :         return 0;
    1029                 :            : }
    1030                 :            : 
    1031                 :          0 : static int _output_as_columns(struct dm_report *rh)
    1032                 :            : {
    1033                 :            :         struct dm_list *fh, *rowh, *ftmp, *rtmp;
    1034                 :          0 :         struct row *row = NULL;
    1035                 :            :         struct dm_report_field *field;
    1036                 :            : 
    1037                 :            :         /* If headings not printed yet, calculate field widths and print them */
    1038         [ #  # ]:          0 :         if (!(rh->flags & RH_HEADINGS_PRINTED))
    1039                 :          0 :                 _report_headings(rh);
    1040                 :            : 
    1041                 :            :         /* Print and clear buffer */
    1042         [ #  # ]:          0 :         dm_list_iterate_safe(rowh, rtmp, &rh->rows) {
    1043         [ #  # ]:          0 :                 if (!dm_pool_begin_object(rh->mem, 512)) {
    1044         [ #  # ]:          0 :                         log_error("dm_report: Unable to allocate output line");
    1045                 :          0 :                         return 0;
    1046                 :            :                 }
    1047                 :          0 :                 row = dm_list_item(rowh, struct row);
    1048         [ #  # ]:          0 :                 dm_list_iterate_safe(fh, ftmp, &row->fields) {
    1049                 :          0 :                         field = dm_list_item(fh, struct dm_report_field);
    1050         [ #  # ]:          0 :                         if (field->props->flags & FLD_HIDDEN)
    1051                 :          0 :                                 continue;
    1052                 :            : 
    1053         [ #  # ]:          0 :                         if (!_output_field(rh, field))
    1054                 :          0 :                                 goto bad;
    1055                 :            : 
    1056         [ #  # ]:          0 :                         if (!dm_list_end(&row->fields, fh))
    1057         [ #  # ]:          0 :                                 if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
    1058         [ #  # ]:          0 :                                         log_error("dm_report: Unable to extend output line");
    1059                 :          0 :                                         goto bad;
    1060                 :            :                                 }
    1061                 :            : 
    1062                 :          0 :                         dm_list_del(&field->list);
    1063                 :            :                 }
    1064         [ #  # ]:          0 :                 if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
    1065         [ #  # ]:          0 :                         log_error("dm_report: Unable to terminate output line");
    1066                 :          0 :                         goto bad;
    1067                 :            :                 }
    1068         [ #  # ]:          0 :                 log_print("%s", (char *) dm_pool_end_object(rh->mem));
    1069                 :          0 :                 dm_list_del(&row->list);
    1070                 :            :         }
    1071                 :            : 
    1072         [ #  # ]:          0 :         if (row)
    1073                 :          0 :                 dm_pool_free(rh->mem, row);
    1074                 :            : 
    1075                 :          0 :         return 1;
    1076                 :            : 
    1077                 :            :       bad:
    1078                 :          0 :         dm_pool_abandon_object(rh->mem);
    1079                 :          0 :         return 0;
    1080                 :            : }
    1081                 :            : 
    1082                 :          1 : int dm_report_output(struct dm_report *rh)
    1083                 :            : {
    1084         [ +  - ]:          1 :         if (dm_list_empty(&rh->rows))
    1085                 :          1 :                 return 1;
    1086                 :            : 
    1087         [ #  # ]:          0 :         if ((rh->flags & RH_SORT_REQUIRED))
    1088                 :          0 :                 _sort_rows(rh);
    1089                 :            : 
    1090         [ #  # ]:          0 :         if ((rh->flags & DM_REPORT_OUTPUT_COLUMNS_AS_ROWS))
    1091                 :          0 :                 return _output_as_rows(rh);
    1092                 :            :         else
    1093                 :          1 :                 return _output_as_columns(rh);
    1094                 :            : }

Generated by: LCOV version 1.8