📄 libdm-report.c
字号:
const char *we = format; /* Word end */ while (*we) { /* Allow consecutive commas */ while (*we && *we == ',') we++; /* start of the field name */ ws = we; while (*we && *we != ',') we++; if (!_field_match(rh, ws, (size_t) (we - ws))) { _display_fields(rh); log_print(" "); if (strcasecmp(ws, "help") && strcmp(ws, "?")) log_error("Unrecognised field: %.*s", (int) (we - ws), ws); return 0; } } return 1;}static int _parse_keys(struct dm_report *rh, const char *keys){ const char *ws; /* Word start */ const char *we = keys; /* Word end */ while (*we) { /* Allow consecutive commas */ while (*we && *we == ',') we++; ws = we; while (*we && *we != ',') we++; if (!_key_match(rh, ws, (size_t) (we - ws))) { log_error("dm_report: Unrecognised field: %.*s", (int) (we - ws), ws); return 0; } } return 1;}struct dm_report *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){ struct dm_report *rh; const struct dm_report_object_type *type; if (!(rh = dm_malloc(sizeof(*rh)))) { log_error("dm_report_init: dm_malloc failed"); return 0; } memset(rh, 0, sizeof(*rh)); /* * rh->report_types is updated in _parse_options() and _parse_keys() * to contain all types corresponding to the fields specified by * options or keys. */ if (report_types) rh->report_types = *report_types; rh->separator = output_separator; rh->fields = fields; rh->types = types; rh->private = private; rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK; if (output_flags & DM_REPORT_OUTPUT_BUFFERED) rh->flags |= RH_SORT_REQUIRED; list_init(&rh->field_props); list_init(&rh->rows); if ((type = _find_type(rh, rh->report_types)) && type->prefix) rh->field_prefix = type->prefix; else rh->field_prefix = ""; if (!(rh->mem = dm_pool_create("report", 10 * 1024))) { log_error("dm_report_init: allocation of memory pool failed"); dm_free(rh); return NULL; } /* Generate list of fields for output based on format string & flags */ if (!_parse_options(rh, output_fields)) { dm_report_free(rh); return NULL; } if (!_parse_keys(rh, sort_keys)) { dm_report_free(rh); return NULL; } /* Return updated types value for further compatility check by caller */ if (report_types) *report_types = rh->report_types; return rh;}void dm_report_free(struct dm_report *rh){ dm_pool_destroy(rh->mem); dm_free(rh);}/* * Create a row of data for an object */static void * _report_get_field_data(struct dm_report *rh, struct field_properties *fp, void *object){ void *ret = fp->type->data_fn(object); if (!ret) return NULL; return ret + rh->fields[fp->field_num].offset;}int dm_report_object(struct dm_report *rh, void *object){ struct field_properties *fp; struct row *row; struct dm_report_field *field; void *data = NULL; if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) { log_error("dm_report_object: struct row allocation failed"); return 0; } row->rh = rh; if ((rh->flags & RH_SORT_REQUIRED) && !(row->sort_fields = dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) * rh->keys_count))) { log_error("dm_report_object: " "row sort value structure allocation failed"); return 0; } list_init(&row->fields); list_add(&rh->rows, &row->list); /* For each field to be displayed, call its report_fn */ list_iterate_items(fp, &rh->field_props) { if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) { log_error("dm_report_object: " "struct dm_report_field allocation failed"); return 0; } field->props = fp; data = _report_get_field_data(rh, fp, object); if (!data) return 0; if (!rh->fields[fp->field_num].report_fn(rh, rh->mem, field, data, rh->private)) { log_error("dm_report_object: " "report function failed for field %s", rh->fields[fp->field_num].id); return 0; } if ((strlen(field->report_string) > field->props->width)) field->props->width = strlen(field->report_string); if ((rh->flags & RH_SORT_REQUIRED) && (field->props->flags & FLD_SORT_KEY)) { (*row->sort_fields)[field->props->sort_posn] = field; } list_add(&row->fields, &field->list); } if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED)) return dm_report_output(rh); return 1;}/* * Print row of headings */static int _report_headings(struct dm_report *rh){ struct field_properties *fp; const char *heading; char buf[1024]; if (rh->flags & RH_HEADINGS_PRINTED) return 1; rh->flags |= RH_HEADINGS_PRINTED; if (!(rh->flags & DM_REPORT_OUTPUT_HEADINGS)) return 1; if (!dm_pool_begin_object(rh->mem, 128)) { log_error("dm_report: " "dm_pool_begin_object failed for headings"); return 0; } /* First heading line */ list_iterate_items(fp, &rh->field_props) { if (fp->flags & FLD_HIDDEN) continue; heading = rh->fields[fp->field_num].heading; if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) { if (dm_snprintf(buf, sizeof(buf), "%-*.*s", fp->width, fp->width, heading) < 0) { log_error("dm_report: snprintf heading failed"); goto bad; } if (!dm_pool_grow_object(rh->mem, buf, fp->width)) { log_error("dm_report: Failed to generate report headings for printing"); goto bad; } } else if (!dm_pool_grow_object(rh->mem, heading, strlen(heading))) { log_error("dm_report: Failed to generate report headings for printing"); goto bad; } if (!list_end(&rh->field_props, &fp->list)) if (!dm_pool_grow_object(rh->mem, rh->separator, strlen(rh->separator))) { log_error("dm_report: Failed to generate report headings for printing"); goto bad; } } if (!dm_pool_grow_object(rh->mem, "\0", 1)) { log_error("dm_report: Failed to generate report headings for printing"); goto bad; } log_print("%s", (char *) dm_pool_end_object(rh->mem)); return 1; bad: dm_pool_abandon_object(rh->mem); return 0;}/* * Sort rows of data */static int _row_compare(const void *a, const void *b){ const struct row *rowa = *(const struct row **) a; const struct row *rowb = *(const struct row **) b; const struct dm_report_field *sfa, *sfb; uint32_t cnt; for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) { sfa = (*rowa->sort_fields)[cnt]; sfb = (*rowb->sort_fields)[cnt]; if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) { const uint64_t numa = *(const uint64_t *) sfa->sort_value; const uint64_t numb = *(const uint64_t *) sfb->sort_value; if (numa == numb) continue; if (sfa->props->flags & FLD_ASCENDING) { return (numa > numb) ? 1 : -1; } else { /* FLD_DESCENDING */ return (numa < numb) ? 1 : -1; } } else { /* DM_REPORT_FIELD_TYPE_STRING */ const char *stra = (const char *) sfa->sort_value; const char *strb = (const char *) sfb->sort_value; int cmp = strcmp(stra, strb); if (!cmp) continue; if (sfa->props->flags & FLD_ASCENDING) { return (cmp > 0) ? 1 : -1; } else { /* FLD_DESCENDING */ return (cmp < 0) ? 1 : -1; } } } return 0; /* Identical */}static int _sort_rows(struct dm_report *rh){ struct row *(*rows)[]; uint32_t count = 0; struct row *row; if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) * list_size(&rh->rows)))) { log_error("dm_report: sort array allocation failed"); return 0; } list_iterate_items(row, &rh->rows) (*rows)[count++] = row; qsort(rows, count, sizeof(**rows), _row_compare); list_init(&rh->rows); while (count--) list_add_h(&rh->rows, &(*rows)[count]->list); return 1;}/* * Produce report output */int dm_report_output(struct dm_report *rh){ struct list *fh, *rowh, *ftmp, *rtmp; struct row *row = NULL; struct dm_report_field *field; const char *repstr; char buf[4096]; int32_t width; uint32_t align; if (list_empty(&rh->rows)) return 1; /* Sort rows */ if ((rh->flags & RH_SORT_REQUIRED)) _sort_rows(rh); /* If headings not printed yet, calculate field widths and print them */ if (!(rh->flags & RH_HEADINGS_PRINTED)) _report_headings(rh); /* Print and clear buffer */ list_iterate_safe(rowh, rtmp, &rh->rows) { if (!dm_pool_begin_object(rh->mem, 512)) { log_error("dm_report: Unable to allocate output line"); return 0; } row = list_item(rowh, struct row); list_iterate_safe(fh, ftmp, &row->fields) { field = list_item(fh, struct dm_report_field); if (field->props->flags & FLD_HIDDEN) continue; repstr = field->report_string; width = field->props->width; if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) { if (!dm_pool_grow_object(rh->mem, repstr, strlen(repstr))) { log_error("dm_report: Unable to extend output line"); goto bad; } } else { if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK)) align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ? DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT; if (align & DM_REPORT_FIELD_ALIGN_LEFT) { if (dm_snprintf(buf, sizeof(buf), "%-*.*s", width, width, repstr) < 0) { log_error("dm_report: left-aligned snprintf() failed"); goto bad; } if (!dm_pool_grow_object(rh->mem, buf, width)) { log_error("dm_report: Unable to extend output line"); goto bad; } } else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) { if (dm_snprintf(buf, sizeof(buf), "%*.*s", width, width, repstr) < 0) { log_error("dm_report: right-aligned snprintf() failed"); goto bad; } if (!dm_pool_grow_object(rh->mem, buf, width)) { log_error("dm_report: Unable to extend output line"); goto bad; } } } if (!list_end(&row->fields, fh)) if (!dm_pool_grow_object(rh->mem, rh->separator, strlen(rh->separator))) { log_error("dm_report: Unable to extend output line"); goto bad; } list_del(&field->list); } if (!dm_pool_grow_object(rh->mem, "\0", 1)) { log_error("dm_report: Unable to terminate output line"); goto bad; } log_print("%s", (char *) dm_pool_end_object(rh->mem)); list_del(&row->list); } if (row) dm_pool_free(rh->mem, row); return 1; bad: dm_pool_abandon_object(rh->mem); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -