]> mj.ucw.cz Git - libucw.git/commitdiff
tableprinter: now uses struct table_col_info * for column ordering
authorRobert Kessl <kesslr@centrum.cz>
Fri, 27 Jun 2014 12:20:35 +0000 (14:20 +0200)
committerRobert Kessl <kesslr@centrum.cz>
Fri, 27 Jun 2014 12:20:35 +0000 (14:20 +0200)
ucw/Makefile
ucw/table-test-2.c [new file with mode: 0644]
ucw/table-test-2.t [new file with mode: 0644]
ucw/table-test.c
ucw/table-types.c [new file with mode: 0644]
ucw/table-types.h [new file with mode: 0644]
ucw/table.c
ucw/table.h

index e45a339c752f28f69eb600208302ca17578ba851..71e66311e476bc8efc1d5b1ed21550b3fec61142 100644 (file)
@@ -38,7 +38,7 @@ LIBUCW_MODS= \
        daemon daemon-ctrl \
        signames \
        opt opt-help opt-conf \
-       table
+       table table-types
 
 LIBUCW_MAIN_INCLUDES= \
        lib.h log.h tbf.h threads.h time.h \
@@ -69,7 +69,7 @@ LIBUCW_MAIN_INCLUDES= \
        signames.h \
        sighandler.h \
        opt.h \
-       table.h
+       table.h table-types.h
 
 ifdef CONFIG_UCW_THREADS
 # Some modules require threading
@@ -133,6 +133,7 @@ $(o)/ucw/ipaccess-test: $(o)/ucw/ipaccess-test.o $(LIBUCW)
 $(o)/ucw/trie-test: $(o)/ucw/trie-test.o $(LIBUCW)
 $(o)/ucw/opt-test: $(o)/ucw/opt-test.o $(LIBUCW)
 $(o)/ucw/table-test: $(o)/ucw/table-test.o $(LIBUCW)
+$(o)/ucw/table-test-2: $(o)/ucw/table-test-2.o $(LIBUCW)
 $(o)/ucw/table-test-align: $(o)/ucw/table-test-align.o $(LIBUCW)
 
 TESTS+=$(addprefix $(o)/ucw/,regex.test unicode.test hash-test.test mempool.test stkstring.test \
@@ -142,7 +143,7 @@ TESTS+=$(addprefix $(o)/ucw/,regex.test unicode.test hash-test.test mempool.test
     fb-mem.test fb-buffer.test fb-mmap.test fb-multi.test fb-null.test \
     redblack-test.test url.test strtonum-test.test \
     gary.test time.test crc.test signames.test md5.test bitops.test opt.test \
-    table.test table-test.test table-test-align.test)
+    table.test table-test.test table-test-2.test table-test-align.test)
 
 $(o)/ucw/varint.test: $(o)/ucw/varint-t
 $(o)/ucw/regex.test: $(o)/ucw/regex-t
@@ -176,6 +177,7 @@ $(o)/ucw/md5.test: $(o)/ucw/md5-t
 $(o)/ucw/opt.test: $(o)/ucw/opt-test
 $(o)/ucw/table.test: $(o)/ucw/table-t
 $(o)/ucw/table-test.test: $(o)/ucw/table-test
+$(o)/ucw/table-test-2.test: $(o)/ucw/table-test-2
 $(o)/ucw/table-test-align.test: $(o)/ucw/table-test-align
 
 ifdef CONFIG_UCW_THREADS
diff --git a/ucw/table-test-2.c b/ucw/table-test-2.c
new file mode 100644 (file)
index 0000000..49fce1d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *     Unit tests of table printer
+ *
+ *     (c) 2014 Robert Kessl <robert.kessl@economia.cz>
+ */
+
+#include <ucw/lib.h>
+#include <ucw/table.h>
+#include <ucw/table-types.h>
+#include <ucw/opt.h>
+#include <stdio.h>
+
+enum test_table_cols {
+  TEST_COL0_SIZE, TEST_COL1_TS
+};
+
+static struct table test_tbl = {
+  TBL_COLUMNS {
+    [TEST_COL0_SIZE] = TBL_COL_SIZE_FMT("size", 10, UNIT_BYTE),
+    [TEST_COL1_TS] = TBL_COL_TIMESTAMP("ts", 20),
+    TBL_COL_END
+  },
+  TBL_OUTPUT_HUMAN_READABLE,
+};
+
+static void do_test(void)
+{
+  struct fastbuf *out;
+  out = bfdopen_shared(1, 4096);
+  table_init(&test_tbl);
+  table_start(&test_tbl, out);
+
+  u64 test_time = 1403685533;
+  s64 test_size = 4LU*(1024LU * 1024LU * 1024LU);
+
+  table_col_size(&test_tbl, TEST_COL0_SIZE, test_size);
+  table_col_timestamp(&test_tbl, TEST_COL1_TS, test_time);
+  table_end_row(&test_tbl);
+
+  test_tbl.column_order[TEST_COL0_SIZE].output_type = UNIT_KILOBYTE;
+  table_col_size(&test_tbl, TEST_COL0_SIZE, test_size);
+  table_col_timestamp(&test_tbl, TEST_COL1_TS, test_time);
+  table_end_row(&test_tbl);
+
+  test_tbl.column_order[TEST_COL0_SIZE].output_type = UNIT_MEGABYTE;
+  table_col_size(&test_tbl, TEST_COL0_SIZE, test_size);
+  table_col_timestamp(&test_tbl, TEST_COL1_TS, test_time);
+  table_end_row(&test_tbl);
+
+  test_tbl.column_order[TEST_COL0_SIZE].output_type = UNIT_GIGABYTE;
+  test_tbl.column_order[TEST_COL1_TS].output_type = TIMESTAMP_DATETIME;
+  table_col_size(&test_tbl, TEST_COL0_SIZE, test_size);
+  table_col_timestamp(&test_tbl, TEST_COL1_TS, test_time);
+  table_end_row(&test_tbl);
+
+  table_end(&test_tbl);
+  table_cleanup(&test_tbl);
+
+  bclose(out);
+}
+
+int main(int argc UNUSED, char **argv UNUSED)
+{
+  do_test();
+  return 0;
+}
+
diff --git a/ucw/table-test-2.t b/ucw/table-test-2.t
new file mode 100644 (file)
index 0000000..1b933c9
--- /dev/null
@@ -0,0 +1,8 @@
+Run: ../obj/ucw/table-test-2
+Out <<EOF
+      size                   ts
+4294967296           1403685533
+ 4194304KB           1403685533
+    4096MB           1403685533
+       4GB  2014-06-25 08:38:53
+EOF
index 41e7884942f4145d0f62b33298d39598c052b85a..9ef4b50db0c2b698a0544e00499d31e810586ad6 100644 (file)
@@ -13,7 +13,7 @@ enum test_table_cols {
   test_col0_str, test_col1_int, test_col2_uint, test_col3_bool, test_col4_double
 };
 
-static uint test_column_order[] = { test_col3_bool, test_col4_double, test_col2_uint,test_col1_int, test_col0_str };
+static struct table_col_info test_column_order[] = { TBL_COL(test_col3_bool), TBL_COL(test_col4_double), TBL_COL(test_col2_uint), TBL_COL(test_col1_int), TBL_COL(test_col0_str) };
 
 static struct table test_tbl = {
   TBL_COLUMNS {
diff --git a/ucw/table-types.c b/ucw/table-types.c
new file mode 100644 (file)
index 0000000..a4be42d
--- /dev/null
@@ -0,0 +1,69 @@
+#include <ucw/lib.h>
+#include <ucw/config.h>
+#include <ucw/table-types.h>
+#include <ucw/fastbuf.h>
+#include <ucw/config.h>
+#include <ucw/table.h>
+#include <time.h>
+#include <stdio.h>
+
+void table_col_name(struct table *tbl, const char *col_name, u64 val)
+{
+}
+
+void table_col_size(struct table *tbl, int col, u64 val)
+{
+  ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col);
+  ASSERT(tbl->columns[col].type == COL_TYPE_ANY || COL_TYPE_SIZE == tbl->columns[col].type);
+
+  tbl->last_printed_col = col;
+  tbl->row_printing_started = 1;
+
+  static u64 unit_div[] = {
+    [UNIT_BYTE] = (u64) 1,
+    [UNIT_KILOBYTE] = (u64) 1024LU,
+    [UNIT_MEGABYTE] = (u64) (1024LU * 1024LU),
+    [UNIT_GIGABYTE] = (u64) (1024LU * 1024LU * 1024LU),
+    [UNIT_TERABYTE] = (u64) (1024LU * 1024LU * 1024LU * 1024LU)
+  };
+
+  static const char *unit_suffix[] = {
+    [UNIT_BYTE] = "",
+    [UNIT_KILOBYTE] = "KB",
+    [UNIT_MEGABYTE] = "MB",
+    [UNIT_GIGABYTE] = "GB",
+    [UNIT_TERABYTE] = "TB"
+  };
+
+  // FIXME: do some rounding?
+  val = val / unit_div[tbl->column_order[col].output_type];
+
+  tbl->col_str_ptrs[col] = mp_printf(tbl->pool, "%lu%s", val, unit_suffix[tbl->column_order[col].output_type]);
+}
+
+#define FORMAT_TIME_SIZE 20    // Minimum buffer size
+
+void table_col_timestamp(struct table *tbl, int col, u64 val)
+{
+  ASSERT_MSG(col < tbl->column_count && col >= 0, "Table column %d does not exist.", col);
+  ASSERT(tbl->columns[col].type == COL_TYPE_ANY || COL_TYPE_TIMESTAMP == tbl->columns[col].type);
+  //ASSERT(fmt != NULL);
+
+  char formatted_time_buf[FORMAT_TIME_SIZE];
+
+  time_t tmp_time = (time_t)val;
+  struct tm t = *gmtime(&tmp_time);
+
+  switch (tbl->column_order[col].output_type) {
+  case TIMESTAMP_EPOCH:
+    sprintf(formatted_time_buf, "%u", (uint) val);
+    break;
+  case TIMESTAMP_DATETIME:
+    strftime(formatted_time_buf, FORMAT_TIME_SIZE, "%F %T", &t);
+  default:
+    break;
+  }
+
+  tbl->col_str_ptrs[col] = mp_printf(tbl->pool, "%s", formatted_time_buf);
+}
+
diff --git a/ucw/table-types.h b/ucw/table-types.h
new file mode 100644 (file)
index 0000000..3ef4375
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _UCW_TABLE_TYPES_H
+#define _UCW_TABLE_TYPES_H
+
+#include <ucw/table.h>
+
+enum size_units {
+  UNIT_BYTE,
+  UNIT_KILOBYTE,
+  UNIT_MEGABYTE,
+  UNIT_GIGABYTE,
+  UNIT_TERABYTE,
+  UNIT_AUTO
+};
+
+enum timestamp_format {
+  TIMESTAMP_EPOCH,
+  TIMESTAMP_DATETIME
+};
+
+
+#define COL_TYPE_SIZE       COL_TYPE_CUSTOM
+#define COL_TYPE_TIMESTAMP  (COL_TYPE_CUSTOM+1)
+
+#define TBL_COL_SIZE(_name, _width)           { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE }
+#define TBL_COL_TIMESTAMP(_name, _width)      { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP }
+
+#define TBL_COL_SIZE_FMT(_name, _width, _units)         { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE }
+#define TBL_COL_TIMESTAMP_FMT(_name, _width, _fmt)      { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP }
+
+/*
+  union {
+    enum size_units units;
+    enum timestamp_format ts_fmt;
+  };
+*/
+/*
+#define TBL_COL_SIZE(_name, _width)           { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE }
+#define TBL_COL_TIMESTAMP(_name, _width)      { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP }
+
+#define TBL_COL_SIZE_FMT(_name, _width, _units)         { .name = _name, .width = _width, .fmt = "%llu", .type = COL_TYPE_SIZE }
+#define TBL_COL_TIMESTAMP_FMT(_name, _width, _fmt)      { .name = _name, .width = _width, .fmt = "%lld", .type = COL_TYPE_TIMESTAMP }
+
+#define TABLE_COL_PROTO(_name_, _type_) void table_col_##_name_(struct table *tbl, int col, _type_ val);\
+  void table_col_##_name_##_name(struct table *tbl, const char *col_name, _type_ val);\
+  void table_col_##_name_##_fmt(struct table *tbl, int col, _type_ val) FORMAT_CHECK(printf, 3, 0);
+//TABLE_COL_PROTO(size, u64);
+//TABLE_COL_PROTO(timestamp, u64);
+#undef TABLE_COL_PROTO
+*/
+
+void table_col_size(struct table *tbl, int col, u64 val);
+void table_col_timestamp(struct table *tbl, int col, u64 val);
+
+//TABLE_COL(size, u64, COL_TYPE_SIZE)
+//TABLE_COL_STR(size, u64, COL_TYPE_SIZE)
+
+//TABLE_COL(timestamp, u64, COL_TYPE_TIMESTAMP)
+//TABLE_COL_STR(timestamp, u64, COL_TYPE_TIMESTAMP)
+
+
+#endif
index cba1c6da22203deaefdc5b0cbe2d6641c077049e..ff6d6250f9a16644d409773b8af111f792209b01 100644 (file)
@@ -27,7 +27,6 @@ void table_init(struct table *tbl)
     ASSERT(tbl->columns[col_count].name != NULL);
     ASSERT(tbl->columns[col_count].type == COL_TYPE_ANY || tbl->columns[col_count].fmt != NULL);
     ASSERT(tbl->columns[col_count].width != 0);
-    ASSERT(tbl->columns[col_count].type < COL_TYPE_LAST);
     col_count++;
   }
   tbl->pool = mp_new(4096);
@@ -123,15 +122,18 @@ void table_set_col_order(struct table *tbl, int *col_order, int cols_to_output)
     ASSERT_MSG(col_order[i] >= 0 && col_order[i] < tbl->column_count, "Column %d does not exist (column number should be between 0 and %d)", col_order[i], tbl->column_count - 1);
   }
 
-  tbl->column_order = col_order;
   tbl->cols_to_output = cols_to_output;
+  tbl->column_order = mp_alloc_zero(tbl->pool, sizeof(struct table_col_info) * cols_to_output);
+  for(int i = 0; i < cols_to_output; i++) {
+    tbl->column_order[i].idx = col_order[i];
+  }
 }
 
 
 bool table_col_is_printed(struct table *tbl, uint col_idx)
 {
   for(uint i = 0; i < tbl->cols_to_output; i++) {
-    if(tbl->column_order[i] == col_idx) return 1;
+    if(tbl->column_order[i].idx == col_idx) return 1;
   }
 
   return 0;
@@ -144,9 +146,12 @@ bool table_col_is_printed(struct table *tbl, uint col_idx)
 const char * table_set_col_order_by_name(struct table *tbl, const char *col_order_str)
 {
   if(col_order_str[0] == '*') {
-    tbl->column_order = mp_alloc(tbl->pool, sizeof(int) * tbl->column_count);
+    tbl->column_order = mp_alloc(tbl->pool, sizeof(struct table_col_info) * tbl->column_count);
     tbl->cols_to_output = tbl->column_count;
-    for(uint i = 0; i < tbl->cols_to_output; i++) tbl->column_order[i] = i;
+    for(uint i = 0; i < tbl->cols_to_output; i++) {
+      tbl->column_order[i].idx = i;
+      tbl->column_order[i].output_type = 0;
+    }
 
     return NULL;
   }
@@ -166,7 +171,7 @@ const char * table_set_col_order_by_name(struct table *tbl, const char *col_orde
     }
   }
 
-  int *col_order_int = mp_alloc_zero(tbl->pool, sizeof(int) * col_count);
+  int *col_order_int = alloca(sizeof(int) * col_count); //mp_alloc_zero(tbl->pool, sizeof(int) * col_count);
   int curr_col_order_int = 0;
   const char *name_start = tmp_col_order;
   while(name_start) {
@@ -184,8 +189,9 @@ const char * table_set_col_order_by_name(struct table *tbl, const char *col_orde
     name_start = next;
   }
 
-  tbl->column_order = col_order_int;
-  tbl->cols_to_output = curr_col_order_int;
+  //tbl->column_order = col_order_int;
+  //tbl->cols_to_output = curr_col_order_int;
+  table_set_col_order(tbl, col_order_int, curr_col_order_int);
   return NULL;
 }
 
@@ -436,7 +442,7 @@ const char *table_set_gary_options(struct table *tbl, char **gary_table_opts)
 static void table_row_human_readable(struct table *tbl)
 {
   for(uint i = 0; i < tbl->cols_to_output; i++) {
-    int col_idx = tbl->column_order[i];
+    int col_idx = tbl->column_order[i].idx;
     if(i) {
       bputs(tbl->out, tbl->col_delimiter);
     }
@@ -450,7 +456,7 @@ static void table_row_human_readable(struct table *tbl)
 static void table_write_header(struct table *tbl)
 {
   for(uint i = 0; i < tbl->cols_to_output; i++) {
-    int col_idx = tbl->column_order[i];
+    int col_idx = tbl->column_order[i].idx;
     if(i) {
       bputs(tbl->out, tbl->col_delimiter);
     }
@@ -486,7 +492,7 @@ struct table_formatter table_fmt_human_readable = {
 static void table_row_machine_readable(struct table *tbl)
 {
   for(uint i = 0; i < tbl->cols_to_output; i++) {
-    int col_idx = tbl->column_order[i];
+    int col_idx = tbl->column_order[i].idx;
     if(i) {
       bputs(tbl->out, tbl->col_delimiter);
     }
@@ -506,10 +512,10 @@ static void table_start_machine_readable(struct table *tbl)
   }
 
   if(tbl->print_header != 0) {
-    uint col_idx = tbl->column_order[0];
+    uint col_idx = tbl->column_order[0].idx;
     bputs(tbl->out, tbl->columns[col_idx].name);
     for(uint i = 1; i < tbl->cols_to_output; i++) {
-      col_idx = tbl->column_order[i];
+      col_idx = tbl->column_order[i].idx;
       bputs(tbl->out, tbl->col_delimiter);
       bputs(tbl->out, tbl->columns[col_idx].name);
     }
@@ -528,7 +534,7 @@ struct table_formatter table_fmt_machine_readable = {
 static void table_row_blockline_output(struct table *tbl)
 {
   for(uint i = 0; i < tbl->cols_to_output; i++) {
-    int col_idx = tbl->column_order[i];
+    int col_idx = tbl->column_order[i].idx;
     bprintf(tbl->out, "%s: %s\n", tbl->columns[col_idx].name, tbl->col_str_ptrs[col_idx]);
   }
   bputc(tbl->out, '\n');
@@ -562,7 +568,7 @@ enum test_table_cols {
   test_col0_str, test_col1_int, test_col2_uint, test_col3_bool, test_col4_double
 };
 
-static uint test_column_order[] = {test_col3_bool, test_col4_double, test_col2_uint,test_col1_int, test_col0_str};
+static struct table_col_info test_column_order[] = { TBL_COL(test_col3_bool), TBL_COL(test_col4_double), TBL_COL(test_col2_uint), TBL_COL(test_col1_int), TBL_COL(test_col0_str) };
 
 static struct table test_tbl = {
   TBL_COLUMNS {
@@ -659,7 +665,7 @@ enum test_any_table_cols {
   test_any_col0_int, test_any_col1_any
 };
 
-static uint test_any_column_order[] = { test_any_col0_int, test_any_col1_any };
+static struct table_col_info test_any_column_order[] = { TBL_COL(test_any_col0_int), TBL_COL(test_any_col1_any) };
 
 static struct table test_any_tbl = {
   TBL_COLUMNS {
index 06da548106b8f585a55e43483699dd8d0a05679d..a43a04763dac2a6bdaea894e32eab3886d83b9be 100644 (file)
@@ -88,6 +88,9 @@ enum column_type {
   COL_TYPE_LAST
 };
 
+#define COL_TYPE_UCW           0x100
+#define COL_TYPE_CUSTOM        0x1000
+
 /** Justify cell contents to the left. **/
 #define CELL_ALIGN_LEFT     (1U << 31)
 
@@ -108,6 +111,11 @@ struct table_column {
   enum column_type type;       // [*] Type of the cells in the column
 };
 
+struct table_col_info {
+  uint idx;
+  uint output_type;
+};
+
 /**
  * Definition of a table. Contains column definitions, per-table settings
  * and internal data. Please use only fields marked with `[*]`.
@@ -122,7 +130,7 @@ struct table {
 
   char **col_str_ptrs;                 // Values of cells in the current row (allocated from the pool)
 
-  uint *column_order;                  // [*] Order of the columns in the print-out of the table
+  struct table_col_info *column_order;  // [*] Order of the columns in the print-out of the table
   uint cols_to_output;                 // [*] Number of columns that are printed
   const char *col_delimiter;           // [*] Delimiter that is placed between columns
   const char *append_delimiter;                // [*] Separator of multiple values in a single cell (see table_append_...())
@@ -181,9 +189,10 @@ struct table {
 #define TBL_COL_END { .name = 0, .width = 0, .fmt = 0, .type = COL_TYPE_LAST }
 
 #define TBL_COLUMNS  .columns = (struct table_column [])
-#define TBL_COL_ORDER(order) .column_order = (int *) order, .cols_to_output = ARRAY_SIZE(order)
+#define TBL_COL_ORDER(order) .column_order = (struct table_col_info *) order, .cols_to_output = ARRAY_SIZE(order)
 #define TBL_COL_DELIMITER(_delimiter_) .col_delimiter = _delimiter_
 #define TBL_APPEND_DELIMITER(_delimiter_) .append_delimiter = _delimiter_
+#define TBL_COL(_idx) { .idx = _idx, .output_type = 0 }
 
 #define TBL_OUTPUT_HUMAN_READABLE     .formatter = &table_fmt_human_readable
 #define TBL_OUTPUT_BLOCKLINE          .formatter = &table_fmt_blockline