Index: uspace/app/top/screen.c
===================================================================
--- uspace/app/top/screen.c	(revision 94f6df78dd46b93498ccd44f24c2a40a3dbaa74a)
+++ uspace/app/top/screen.c	(revision f682f5a7a15b208afa1a1c5c291d774164968db9)
@@ -290,14 +290,13 @@
 }
 
-static inline void print_tasks_head(void)
+static inline void print_help_head(void)
 {
 	screen_style_inverted();
-	printf("[taskid] [thrds] [resident] [%%resi] [virtual] [%%virt]"
-	    " [%%user] [%%kern] [name");
+	printf("Help");
 	screen_newline();
 	screen_style_normal();
 }
 
-static inline void print_tasks(data_t *data)
+static inline void print_help(void)
 {
 	sysarg_t cols;
@@ -305,36 +304,36 @@
 	screen_get_size(&cols, &rows);
 	
+	screen_newline();
+	
+	printf("Operation modes:");
+	screen_newline();
+	
+	printf(" t .. tasks statistics");
+	screen_newline();
+	
+	printf(" i .. IPC statistics");
+	screen_newline();
+	
+	printf(" e .. exceptions statistics");
+	screen_newline();
+	
+	printf("      a .. toggle display of all/hot exceptions");
+	screen_newline();
+
+	printf(" h .. toggle this help screen");
+	screen_newline();
+
+	screen_newline();
+
+	printf("Other keys:");
+	screen_newline();
+	
+	printf(" q .. quit");
+	screen_newline();
+	
 	sysarg_t col;
 	sysarg_t row;
 	screen_get_pos(&col, &row);
 	
-	size_t i;
-	for (i = 0; (i < data->tasks_count) && (row < rows); i++, row++) {
-		stats_task_t *task = data->tasks + data->tasks_map[i];
-		perc_task_t *perc = data->tasks_perc + data->tasks_map[i];
-		
-		uint64_t resmem;
-		const char *resmem_suffix;
-		bin_order_suffix(task->resmem, &resmem, &resmem_suffix, true);
-		
-		uint64_t virtmem;
-		const char *virtmem_suffix;
-		bin_order_suffix(task->virtmem, &virtmem, &virtmem_suffix, true);
-		
-		printf("%-8" PRIu64 " %7zu %7" PRIu64 "%s ",
-		    task->task_id, task->threads, resmem, resmem_suffix);
-		print_percent(perc->resmem, 2);
-		printf(" %6" PRIu64 "%s ", virtmem, virtmem_suffix);
-		print_percent(perc->virtmem, 2);
-		puts(" ");
-		print_percent(perc->ucycles, 2);
-		puts(" ");
-		print_percent(perc->kcycles, 2);
-		puts(" ");
-		print_string(task->name);
-		
-		screen_newline();
-	}
-	
 	while (row < rows) {
 		screen_newline();
@@ -343,18 +342,34 @@
 }
 
-static inline void print_ipc_head(void)
-{
-	screen_style_inverted();
-	printf("[taskid] [cls snt] [cls rcv] [ans snt]"
-	    " [ans rcv] [irq rcv] [forward] [name");
-	screen_newline();
-	screen_style_normal();
-}
-
-static inline void print_ipc(data_t *data)
+static inline void print_table_head(const table_t *table)
 {
 	sysarg_t cols;
 	sysarg_t rows;
 	screen_get_size(&cols, &rows);
+
+	screen_style_inverted();
+	for (size_t i = 0; i < table->num_columns; i++) {
+		const char *name = table->columns[i].name;
+		int width = table->columns[i].width;
+		if (i != 0) {
+			puts(" ");
+		}
+		if (width == 0) {
+			sysarg_t col;
+			sysarg_t row;
+			screen_get_pos(&col, &row);
+			width = cols - col - 1;
+		}
+		printf("[%-*.*s]", width - 2, width - 2, name);
+	}
+	screen_newline();
+	screen_style_normal();
+}
+
+static inline void print_table(const table_t *table)
+{
+	sysarg_t cols;
+	sysarg_t rows;
+	screen_get_size(&cols, &rows);
 	
 	sysarg_t col;
@@ -363,44 +378,58 @@
 	
 	size_t i;
-	for (i = 0; (i < data->tasks_count) && (row < rows); i++, row++) {
-		uint64_t call_sent;
-		uint64_t call_received;
-		uint64_t answer_sent;
-		uint64_t answer_received;
-		uint64_t irq_notif_received;
-		uint64_t forwarded;
-		
-		char call_sent_suffix;
-		char call_received_suffix;
-		char answer_sent_suffix;
-		char answer_received_suffix;
-		char irq_notif_received_suffix;
-		char forwarded_suffix;
-		
-		order_suffix(data->tasks[i].ipc_info.call_sent, &call_sent,
-		    &call_sent_suffix);
-		order_suffix(data->tasks[i].ipc_info.call_received,
-		    &call_received, &call_received_suffix);
-		order_suffix(data->tasks[i].ipc_info.answer_sent,
-		    &answer_sent, &answer_sent_suffix);
-		order_suffix(data->tasks[i].ipc_info.answer_received,
-		    &answer_received, &answer_received_suffix);
-		order_suffix(data->tasks[i].ipc_info.irq_notif_received,
-		    &irq_notif_received, &irq_notif_received_suffix);
-		order_suffix(data->tasks[i].ipc_info.forwarded, &forwarded,
-		    &forwarded_suffix);
-		
-		printf("%-8" PRIu64 " %8" PRIu64 "%c %8" PRIu64 "%c"
-		     " %8" PRIu64 "%c %8" PRIu64 "%c %8" PRIu64 "%c"
-		     " %8" PRIu64 "%c ", data->tasks[i].task_id,
-		     call_sent, call_sent_suffix,
-		     call_received, call_received_suffix,
-		     answer_sent, answer_sent_suffix,
-		     answer_received, answer_received_suffix,
-		     irq_notif_received, irq_notif_received_suffix,
-		     forwarded, forwarded_suffix);
-		print_string(data->tasks[i].name);
-		
-		screen_newline();
+	for (i = 0; (i < table->num_fields) && (row < rows); i++) {
+		size_t column_index = i % table->num_columns;
+		int width = table->columns[column_index].width;
+		field_t *field = &table->fields[i];
+
+		if (column_index != 0) {
+			puts(" ");
+		}
+
+		if (width == 0) {
+			screen_get_pos(&col, &row);
+			width = cols - col - 1;
+		}
+
+		switch (field->type) {
+			case FIELD_EMPTY:
+				printf("%*s", width, "");
+				break;
+			case FIELD_UINT:
+				printf("%*" PRIu64, width, field->uint);
+				break;
+			case FIELD_UINT_SUFFIX_BIN: {
+				uint64_t val = field->uint;
+				const char *suffix;
+				width -= 3;
+				bin_order_suffix(val, &val, &suffix, true);
+				printf("%*" PRIu64 "%s", width, val, suffix);
+				break;
+				}
+			case FIELD_UINT_SUFFIX_DEC: {
+				uint64_t val = field->uint;
+				char suffix;
+				width -= 1;
+				order_suffix(val, &val, &suffix);
+				printf("%*" PRIu64 "%c", width, val, suffix);
+				break;
+				}
+			case FIELD_PERCENT:
+				width -= 5; /* nnn.% */
+				if (width > 2) {
+					printf("%*s", width - 2, "");
+					width = 2;
+				}
+				print_percent(field->fixed, width);
+				break;
+			case FIELD_STRING:
+				printf("%-*.*s", width, width, field->string);
+				break;
+		}
+
+		if (column_index == table->num_columns - 1) {
+			screen_newline();
+			row++;
+		}
 	}
 	
@@ -411,108 +440,5 @@
 }
 
-static inline void print_excs_head(void)
-{
-	screen_style_inverted();
-	printf("[exc   ] [count   ] [%%count] [cycles  ] [%%cycles] [description");
-	screen_newline();
-	screen_style_normal();
-}
-
-static inline void print_excs(data_t *data)
-{
-	sysarg_t cols;
-	sysarg_t rows;
-	screen_get_size(&cols, &rows);
-	
-	sysarg_t col;
-	sysarg_t row;
-	screen_get_pos(&col, &row);
-	
-	size_t i;
-	for (i = 0; (i < data->exceptions_count) && (row < rows); i++) {
-		/* Filter-out cold exceptions if not instructed otherwise */
-		if ((!excs_all) && (!data->exceptions[i].hot))
-			continue;
-		
-		uint64_t count;
-		uint64_t cycles;
-		
-		char count_suffix;
-		char cycles_suffix;
-		
-		order_suffix(data->exceptions[i].count, &count, &count_suffix);
-		order_suffix(data->exceptions[i].cycles, &cycles, &cycles_suffix);
-		
-		printf("%-8u %9" PRIu64 "%c  ",
-		     data->exceptions[i].id, count, count_suffix);
-		print_percent(data->exceptions_perc[i].count, 2);
-		printf(" %9" PRIu64 "%c   ", cycles, cycles_suffix);
-		print_percent(data->exceptions_perc[i].cycles, 2);
-		puts(" ");
-		print_string(data->exceptions[i].desc);
-		
-		screen_newline();
-		row++;
-	}
-	
-	while (row < rows) {
-		screen_newline();
-		row++;
-	}
-}
-
-static inline void print_help_head(void)
-{
-	screen_style_inverted();
-	printf("Help");
-	screen_newline();
-	screen_style_normal();
-}
-
-static void print_help(void)
-{
-	sysarg_t cols;
-	sysarg_t rows;
-	screen_get_size(&cols, &rows);
-	
-	screen_newline();
-	
-	printf("Operation modes:");
-	screen_newline();
-	
-	printf(" t .. tasks statistics");
-	screen_newline();
-	
-	printf(" i .. IPC statistics");
-	screen_newline();
-	
-	printf(" e .. exceptions statistics");
-	screen_newline();
-	
-	printf("      a .. toggle display of all/hot exceptions");
-	screen_newline();
-
-	printf(" h .. this help screen");
-	screen_newline();
-
-	screen_newline();
-
-	printf("Other keys:");
-	screen_newline();
-	
-	printf(" q .. quit");
-	screen_newline();
-	
-	sysarg_t col;
-	sysarg_t row;
-	screen_get_pos(&col, &row);
-	
-	while (row < rows) {
-		screen_newline();
-		row++;
-	}
-}
-
-static void print_warning(void)
+static inline void print_warning(void)
 {
 	screen_get_pos(&warning_col, &warning_row);
@@ -538,18 +464,10 @@
 	print_warning();
 	
-	switch (op_mode) {
-	case OP_TASKS:
-		print_tasks_head();
-		print_tasks(data);
+	switch (screen_mode) {
+	case SCREEN_TABLE:
+		print_table_head(&data->table);
+		print_table(&data->table);
 		break;
-	case OP_IPC:
-		print_ipc_head();
-		print_ipc(data);
-		break;
-	case OP_EXCS:
-		print_excs_head();
-		print_excs(data);
-		break;
-	case OP_HELP:
+	case SCREEN_HELP:
 		print_help_head();
 		print_help();
Index: uspace/app/top/top.c
===================================================================
--- uspace/app/top/top.c	(revision 94f6df78dd46b93498ccd44f24c2a40a3dbaa74a)
+++ uspace/app/top/top.c	(revision f682f5a7a15b208afa1a1c5c291d774164968db9)
@@ -55,7 +55,79 @@
 #define MINUTE  60
 
-op_mode_t op_mode = OP_TASKS;
+typedef enum {
+	OP_TASKS,
+	OP_IPC,
+	OP_EXCS,
+} op_mode_t;
+
+screen_mode_t screen_mode = SCREEN_TABLE;
+static op_mode_t op_mode = OP_TASKS;
 sort_mode_t sort_mode = SORT_TASK_CYCLES;
-bool excs_all = false;
+static bool excs_all = false;
+
+static const column_t task_columns[] = {
+	{"taskid",   't',  8},
+	{"thrds",    'h',  7},
+	{"resident", 'r', 10},
+	{"%resi",    'R',  7},
+	{"virtual",  'v',  9},
+	{"%virt",    'V',  7},
+	{"%user",    'U',  7},
+	{"%kern",    'K',  7},
+	{"name",     'd',  0},
+};
+
+enum {
+	TASK_COL_ID = 0,
+	TASK_COL_NUM_THREADS,
+	TASK_COL_RESIDENT,
+	TASK_COL_PERCENT_RESIDENT,
+	TASK_COL_VIRTUAL,
+	TASK_COL_PERCENT_VIRTUAL,
+	TASK_COL_PERCENT_USER,
+	TASK_COL_PERCENT_KERNEL,
+	TASK_COL_NAME,
+	TASK_NUM_COLUMNS,
+};
+
+static const column_t ipc_columns[] = {
+	{"taskid",  't', 8},
+	{"cls snt", 'c', 9},
+	{"cls rcv", 'C', 9},
+	{"ans snt", 'a', 9},
+	{"ans rcv", 'A', 9},
+	{"forward", 'f', 9},
+	{"name",    'd', 0},
+};
+
+enum {
+	IPC_COL_TASKID = 0,
+	IPC_COL_CLS_SNT,
+	IPC_COL_CLS_RCV,
+	IPC_COL_ANS_SNT,
+	IPC_COL_ANS_RCV,
+	IPC_COL_FORWARD,
+	IPC_COL_NAME,
+	IPC_NUM_COLUMNS,
+};
+
+static const column_t exception_columns[] = {
+	{"exc",         'e',  8},
+	{"count",       'n', 10},
+	{"%count",      'N',  8},
+	{"cycles",      'c', 10},
+	{"%cycles",     'C',  9},
+	{"description", 'd',  0},
+};
+
+enum {
+	EXCEPTION_COL_ID = 0,
+	EXCEPTION_COL_COUNT,
+	EXCEPTION_COL_PERCENT_COUNT,
+	EXCEPTION_COL_CYCLES,
+	EXCEPTION_COL_PERCENT_CYCLES,
+	EXCEPTION_COL_DESCRIPTION,
+	EXCEPTION_NUM_COLUMNS,
+};
 
 static const char *read_data(data_t *target)
@@ -76,4 +148,9 @@
 	target->ecycles_diff = NULL;
 	target->ecount_diff = NULL;
+	target->table.name = NULL;
+	target->table.num_columns = 0;
+	target->table.columns = NULL;
+	target->table.num_fields = 0;
+	target->table.fields = NULL;
 	
 	/* Get current time */
@@ -316,4 +393,130 @@
 }
 
+static const char *fill_task_table(data_t *data)
+{
+	data->table.name = "Tasks";
+	data->table.num_columns = TASK_NUM_COLUMNS;
+	data->table.columns = task_columns;
+	data->table.num_fields = data->tasks_count * TASK_NUM_COLUMNS;
+	data->table.fields = calloc(data->table.num_fields,
+	    sizeof(field_t));
+	if (data->table.fields == NULL)
+		return "Not enough memory for table fields";
+
+	field_t *field = data->table.fields;
+	for (size_t i = 0; i < data->tasks_count; i++) {
+		stats_task_t *task = data->tasks + data->tasks_map[i];
+		perc_task_t *perc = data->tasks_perc + data->tasks_map[i];
+		field[TASK_COL_ID].type = FIELD_UINT;
+		field[TASK_COL_ID].uint = task->task_id;
+		field[TASK_COL_NUM_THREADS].type = FIELD_UINT;
+		field[TASK_COL_NUM_THREADS].uint = task->threads;
+		field[TASK_COL_RESIDENT].type = FIELD_UINT_SUFFIX_BIN;
+		field[TASK_COL_RESIDENT].uint = task->resmem;
+		field[TASK_COL_PERCENT_RESIDENT].type = FIELD_PERCENT;
+		field[TASK_COL_PERCENT_RESIDENT].fixed = perc->resmem;
+		field[TASK_COL_VIRTUAL].type = FIELD_UINT_SUFFIX_BIN;
+		field[TASK_COL_VIRTUAL].uint = task->virtmem;
+		field[TASK_COL_PERCENT_VIRTUAL].type = FIELD_PERCENT;
+		field[TASK_COL_PERCENT_VIRTUAL].fixed = perc->virtmem;
+		field[TASK_COL_PERCENT_USER].type = FIELD_PERCENT;
+		field[TASK_COL_PERCENT_USER].fixed = perc->ucycles;
+		field[TASK_COL_PERCENT_KERNEL].type = FIELD_PERCENT;
+		field[TASK_COL_PERCENT_KERNEL].fixed = perc->kcycles;
+		field[TASK_COL_NAME].type = FIELD_STRING;
+		field[TASK_COL_NAME].string = task->name;
+		field += TASK_NUM_COLUMNS;
+	}
+
+	return NULL;
+}
+
+static const char *fill_ipc_table(data_t *data)
+{
+	data->table.name = "IPC";
+	data->table.num_columns = IPC_NUM_COLUMNS;
+	data->table.columns = ipc_columns;
+	data->table.num_fields = data->tasks_count * IPC_NUM_COLUMNS;
+	data->table.fields = calloc(data->table.num_fields,
+	    sizeof(field_t));
+	if (data->table.fields == NULL)
+		return "Not enough memory for table fields";
+
+	field_t *field = data->table.fields;
+	for (size_t i = 0; i < data->tasks_count; i++) {
+		field[IPC_COL_TASKID].type = FIELD_UINT;
+		field[IPC_COL_TASKID].uint = data->tasks[i].task_id;
+		field[IPC_COL_CLS_SNT].type = FIELD_UINT_SUFFIX_DEC;
+		field[IPC_COL_CLS_SNT].uint = data->tasks[i].ipc_info.call_sent;
+		field[IPC_COL_CLS_RCV].type = FIELD_UINT_SUFFIX_DEC;
+		field[IPC_COL_CLS_RCV].uint = data->tasks[i].ipc_info.call_received;
+		field[IPC_COL_ANS_SNT].type = FIELD_UINT_SUFFIX_DEC;
+		field[IPC_COL_ANS_SNT].uint = data->tasks[i].ipc_info.answer_sent;
+		field[IPC_COL_ANS_RCV].type = FIELD_UINT_SUFFIX_DEC;
+		field[IPC_COL_ANS_RCV].uint = data->tasks[i].ipc_info.answer_received;
+		field[IPC_COL_FORWARD].type = FIELD_UINT_SUFFIX_DEC;
+		field[IPC_COL_FORWARD].uint = data->tasks[i].ipc_info.forwarded;
+		field[IPC_COL_NAME].type = FIELD_STRING;
+		field[IPC_COL_NAME].string = data->tasks[i].name;
+		field += IPC_NUM_COLUMNS;
+	}
+
+	return NULL;
+}
+
+static const char *fill_exception_table(data_t *data)
+{
+	data->table.name = "Exceptions";
+	data->table.num_columns = EXCEPTION_NUM_COLUMNS;
+	data->table.columns = exception_columns;
+	data->table.num_fields = data->exceptions_count *
+	    EXCEPTION_NUM_COLUMNS;
+	data->table.fields = calloc(data->table.num_fields, sizeof(field_t));
+	if (data->table.fields == NULL)
+		return "Not enough memory for table fields";
+
+	field_t *field = data->table.fields;
+	for (size_t i = 0; i < data->exceptions_count; i++) {
+		if (!excs_all && !data->exceptions[i].hot)
+			continue;
+		field[EXCEPTION_COL_ID].type = FIELD_UINT;
+		field[EXCEPTION_COL_ID].uint = data->exceptions[i].id;
+		field[EXCEPTION_COL_COUNT].type = FIELD_UINT_SUFFIX_DEC;
+		field[EXCEPTION_COL_COUNT].uint = data->exceptions[i].count;
+		field[EXCEPTION_COL_PERCENT_COUNT].type = FIELD_PERCENT;
+		field[EXCEPTION_COL_PERCENT_COUNT].fixed = data->exceptions_perc[i].count;
+		field[EXCEPTION_COL_CYCLES].type = FIELD_UINT_SUFFIX_DEC;
+		field[EXCEPTION_COL_CYCLES].uint = data->exceptions[i].cycles;
+		field[EXCEPTION_COL_PERCENT_CYCLES].type = FIELD_PERCENT;
+		field[EXCEPTION_COL_PERCENT_CYCLES].fixed = data->exceptions_perc[i].cycles;
+		field[EXCEPTION_COL_DESCRIPTION].type = FIELD_STRING;
+		field[EXCEPTION_COL_DESCRIPTION].string = data->exceptions[i].desc;
+		field += EXCEPTION_NUM_COLUMNS;
+	}
+
+	/* in case any cold exceptions were ignored */
+	data->table.num_fields = field - data->table.fields;
+
+	return NULL;
+}
+
+static const char *fill_table(data_t *data)
+{
+	if (data->table.fields != NULL) {
+		free(data->table.fields);
+		data->table.fields = NULL;
+	}
+
+	switch (op_mode) {
+		case OP_TASKS:
+			return fill_task_table(data);
+		case OP_IPC:
+			return fill_ipc_table(data);
+		case OP_EXCS:
+			return fill_exception_table(data);
+	}
+	return NULL;
+}
+
 static void free_data(data_t *target)
 {
@@ -356,4 +559,7 @@
 	if (target->ecount_diff != NULL)
 		free(target->ecount_diff);
+
+	if (target->table.fields != NULL)
+		free(target->table.fields);
 }
 
@@ -389,15 +595,21 @@
 				break;
 			case 't':
+				screen_mode = SCREEN_TABLE;
 				op_mode = OP_TASKS;
 				break;
 			case 'i':
+				screen_mode = SCREEN_TABLE;
 				op_mode = OP_IPC;
 				break;
 			case 'e':
+				screen_mode = SCREEN_TABLE;
 				op_mode = OP_EXCS;
 				break;
 			case 'h':
 			case '?':
-				op_mode = OP_HELP;
+				if (screen_mode == SCREEN_HELP)
+					screen_mode = SCREEN_TABLE;
+				else
+					screen_mode = SCREEN_HELP;
 				break;
 			case 'q':
@@ -405,4 +617,5 @@
 			case 'a':
 				if (op_mode == OP_EXCS) {
+					screen_mode = SCREEN_TABLE;
 					excs_all = !excs_all;
 					if (excs_all)
@@ -419,4 +632,7 @@
 
 		sort_data(&data);
+		if ((ret = fill_table(&data)) != NULL) {
+			goto out;
+		}
 		print_data(&data);
 	}
Index: uspace/app/top/top.h
===================================================================
--- uspace/app/top/top.h	(revision 94f6df78dd46b93498ccd44f24c2a40a3dbaa74a)
+++ uspace/app/top/top.h	(revision f682f5a7a15b208afa1a1c5c291d774164968db9)
@@ -51,9 +51,7 @@
 
 typedef enum {
-	OP_TASKS,
-	OP_IPC,
-	OP_EXCS,
-	OP_HELP
-} op_mode_t;
+	SCREEN_TABLE,
+	SCREEN_HELP,
+} screen_mode_t;
 
 typedef enum {
@@ -61,7 +59,6 @@
 } sort_mode_t;
 
-extern op_mode_t op_mode;
+extern screen_mode_t screen_mode;
 extern sort_mode_t sort_mode;
-extern bool excs_all;
 
 typedef struct {
@@ -86,4 +83,32 @@
 	fixed_float count;
 } perc_exc_t;
+
+typedef enum {
+	FIELD_EMPTY, FIELD_UINT, FIELD_UINT_SUFFIX_BIN, FIELD_UINT_SUFFIX_DEC,
+	FIELD_PERCENT, FIELD_STRING
+} field_type_t;
+
+typedef struct {
+	field_type_t type;
+	union {
+		fixed_float fixed;
+		uint64_t uint;
+		const char *string;
+	};
+} field_t;
+
+typedef struct {
+	const char *name;
+	char key;
+	int width;
+} column_t;
+
+typedef struct {
+	const char *name;
+	size_t num_columns;
+	const column_t *columns;
+	size_t num_fields;
+	field_t *fields;
+} table_t;
 
 typedef struct {
@@ -122,4 +147,6 @@
 	uint64_t *ecycles_diff;
 	uint64_t *ecount_diff;
+
+	table_t table;
 } data_t;
 
