mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
This commit is contained in:
452
zdev/src/table.c
Normal file
452
zdev/src/table.c
Normal file
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2016, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/util_base.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "table.h"
|
||||
|
||||
/* Search for a column in @columns which matches the specified @name. Return
|
||||
* corresponding struct column on success, NULL otherwise. */
|
||||
struct column *table_get_column(struct column *columns, const char *name)
|
||||
{
|
||||
struct column *c;
|
||||
int i;
|
||||
|
||||
for (i = 0; columns[i].name; i++) {
|
||||
c = &columns[i];
|
||||
if (strcasecmp(c->name, name) == 0)
|
||||
return c;
|
||||
if (strchr(c->name, ':') && starts_with_nocase(name, c->name))
|
||||
return c;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* cell - Representation of a single table cell
|
||||
* @id: Column ID of the cell
|
||||
* @heading: Actual column heading
|
||||
* @value: Cell contents
|
||||
* @width: Total width of cell
|
||||
* @align: Alignment of cell text
|
||||
*
|
||||
*/
|
||||
struct cell {
|
||||
char *value;
|
||||
char *heading;
|
||||
int id;
|
||||
int width;
|
||||
align_t align;
|
||||
};
|
||||
|
||||
/* Used for debugging. */
|
||||
void cells_print(struct cell *cells, int indent)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("%*scells at %p\n", indent, "", (void *) cells);
|
||||
if (!cells)
|
||||
return;
|
||||
indent += 2;
|
||||
for (i = 0; cells[i].heading; i++) {
|
||||
printf("%*scells[%d]:\n", indent, "", i);
|
||||
printf("%*svalue=%s\n", indent + 2, "", cells[i].value);
|
||||
printf("%*sheading=%s\n", indent + 2, "", cells[i].heading);
|
||||
printf("%*sid=%d\n", indent + 2, "", cells[i].id);
|
||||
printf("%*swidth=%d\n", indent + 2, "", cells[i].width);
|
||||
printf("%*salign=%d\n", indent + 2, "", cells[i].align);
|
||||
}
|
||||
}
|
||||
|
||||
static void cells_free(struct cell *cells)
|
||||
{
|
||||
int i;
|
||||
struct cell *c;
|
||||
|
||||
if (!cells)
|
||||
return;
|
||||
for (i = 0; cells[i].heading; i++) {
|
||||
c = &cells[i];
|
||||
free(c->value);
|
||||
free(c->heading);
|
||||
}
|
||||
free(cells);
|
||||
}
|
||||
|
||||
/* Return a newly allocated array of struct cells containing a struct cell for
|
||||
* each default column in the specified table. */
|
||||
static struct cell *cells_get_default(struct column *columns)
|
||||
{
|
||||
int i, num;
|
||||
struct cell *cells;
|
||||
|
||||
/* Determine number of default columns. */
|
||||
num = 0;
|
||||
for (i = 0; columns[i].name; i++) {
|
||||
if (!columns[i].def)
|
||||
continue;
|
||||
num++;
|
||||
}
|
||||
|
||||
/* Allocated cells array. */
|
||||
cells = misc_malloc((num + 1) * sizeof(struct cell));
|
||||
|
||||
/* Initialize cells for default columns. */
|
||||
num = 0;
|
||||
for (i = 0; columns[i].name; i++) {
|
||||
if (!columns[i].def)
|
||||
continue;
|
||||
cells[num].heading = misc_strdup(columns[i].name);
|
||||
cells[num].id = columns[i].id;
|
||||
cells[num].align = columns[i].align;
|
||||
num++;
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
/* Return a newly allocated array of struct cells containing a struct cell for
|
||||
* each column definition whose name was specified in strlist @names. */
|
||||
static struct cell *cells_get(struct column *columns, struct util_list *names)
|
||||
{
|
||||
unsigned long num;
|
||||
struct cell *cells;
|
||||
int i;
|
||||
const struct column *column;
|
||||
struct strlist_node *s;
|
||||
|
||||
num = util_list_len(names);
|
||||
cells = misc_malloc((num + 1) * sizeof(struct cell));
|
||||
|
||||
i = 0;
|
||||
util_list_iterate(names, s) {
|
||||
column = table_get_column(columns, s->str);
|
||||
if (!column)
|
||||
goto err_unknown;
|
||||
cells[i].heading = misc_strdup(s->str);
|
||||
cells[i].id = column->id;
|
||||
cells[i].align = column->align;
|
||||
i++;
|
||||
}
|
||||
|
||||
return cells;
|
||||
|
||||
err_unknown:
|
||||
cells_free(cells);
|
||||
error("Unknown column name specified: %s\n", s->str);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Determine maximum width for values and headings in table. */
|
||||
static void cells_get_width(struct cell *cells, struct util_list *items,
|
||||
table_value_cb_t value_cb, void *data)
|
||||
{
|
||||
int i, len;
|
||||
struct cell *c;
|
||||
struct ptrlist_node *p;
|
||||
char *val;
|
||||
|
||||
/* Initialize widths. */
|
||||
for (i = 0; cells[i].heading; i++)
|
||||
cells[i].width = strlen(cells[i].heading);
|
||||
|
||||
/* Determine largest width from items. */
|
||||
util_list_iterate(items, p) {
|
||||
for (i = 0; cells[i].heading; i++) {
|
||||
c = &cells[i];
|
||||
val = value_cb(p->ptr, c->id, c->heading, data);
|
||||
if (!val)
|
||||
continue;
|
||||
len = strlen(val);
|
||||
free(val);
|
||||
if (c->width < len)
|
||||
c->width = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the optimal space delimiter for the specified cells. */
|
||||
static const char *cells_get_space(struct cell *cells, struct util_list *items,
|
||||
table_value_cb_t value_cb, void *data,
|
||||
int indent)
|
||||
{
|
||||
char *val;
|
||||
int columns, i, off_one, off_two, last, wrap_one, wrap_two, len;
|
||||
struct ptrlist_node *p;
|
||||
struct cell *c;
|
||||
|
||||
/* Quick exit on special case to make processing simpler. */
|
||||
if (!cells[0].heading)
|
||||
return " ";
|
||||
|
||||
/* Determine column offset of last column. */
|
||||
off_one = indent;
|
||||
off_two = indent;
|
||||
for (i = 0; cells[i + 1].heading; i++) {
|
||||
off_one += cells[i].width + 1;
|
||||
off_two += cells[i].width + 2;
|
||||
}
|
||||
last = i;
|
||||
|
||||
/* Determine how many rows would wrap with either one or two spaces. */
|
||||
columns = get_columns();
|
||||
wrap_one = 0;
|
||||
wrap_two = 0;
|
||||
c = &cells[last];
|
||||
util_list_iterate(items, p) {
|
||||
val = value_cb(p->ptr, c->id, c->heading, data);
|
||||
if (val) {
|
||||
len = strlen(val);
|
||||
free(val);
|
||||
} else
|
||||
len = 0;
|
||||
if (off_one + len >= columns)
|
||||
wrap_one++;
|
||||
if (off_two + len >= columns)
|
||||
wrap_two++;
|
||||
}
|
||||
|
||||
/* Use two spaces if the number of lines that would wrap is the same
|
||||
* for one and two spaces. */
|
||||
if (wrap_two <= wrap_one)
|
||||
return " ";
|
||||
|
||||
return " ";
|
||||
}
|
||||
|
||||
/* Get all values for an item. */
|
||||
static void cells_get_values(struct cell *cells, void *item,
|
||||
table_value_cb_t value_cb, void *data)
|
||||
{
|
||||
int i;
|
||||
struct cell *c;
|
||||
|
||||
for (i = 0; cells[i].heading; i++) {
|
||||
c = &cells[i];
|
||||
free(c->value);
|
||||
c->value = value_cb(item, c->id, c->heading, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Print all headings. */
|
||||
static void print_heading(struct cell *cells, const char *space, int indent)
|
||||
{
|
||||
int i, width;
|
||||
struct cell *c;
|
||||
|
||||
if (indent > 0)
|
||||
printf("%*s", indent, "");
|
||||
for (i = 0; cells[i].heading; i++) {
|
||||
c = &cells[i];
|
||||
|
||||
/* Don't print spaces in last cell. */
|
||||
if (!cells[i + 1].heading)
|
||||
width = 0;
|
||||
else if (c->align == align_left)
|
||||
width = -c->width;
|
||||
else
|
||||
width = c->width;
|
||||
|
||||
printf("%s%*s", i > 0 ? space : "", width, c->heading);
|
||||
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Print all cells in a row in list format. */
|
||||
static void print_row(struct cell *cells, const char *space, int indent,
|
||||
int wrap)
|
||||
{
|
||||
int i, width, columns, offset, slen;
|
||||
struct cell *c;
|
||||
|
||||
columns = get_columns();
|
||||
slen = strlen(space);
|
||||
offset = indent;
|
||||
|
||||
if (indent > 0)
|
||||
printf("%*s", indent, "");
|
||||
|
||||
for (i = 0; cells[i].heading; i++) {
|
||||
c = &cells[i];
|
||||
|
||||
/* Don't print spaces in last cell. */
|
||||
if (!cells[i + 1].heading)
|
||||
width = 0;
|
||||
else if (c->align == align_left)
|
||||
width = -c->width;
|
||||
else
|
||||
width = c->width;
|
||||
|
||||
if (!wrap)
|
||||
goto do_print;
|
||||
|
||||
offset += (i > 0 ? slen : 0);
|
||||
if (c->value)
|
||||
offset += MAX((size_t) abs(width), strlen(c->value));
|
||||
else
|
||||
offset += abs(width);
|
||||
|
||||
if (offset >= columns && i > 0) {
|
||||
/* Printing this cell would wrap the line - start on
|
||||
* the next line, indented to the second column. */
|
||||
offset = indent + cells[0].width;
|
||||
printf("\n%*s", offset, "");
|
||||
if (c->value) {
|
||||
offset += MAX((size_t) abs(width),
|
||||
strlen(c->value));
|
||||
} else
|
||||
offset += abs(width);
|
||||
}
|
||||
|
||||
do_print:
|
||||
printf("%s%*s", i > 0 ? space : "", width,
|
||||
c->value ? c->value : "");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Print all cells in a row in pairs format. */
|
||||
static void print_row_pairs(struct cell *cells)
|
||||
{
|
||||
int i;
|
||||
struct cell *c;
|
||||
char *val;
|
||||
|
||||
for (i = 0; cells[i].heading; i++) {
|
||||
c = &cells[i];
|
||||
val = quote_str(c->value ? c->value : "", 1);
|
||||
printf("%s%s=%s", i > 0 ? " " : "", c->heading, val);
|
||||
free(val);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Print a table. Either in list form or in pairs form (if @pairs is set).
|
||||
* In list form, print a heading if @heading is set. Show data from items
|
||||
* in ptrlist @items. Specify column names of columns to be printed in
|
||||
* @names. If @wrap is set, wrap overlong lines. , */
|
||||
exit_code_t table_print(struct column *columns, table_value_cb_t get_value_cb,
|
||||
void *data, struct util_list *items,
|
||||
struct util_list *names, int heading, int pairs,
|
||||
int indent, int wrap)
|
||||
{
|
||||
struct cell *cells;
|
||||
struct ptrlist_node *p;
|
||||
const char *space = " ";
|
||||
|
||||
/* Initialize cells array. */
|
||||
if (!names || util_list_is_empty(names))
|
||||
cells = cells_get_default(columns);
|
||||
else {
|
||||
cells = cells_get(columns, names);
|
||||
if (!cells)
|
||||
return EXIT_UNKNOWN_COLUMN;
|
||||
}
|
||||
|
||||
if (!pairs) {
|
||||
cells_get_width(cells, items, get_value_cb, data);
|
||||
if (wrap) {
|
||||
space = cells_get_space(cells, items, get_value_cb,
|
||||
data, indent);
|
||||
} else
|
||||
space = " ";
|
||||
if (heading)
|
||||
print_heading(cells, space, indent);
|
||||
}
|
||||
|
||||
/* Print rows. */
|
||||
util_list_iterate(items, p) {
|
||||
cells_get_values(cells, p->ptr, get_value_cb, data);
|
||||
if (pairs)
|
||||
print_row_pairs(cells);
|
||||
else
|
||||
print_row(cells, space, indent, wrap);
|
||||
}
|
||||
|
||||
cells_free(cells);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
exit_code_t table_check_columns(struct column *columns, struct util_list *names)
|
||||
{
|
||||
struct cell *cells;
|
||||
|
||||
if (!names || util_list_is_empty(names))
|
||||
return EXIT_OK;
|
||||
|
||||
cells = cells_get(columns, names);
|
||||
if (!cells)
|
||||
return EXIT_UNKNOWN_COLUMN;
|
||||
|
||||
cells_free(cells);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
enum {
|
||||
column_name,
|
||||
column_desc,
|
||||
};
|
||||
|
||||
static struct column *columns_table = COLUMN_ARRAY(
|
||||
COLUMN("COLUMN", align_left, column_name, 1, ""),
|
||||
COLUMN("DESCRIPTION", align_left, column_desc, 1, "")
|
||||
);
|
||||
|
||||
static char *columns_table_get_value(void *item, int id, const char *heading,
|
||||
void *data)
|
||||
{
|
||||
struct column *c = item;
|
||||
|
||||
switch (id) {
|
||||
case column_name:
|
||||
return misc_strdup(c->name);
|
||||
case column_desc:
|
||||
return misc_strdup(c->desc);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Print a table listing available columns and their description. */
|
||||
void table_print_columns(struct column *columns, struct util_list *names,
|
||||
int heading, int pairs)
|
||||
{
|
||||
int i;
|
||||
struct util_list *items;
|
||||
|
||||
items = ptrlist_new();
|
||||
for (i = 0; columns[i].name; i++)
|
||||
ptrlist_add(items, &columns[i]);
|
||||
table_print(columns_table, columns_table_get_value, NULL, items, names,
|
||||
heading, pairs, 0, 0);
|
||||
ptrlist_free(items, 0);
|
||||
}
|
||||
|
||||
/* Change the default state of column with @id in table @columns to @def. */
|
||||
void table_set_default(struct column *columns, int id, int def)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; columns[i].name; i++) {
|
||||
if (columns[i].id == id) {
|
||||
columns[i].def = def;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user