Logo Search packages:      
Sourcecode: s390-tools version File versions  Download package

table.c

/*
 * hyptop - Show hypervisor performance data on System z
 *
 * Table module: Provide line mode and curses base table
 *
 * Copyright IBM Corp. 2010
 * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
 */

#include <stdlib.h>
#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "table.h"
#include "hyptop.h"
#include "helper.h"

#define L_ROWS_EXTRA                2 /* head + last */

#define table_col_iterate(t, col, i) \
      for (i = 0, col = t->col_vec[0]; col != NULL;  col = t->col_vec[++i])

/*
 * Is row marked?
 */
static int l_row_is_marked(struct table *t, struct table_row *row)
{
      struct table_mark_key *key;

      list_iterate(key, &t->mark_key_list, list) {
            if (strcmp(row->entries[0].str, key->str) == 0)
                  return 1;
      }
      return 0;
}

/*
 * Add mark key to table
 */
static void l_mark_key_add(struct table *t, char *str)
{
      struct table_mark_key *key;

      key = ht_zalloc(sizeof(*key));
      strncpy(key->str, str, sizeof(key->str));
      list_add_end(&key->list, &t->mark_key_list);
      t->mark_keys_cnt++;
}

/*
 * Remove mark key from table
 */
static void l_mark_key_remove(struct table *t, char *str)
{
      struct table_mark_key *key;

      list_iterate(key, &t->mark_key_list, list) {
            if (strcmp(str, key->str) == 0) {
                  list_del(&key->list);
                  ht_free(key);
                  t->mark_keys_cnt--;
                  return;
            }
      }
}

/*
 * Delete all mark keys from table
 */
void table_row_mark_del_all(struct table *t)
{
      struct table_mark_key *key, *tmp;
      struct table_row *row;

      list_iterate(row, &t->row_list, list)
            row->marked = 0;
      list_iterate_safe(key, &t->mark_key_list, list, tmp) {
            list_del(&key->list);
            ht_free(key);
      }
      t->mark_keys_cnt = 0;
}

/*
 * Toggle mark for "row"
 */
void table_row_mark_toggle(struct table *t, struct table_row *row)
{
      if (row->marked) {
            l_mark_key_remove(t, row->entries[0].str);
            row->marked = 0;
            t->row_cnt_marked--;
            if (t->row_cnt_marked == 0)
                  t->mode_hide_unmarked = 0;
      } else {
            l_mark_key_add(t, row->entries[0].str);
            row->marked = 1;
            t->row_cnt_marked++;
      }
}

/*
 * Toggle mark by key
 */
void table_row_mark_toggle_by_key(struct table *t, const char *str)
{
      struct table_row *row;

      list_iterate(row, &t->row_list, list) {
            if (strcmp(str, row->entries[0].str) == 0)
                  table_row_mark_toggle(t, row);
      }
}

/*
 * Is column selected?
 */
static int l_col_selected(struct table *t, struct table_col *col)
{
      return t->col_selected == col;
}

/*
 * Get number of rows for table
 */
static int l_row_cnt(struct table *t)
{
      return t->mode_hide_unmarked ? t->row_cnt_marked : t->row_cnt;
}

/*
 * Get number of data rows that we can display on screen
 */
static int l_row_cnt_displ(struct table *t)
{
      return g.c.row_cnt - t->row_cnt_extra;
}

/*
 * Alloc a new row for table
 */
struct table_row *table_row_alloc(struct table *t)
{
      struct table_row *table_row;

      table_row = ht_zalloc(sizeof(*table_row));
      table_row->entries = ht_zalloc(sizeof(*table_row->entries) *
                                t->col_cnt);
      list_init(&table_row->list);
      return table_row;
}

/*
 * Free table row
 */
static void table_row_free(struct table_row *table_row)
{
      ht_free(table_row->entries);
      ht_free(table_row);
}

/*
 * Allocate and initialize a new table
 */
struct table *table_new(int extra_rows, int sorted, int first_bold,
                  int with_units)
{
      struct table *t = ht_zalloc(sizeof(*t));

      list_init(&t->row_list);
      list_init(&t->mark_key_list);
      t->row_cnt_marked = 0;
      if (with_units)
            t->row_cnt_extra = extra_rows + L_ROWS_EXTRA + 1;
      else
            t->row_cnt_extra = extra_rows + L_ROWS_EXTRA;
      t->attr_with_units = with_units;
      t->attr_sorted_table = sorted;
      t->attr_first_bold = first_bold;

      return t;
}

/*
 * Initialize headline for one column
 */
static void l_col_headline_init(struct table *t, struct table_col *col)
{
      char *ptr;

      strcpy(col->p->head_first, col->head);
      ptr = strchr(col->p->head_first, tolower(col->hotkey));
      assert(ptr != NULL);
      *ptr = 0;
      col->p->head_char[0] = col->hotkey;
      strcpy(col->p->head_last, ++ptr);
      if (!t->attr_sorted_table) {
            ht_str_to_upper(col->p->head_first);
            ht_str_to_upper(col->p->head_last);
            col->p->head_char[0] = toupper(col->p->head_char[0]);
      }
}

/*
 * Initialize the max width values for a column
 */
static void l_col_max_width_init(struct table *t, struct table_col *col)
{
      /* Units are displayed with brackets, therefore (+2) */
      if (t->attr_with_units)
            col->p->max_width = MAX(strlen(col->head),
                              strlen(col->unit->str) + 2);
      else
            col->p->max_width = strlen(col->head);
}

/*
 * Add a new column to table
 */
void table_col_add(struct table *t, struct table_col *col)
{
      col->p = ht_zalloc(sizeof(*col->p));
      col->p->col_nr = t->col_cnt;
      col->p->enabled = 1;
      t->col_cnt++;
      t->col_vec = ht_realloc(t->col_vec, sizeof(void *) *
                           (t->col_cnt + 1));
      t->col_vec[t->col_cnt - 1] = col;
      t->col_vec[t->col_cnt] = NULL;
      if (!t->col_selected && t->attr_sorted_table)
            t->col_selected = col;
      if (t->row_last)
            table_row_free(t->row_last);
      t->row_last = table_row_alloc(t);
      l_col_headline_init(t, col);
      l_col_max_width_init(t, col);
}

/*
 * Initialize last row
 */
static void l_row_last_init(struct table *t)
{
      memset(t->row_last->entries, 0,
             t->col_cnt * sizeof(struct table_entry));
}

/*
 * Delete all rows of a table
 */
void table_row_del_all(struct table *t)
{
      struct table_row *row, *tmp;

      list_iterate_safe(row, &t->row_list, list, tmp) {
            list_del(&row->list);
            table_row_free(row);
      }
      l_row_last_init(t);
      t->row_cnt_marked = 0;
      t->ready = 0;
      t->row_cnt = 0;
}

/*
 * Reset table
 */
void table_reset(struct table *t)
{
      table_row_mark_del_all(t);
      table_row_del_all(t);
      t->mode_sort_inverse = 0;
      t->mode_select = 0;
}

/*
 * Return true, if "e1" is less than "e2"
 */
static int l_entry_less_than(enum table_col_type type, struct table_entry *e1,
                       struct table_entry *e2)
{
      switch (type) {
      case TABLE_COL_TYPE_U64:
            return (e1->d.u64.v1 < e2->d.u64.v1);
      case TABLE_COL_TYPE_S64:
            return (e1->d.s64.v1 < e2->d.s64.v1);
      case TABLE_COL_TYPE_STR:
            return (strcmp(e1->str, e2->str) > 0);
      }
      return 0; /* Keep gcc quite */
}

/*
 * Return true, if "row1" is less than "row2"
 */
static int l_row_less_than(struct table *t, struct table_row *row1,
                     struct table_row *row2)
{
      struct table_col *col = t->col_selected;
      struct table_entry *e1 = &row1->entries[col->p->col_nr];
      struct table_entry *e2 = &row2->entries[col->p->col_nr];

      if ((t->mode_sort_inverse && !col->p->rsort) ||
          (!t->mode_sort_inverse && col->p->rsort))
            return !l_entry_less_than(col->type, e1, e2);
      else
            return l_entry_less_than(col->type, e1, e2);
}

/*
 * Calculate: e1 = e1 + e2
 */
static void l_entry_sum(enum table_col_type type, struct table_entry *e1,
                  struct table_entry *e2)
{
      switch (type) {
      case TABLE_COL_TYPE_U64:
            e1->d.u64.v1 += e2->d.u64.v1;
            return;
      case TABLE_COL_TYPE_S64:
            e1->d.s64.v1 += e2->d.s64.v1;
            return;
      default:
            assert(0);
            return;
      }
}

/*
 * Calculate: e1 = MAX(e1, e2)
 */
static void l_entry_max(enum table_col_type type, struct table_entry *e1,
                  struct table_entry *e2)
{
      switch (type) {
      case TABLE_COL_TYPE_U64:
            e1->d.u64.v1 = MAX(e1->d.u64.v1, e2->d.u64.v1);
            return;
      case TABLE_COL_TYPE_S64:
            e1->d.s64.v1 = MAX(e1->d.s64.v1, e2->d.s64.v1);
            return;
      default:
            assert(0);
            return;
      }
}

/*
 * Aggregate "row" to "last row"
 */
static void l_row_last_agg(struct table *t, struct table_row *table_row)
{
      struct table_col *col;
      int col_nr;

      table_col_iterate(t, col, col_nr) {
            struct table_entry *e_last = &t->row_last->entries[col_nr];
            struct table_entry *e_new = &table_row->entries[col_nr];

            switch (col->agg) {
            case TABLE_COL_AGG_SUM:
                  l_entry_sum(col->type, e_last, e_new);
                  break;
            case TABLE_COL_AGG_MAX:
                  l_entry_max(col->type, e_last, e_new);
                  break;
            case TABLE_COL_AGG_NONE:
                  break;
            }
      }
}

/*
 * Format row: Invoke unit callback and adjust max width of column
 */
static void l_row_format(struct table *t, struct table_row *row)
{
      unsigned int len, col_nr;
      struct table_col *col;

      table_col_iterate(t, col, col_nr) {
            struct table_entry *e = &row->entries[col_nr];
            if (col->agg == TABLE_COL_AGG_NONE && row == t->row_last)
                  len = 0;
            else
                  len = col->unit->fn(col, e);
            assert(len < TABLE_STR_MAX);
            if (len > col->p->max_width)
                  col->p->max_width = len;
      }
}

/*
 * Calculate last row
 */
static void l_row_last_calc(struct table *t)
{
      struct table_row *row;

      l_row_last_init(t);
      list_iterate(row, &t->row_list, list) {
            if (t->mode_hide_unmarked && !row->marked)
                  continue;
            l_row_last_agg(t, row);
      }
      l_row_format(t, t->row_last);
}

/*
 * Finish table after all rows have been added
 */
void table_finish(struct table *t)
{
      l_row_last_calc(t);
      t->ready = 1;
}

/*
 * Add new row to table
 */
void table_row_add(struct table *t, struct table_row *row)
{
      struct table_row *tmp;

      l_row_format(t, row);

      if (list_is_empty(&t->row_list) || !t->attr_sorted_table) {
            list_add_end(&row->list, &t->row_list);
      } else {
            list_iterate(tmp, &t->row_list, list) {
                  if (l_row_less_than(t, tmp, row))
                        break;
            }
            list_add_end(&row->list, &tmp->list);
      }
      if (l_row_is_marked(t, row)) {
            row->marked = 1;
            t->row_cnt_marked++;
      }
      t->row_cnt++;
}

/*
 * Rebuild table: Reformat all rows and adjust max width values
 */
void table_rebuild(struct table *t)
{
      struct table_col *col;
      struct table_row *row;
      unsigned int i;

      table_col_iterate(t, col, i)
            l_col_max_width_init(t, col);
      list_iterate(row, &t->row_list, list)
            l_row_format(t, row);
      l_row_format(t, t->row_last);
}

/*
 * Sort table (TODO: Use better sorting algorithm)
 */
static void l_table_sort(struct table *t)
{
      struct table_row *row_min;
      struct table_row *row;
      struct table_row *tmp;
      struct list list;

      list_init(&list);

      /*
       * Sort row list into temp list
       */
      while (!list_is_empty(&t->row_list)) {
            row_min = NULL;

            list_iterate(row, &t->row_list, list) {
                  if (row_min == NULL)
                        row_min = row;
                  else if (l_row_less_than(t, row, row_min))
                        row_min = row;
            }
            list_del(&row_min->list);
            list_add(&row_min->list, &list);
      }
      /*
       * Copy temp list to original list
       */
      list_iterate_safe(row, &list, list, tmp) {
            list_del(&row->list);
            list_add_end(&row->list, &t->row_list);
      }
}

/*
 * Adjust table values for select mode (e.g. for window resize or scrolling)
 */
static void l_adjust_values_select_mode(struct table *t)
{
      int row_cnt_displ = l_row_cnt_displ(t);
      int row_cnt = l_row_cnt(t);

      /* We went out of range with row selection */
      if (t->row_nr_select >= row_cnt)
            t->row_nr_select = row_cnt - 1;

      /* Is selected row within visible area? */
      if (t->row_nr_select < t->row_nr_begin) {
            /* Selected row is above area: Scroll up */
            t->row_nr_begin = t->row_nr_select;
      } else if (t->row_nr_select - t->row_nr_begin >= row_cnt_displ) {
            /* Selected row is below area: Scroll down */
            t->row_nr_begin = MAX(t->row_nr_select - row_cnt_displ + 1, 0);
      }
}

/*
 * Adjust table values (e.g. for window resize or scrolling)
 */
static void l_adjust_values(struct table *t)
{
      int row_cnt_displ = l_row_cnt_displ(t);
      int row_cnt = l_row_cnt(t);

      if (t->mode_select)
            l_adjust_values_select_mode(t);
      /* If we do not use the whole screen, scroll up */
      if (row_cnt - t->row_nr_begin < row_cnt_displ)
            t->row_nr_begin = MAX(row_cnt - row_cnt_displ, 0);
}

/*
 * Number of rows to be scrolled for page scroll
 */
static int l_scroll_page_row_cnt(struct table *t)
{
      /* We have two rows overlap for scrolling pages */
      return l_row_cnt_displ(t) - 2;
}

/*
 * Scroll table down
 */
void table_scroll_down(struct table *t, enum table_scroll_unit scroll_unit)
{
      switch (scroll_unit) {
      case TABLE_SCROLL_LINE:
            t->row_nr_begin++;
            break;
      case TABLE_SCROLL_PAGE:
            t->row_nr_begin += l_scroll_page_row_cnt(t);
            break;
      case TABLE_SCROLL_LAST:
            t->row_nr_begin = t->row_cnt;
            break;
      }
}

/*
 * Scroll table up
 */
void table_scroll_up(struct table *t, enum table_scroll_unit scroll_unit)
{
      switch (scroll_unit) {
      case TABLE_SCROLL_LINE:
            t->row_nr_begin = MAX(t->row_nr_begin - 1, 0);
            break;
      case TABLE_SCROLL_PAGE:
            t->row_nr_begin =
                  MAX(t->row_nr_begin - l_scroll_page_row_cnt(t), 0);
            break;
      case TABLE_SCROLL_LAST:
            t->row_nr_begin = 0;
            break;
      }
}

/*
 * Return selected row
 */
static struct table_row *l_selected_row(struct table *t)
{
      struct table_row *row;
      int row_nr = 0;

      list_iterate(row, &t->row_list, list) {
            if (t->mode_hide_unmarked && !row->marked)
                  continue;
            if (row_nr == t->row_nr_select)
                  return row;
            row_nr++;
      }
      return NULL;
}

/*
 * Toggle mark for selected row
 */
static void l_row_select_mark_toggle(struct table *t)
{
      struct table_row *row;

      row = l_selected_row(t);
      table_row_mark_toggle(t, row);
      l_row_last_calc(t);
}

/*
 * Switch select mode off
 */
static void l_select_mode_off(struct table *t)
{
      t->mode_select = 0;
}

/*
 * Switch select mode on
 */
static void l_select_mode_on(struct table *t)
{
      t->mode_select = 1;
      t->row_nr_select = t->row_nr_begin;
}

/*
 * Get key for selected row
 */
void table_row_select_key_get(struct table *t, char str[TABLE_STR_MAX])
{
      struct table_row *row;

      row = l_selected_row(t);
      strncpy(str, row->entries[0].str, TABLE_STR_MAX);
}

/*
 * Select row one page down
 */
void table_row_select_down(struct table *t, enum table_scroll_unit scroll_unit)
{
      switch (scroll_unit) {
      case TABLE_SCROLL_LINE:
            t->row_nr_select++;
            break;
      case TABLE_SCROLL_PAGE:
            t->row_nr_select += g.c.row_cnt - t->row_cnt_extra;
            break;
      case TABLE_SCROLL_LAST:
            t->row_nr_select = t->row_cnt;
            break;
      }
}

/*
 * Select row one page up
 */
void table_row_select_up(struct table *t, enum table_scroll_unit scroll_unit)
{
      switch (scroll_unit) {
      case TABLE_SCROLL_LINE:
            t->row_nr_select = MAX(t->row_nr_select - 1, 0);
            break;
      case TABLE_SCROLL_PAGE:
            t->row_nr_select = MAX(t->row_nr_begin -
                               (g.c.row_cnt - t->row_cnt_extra), 0);
            break;
      case TABLE_SCROLL_LAST:
            t->row_nr_select = 0;
            break;
      }
}

/*
 * Toggle "hide unmarked" mode
 */
static int l_mode_hide_unmarked_toggle(struct table *t)
{
      if (t->row_cnt_marked == 0)
            return -ENODEV;
      t->mode_hide_unmarked = t->mode_hide_unmarked ? 0 : 1;
      t->row_nr_select = 0;
      l_row_last_calc(t);
      return 0;
}

/*
 * Is it possible to scroll down the table?
 */
static int l_can_scroll_down(struct table *t)
{
      int row_cnt = t->mode_hide_unmarked ? t->row_cnt_marked : t->row_cnt;
      int row_cnt_real = g.c.row_cnt - t->row_cnt_extra;

      return (row_cnt - t->row_nr_begin > row_cnt_real);
}

/*
 * Is it possible to scroll up the table?
 */
static int l_can_scroll_up(struct table *t)
{
      return (t->row_nr_begin > 0);
}

/*
 * Update the status field
 */
static void l_status_update(struct table *t)
{
      struct table_entry *e_status = &t->row_last->entries[0];

      if (g.o.batch_mode_specified)
            return;

      if (l_can_scroll_down(t) && l_can_scroll_up(t))
            strcpy(e_status->str, "|");
      else if (l_can_scroll_up(t))
            strcpy(e_status->str, "^");
      else if (l_can_scroll_down(t))
            strcpy(e_status->str, "V");
      else
            strcpy(e_status->str, "=");

      if (t->attr_sorted_table) {
            strcat(e_status->str, ":");
            if (t->mode_sort_inverse)
                  strcat(e_status->str, "^");
            else
                  strcat(e_status->str, "V");
      }
      strcat(e_status->str, ":");
      if (t->mode_select)
            strcat(e_status->str, "S");
      else
            strcat(e_status->str, "N");
}

/*
 * Print string with alignment
 */
static void l_str_print(struct table_col *col, const char *str)
{
      char unit[10];

      if (col->align == TABLE_COL_ALIGN_LEFT)
            sprintf(unit, "%%-%ds", col->p->max_width);
      else
            sprintf(unit, "%%%ds", col->p->max_width);
      hyptop_printf(unit, str);
}

/*
 * Print string for "col"
 */
static void l_col_print(struct table *t, struct table_col *col, const char *str)
{
      if (l_col_selected(t, col))
            ht_underline_on();
      if (col->p->col_nr == 0 && t->attr_first_bold)
            ht_bold_on();

      l_str_print(col, str);

      if (l_col_selected(t, col))
            ht_underline_off();
      if (col->p->col_nr == 0 && t->attr_first_bold)
            ht_bold_off();
}

/*
 * Print status field
 */
static void l_status_print(struct table *t, const char *str)
{
      ht_bold_on();
      l_str_print(t->col_vec[0], str);
      ht_bold_off();
}

/*
 * Print headline of column
 */
static void l_col_headline_print(struct table *t, struct table_col *col)
{
      unsigned int len = strlen(col->head);
      char blank_str[TABLE_STR_MAX];
      (void) t;

      memset(blank_str, ' ', col->p->max_width - len);
      blank_str[col->p->max_width - len] = 0;

      if (l_col_selected(t, col))
            ht_bold_on();
      if (col->align == TABLE_COL_ALIGN_RIGHT)
            hyptop_printf("%s", blank_str);
      hyptop_printf("%s", col->p->head_first);
      if (t->attr_sorted_table)
            ht_underline_on();
      hyptop_printf("%s", col->p->head_char);
      if (t->attr_sorted_table)
            ht_underline_off();
      hyptop_printf("%s", col->p->head_last);
      if (col->align == TABLE_COL_ALIGN_LEFT)
            hyptop_printf("%s", blank_str);
      if (l_col_selected(t, col))
            ht_bold_off();

}

/*
 * Print headline for table
 */
static void l_headline_print(struct table *t)
{
      struct table_col *col;
      int col_nr, first = 1;

      ht_reverse_on();
      /* Print all column headlines */
      table_col_iterate(t, col, col_nr) {
            if (!col->p->enabled)
                  continue;
            if (first)
                  first = 0;
            else
                  hyptop_printf(" ");
            l_col_headline_print(t, col);
      }
      /* This creates a black bar to the end of the line */
      hyptop_print_seek_back(0);
      ht_reverse_off();
      hyptop_print_nl();
}

/*
 * Print unit line for table
 */
static void l_unitline_print(struct table *t)
{
      struct table_col *col;
      int col_nr, first = 1;
      char unit_str[20];

      if (!t->attr_with_units)
            return;
      ht_reverse_on();
      /* Print all column units */
      table_col_iterate(t, col, col_nr) {
            if (!col->p->enabled)
                  continue;
            if (first)
                  first = 0;
            else
                  hyptop_printf(" ");
            if (l_col_selected(t, col))
                  ht_bold_on();
            snprintf(unit_str, sizeof(unit_str), "(%s)", col->unit->str);
            l_str_print(col, unit_str);
            if (l_col_selected(t, col))
                  ht_bold_off();
      }
      /* This creates a black bar to the end of the line */
      hyptop_print_seek_back(0);
      ht_reverse_off();
      hyptop_print_nl();
}

/*
 * Print one table row
 */
static void l_row_print(struct table *t, struct table_row *row)
{
      struct table_col *col;
      int first = 1, col_nr;

      table_col_iterate(t, col, col_nr) {
            struct table_entry *e = &row->entries[col_nr];
            if (!col->p->enabled)
                  continue;
            if (!first)
                  hyptop_printf(" ");
            else
                  first = 0;
            if (row == t->row_last && col_nr == 0)
                  l_status_print(t, e->str);
            else
                  l_col_print(t, col, e->str);
      }
}

/*
 * Print table under curses
 */
static void l_table_print_curses(struct table *t)
{
      struct table_row *row;
      int row_nr = 0;

      if (!t->ready)
            return;
      l_adjust_values(t);
      l_status_update(t);
      l_headline_print(t);
      l_unitline_print(t);
      list_iterate(row, &t->row_list, list) {
            if (t->mode_hide_unmarked && !row->marked)
                  continue;
            if (row_nr < t->row_nr_begin) {
                  row_nr++;
                  continue;
            }
            if (row_nr - t->row_nr_begin >= g.c.row_cnt - t->row_cnt_extra)
                  break;
            if (t->mode_select && row_nr == t->row_nr_select)
                  ht_reverse_on();
            if (row->marked)
                  ht_bold_on();
            l_row_print(t, row);
            if (t->mode_select && row_nr == t->row_nr_select) {
#ifdef WITH_SCROLL_BAR
                  hyptop_print_seek_back(1);
#else
                  hyptop_print_seek_back(0);
#endif
                  ht_reverse_off();
            }
            if (row->marked)
                  ht_bold_off();
            hyptop_print_nl();
            row_nr++;
      }
      ht_reverse_on();
      l_row_print(t, t->row_last);
      hyptop_print_seek_back(0);
      ht_reverse_off();
#ifdef WITH_SCROLL_BAR
      if (t->mode_hide_unmarked)
            ht_print_scroll_bar(t->row_cnt_marked, t->row_nr_begin,
                              t->row_cnt_extra - 1, 1,
                              l_can_scroll_up(t),
                              l_can_scroll_down(t), 1);
      else
            ht_print_scroll_bar(t->row_cnt, t->row_nr_begin,
                              t->row_cnt_extra - 1, 1,
                              l_can_scroll_up(t),
                              l_can_scroll_down(t), 1);
#endif
}

/*
 * Print table under batch mode
 */
static void l_table_print_all(struct table *t)
{
      struct table_row *row;

      l_headline_print(t);
      l_unitline_print(t);
      list_iterate(row, &t->row_list, list) {
            l_row_print(t, row);
            hyptop_print_nl();
      }
      l_row_print(t, t->row_last);
}

/*
 * Print table to screen
 */
void table_print(struct table *t)
{
      if (g.o.batch_mode_specified)
            l_table_print_all(t);
      else
            l_table_print_curses(t);
}

/*
 * Return column by hotkey
 */
static struct table_col *l_col_by_hotkey(struct table *t, char hotkey)
{
      struct table_col *col;
      int col_nr;

      table_col_iterate(t, col, col_nr) {
            if (col->hotkey == hotkey)
                  return col;
      }
      return NULL;
}

/*
 * Select next unit for column with "hotkey"
 */
void table_col_unit_next(struct table *t, char hotkey)
{
      struct table_col *col;
      int i;

      col = l_col_by_hotkey(t, hotkey);
      if (!col || !col->unit_fam)
            assert(0);

      for (i = 0; col->unit_fam[i] != NULL; i++) {
            if (col->unit != col->unit_fam[i])
                  continue;

            if (col->unit_fam[i + 1] == NULL)
                  col->unit = col->unit_fam[0];
            else
                  col->unit = col->unit_fam[i + 1];
            return;
      }
      assert(0);
}

/*
 * Select previous unit for column with "hotkey"
 */
void table_col_unit_prev(struct table *t, char hotkey)
{
      struct table_col *col;
      int i;

      col = l_col_by_hotkey(t, hotkey);
      if (!col || !col->unit_fam)
            assert(0);

      for (i = 0; col->unit_fam[i] != NULL; i++) {
            if (col->unit != col->unit_fam[i])
                  continue;

            if (i == 0) {
                  int j;

                  for (j = 0; col->unit_fam[j] != NULL; j++) {}
                  col->unit = col->unit_fam[j - 1];
            } else {
                  col->unit = col->unit_fam[i - 1];
            }
            return;
      }
      assert(0);
}

/*
 * Set unit for column
 */
int table_col_unit_set(struct table *t, char hotkey, const char *str)
{
      struct table_col *col;
      int i;

      col = l_col_by_hotkey(t, hotkey);
      if (!col)
            return -ENODEV;

      for (i = 0; col->unit_fam[i] != NULL; i++) {
            if (strcasecmp(col->unit_fam[i]->str, str) == 0) {
                  col->unit = col->unit_fam[i];
                  return 0;
            }
      }
      return -EINVAL;
}

/*
 * Select column by hotkey
 */
int table_col_select(struct table *t, char hotkey)
{
      struct table_col *col;

      if (!t->attr_sorted_table)
            assert(0);
      col = l_col_by_hotkey(t, hotkey);
      if (!col || !col->p->enabled)
            return -ENODEV;
      if (t->col_selected == col) {
            t->mode_sort_inverse = t->mode_sort_inverse ? 0 : 1;
      } else  {
            t->mode_sort_inverse = 0;
            t->col_selected = col;
      }
      table_rebuild(t);
      l_table_sort(t);
      return 0;
}

/*
 * Select next column
 */
void table_col_select_next(struct table *t)
{
      int i;

      for (i = t->col_selected->p->col_nr + 1; i < t->col_cnt; i++) {
            if (t->col_vec[i]->p->enabled)
                  goto found;
      }
      return;
found:
      t->col_selected = t->col_vec[i];
      l_table_sort(t);
}

/*
 * Select previous column
 */
void table_col_select_prev(struct table *t)
{
      int i;

      for (i = t->col_selected->p->col_nr - 1; i >= 0; i--) {
            if (t->col_vec[i]->p->enabled)
                  goto found;
      }
      return;
found:
      t->col_selected = t->col_vec[i];
      l_table_sort(t);
}

/*
 * Toggle enabled status for column
 */
void table_col_enable_toggle(struct table *t, char hotkey)
{
      struct table_col *col;

      col = l_col_by_hotkey(t, hotkey);
      if (!col || col->p->col_nr == 0)
            return;
      col->p->enabled = col->p->enabled ? 0 : 1;
      if (col == t->col_selected)
            t->col_selected = t->col_vec[0];
}

/*
 * Process input for table
 */
void table_process_input(struct table *t, int c)
{
      switch (c) {
      case '<':
            if (t->attr_sorted_table)
                  table_col_select_prev(t);
            break;
      case '>':
            if (t->attr_sorted_table)
                  table_col_select_next(t);
            break;
      case '.':
            if (l_mode_hide_unmarked_toggle(t) == 0)
                  l_select_mode_off(t);
            break;
      case '+':
            if (!t->attr_with_units)
                  break;
            table_col_unit_next(t, t->col_selected->hotkey);
            table_rebuild(t);
            break;
      case '-':
            if (!t->attr_with_units)
                  break;
            table_col_unit_prev(t, t->col_selected->hotkey);
            table_rebuild(t);
            break;
      case 'G':
            if (t->mode_select)
                  table_row_select_down(t, TABLE_SCROLL_LAST);
            else
                  table_scroll_down(t, TABLE_SCROLL_LAST);
            break;
      case 'g':
            if (t->mode_select)
                  table_row_select_up(t, TABLE_SCROLL_LAST);
            else
                  table_scroll_up(t, TABLE_SCROLL_LAST);
            break;
      case KEY_NPAGE:
            if (t->mode_select)
                  table_row_select_down(t, TABLE_SCROLL_PAGE);
            else
                  table_scroll_down(t, TABLE_SCROLL_PAGE);
            break;
      case KEY_PPAGE:
            if (t->mode_select)
                  table_row_select_up(t, TABLE_SCROLL_PAGE);
            else
                  table_scroll_up(t, TABLE_SCROLL_PAGE);
            break;
      case 'j':
      case KEY_DOWN:
            if (t->mode_select)
                  table_row_select_down(t, TABLE_SCROLL_LINE);
            else
                  table_scroll_down(t, TABLE_SCROLL_LINE);
            break;
      case 'k':
      case KEY_UP:
            if (t->mode_select)
                  table_row_select_up(t, TABLE_SCROLL_LINE);
            else
                  table_scroll_up(t, TABLE_SCROLL_LINE);
            break;
      case ' ':
            if (t->mode_select) {
                  l_row_select_mark_toggle(t);
            } else {
                  table_row_mark_del_all(t);
                  t->mode_hide_unmarked = 0;
            }
            break;
      case 'l':
      case KEY_RIGHT:
            if (!t->mode_select)
                  l_select_mode_on(t);
            break;
      case 'h':
      case KEY_LEFT:
            if (t->mode_select)
                  l_select_mode_off(t);
            break;
      default:
            if (t->attr_sorted_table)
                  table_col_select(t, c);
      }
}

Generated by  Doxygen 1.6.0   Back to index