Index: uspace/srv/hid/output/proto/vt100.c
===================================================================
--- uspace/srv/hid/output/proto/vt100.c	(revision 7eaeec113ff74c8737354abec7d5185097de8278)
+++ uspace/srv/hid/output/proto/vt100.c	(revision 7eaeec113ff74c8737354abec7d5185097de8278)
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <io/color.h>
+#include "vt100.h"
+
+#define MAX_CONTROL  20
+
+typedef enum {
+	CI_BLACK   = 0,
+	CI_RED     = 1,
+	CI_GREEN   = 2,
+	CI_BROWN   = 3,
+	CI_BLUE    = 4,
+	CI_MAGENTA = 5,
+	CI_CYAN    = 6,
+	CI_WHITE   = 7
+} sgr_color_index_t;
+
+typedef enum {
+	SGR_RESET       = 0,
+	SGR_BOLD        = 1,
+	SGR_UNDERLINE   = 4,
+	SGR_BLINK       = 5,
+	SGR_REVERSE     = 7,
+	SGR_FGCOLOR     = 30,
+	SGR_BGCOLOR     = 40
+} sgr_command_t;
+
+static sgr_color_index_t color_map[] = {
+	[COLOR_BLACK]   = CI_BLACK,
+	[COLOR_BLUE]    = CI_RED,
+	[COLOR_GREEN]   = CI_GREEN,
+	[COLOR_CYAN]    = CI_CYAN,
+	[COLOR_RED]     = CI_RED,
+	[COLOR_MAGENTA] = CI_MAGENTA,
+	[COLOR_YELLOW]  = CI_BROWN,
+	[COLOR_WHITE]   = CI_WHITE
+};
+
+/** ECMA-48 Set Graphics Rendition. */
+static void vt100_sgr(vt100_state_t *state, unsigned int mode)
+{
+	char control[MAX_CONTROL];
+	
+	snprintf(control, MAX_CONTROL, "\033[%um", mode);
+	state->control_puts(control);
+}
+
+static void vt100_set_pos(vt100_state_t *state, sysarg_t col, sysarg_t row)
+{
+	char control[MAX_CONTROL];
+	
+	snprintf(control, MAX_CONTROL, "\033[%" PRIun ";%" PRIun "f",
+	    row + 1, col + 1);
+	state->control_puts(control);
+}
+
+static void vt100_set_sgr(vt100_state_t *state, char_attrs_t attrs)
+{
+	switch (attrs.type) {
+	case CHAR_ATTR_STYLE:
+		switch (attrs.val.style) {
+		case STYLE_NORMAL:
+			vt100_sgr(state, SGR_RESET);
+			vt100_sgr(state, SGR_BGCOLOR + CI_WHITE);
+			vt100_sgr(state, SGR_FGCOLOR + CI_BLACK);
+			break;
+		case STYLE_EMPHASIS:
+			vt100_sgr(state, SGR_RESET);
+			vt100_sgr(state, SGR_BGCOLOR + CI_WHITE);
+			vt100_sgr(state, SGR_FGCOLOR + CI_RED);
+			vt100_sgr(state, SGR_BOLD);
+			break;
+		case STYLE_INVERTED:
+			vt100_sgr(state, SGR_RESET);
+			vt100_sgr(state, SGR_BGCOLOR + CI_BLACK);
+			vt100_sgr(state, SGR_FGCOLOR + CI_WHITE);
+			break;
+		case STYLE_SELECTED:
+			vt100_sgr(state, SGR_RESET);
+			vt100_sgr(state, SGR_BGCOLOR + CI_RED);
+			vt100_sgr(state, SGR_FGCOLOR + CI_WHITE);
+			break;
+		}
+		break;
+	case CHAR_ATTR_INDEX:
+		vt100_sgr(state, SGR_RESET);
+		vt100_sgr(state, SGR_BGCOLOR + color_map[attrs.val.index.bgcolor & 7]);
+		vt100_sgr(state, SGR_FGCOLOR + color_map[attrs.val.index.fgcolor & 7]);
+		
+		if (attrs.val.index.attr & CATTR_BRIGHT)
+			vt100_sgr(state, SGR_BOLD);
+		
+		break;
+	case CHAR_ATTR_RGB:
+		vt100_sgr(state, SGR_RESET);
+		
+		if (attrs.val.rgb.bgcolor <= attrs.val.rgb.fgcolor)
+			vt100_sgr(state, SGR_REVERSE);
+		
+		break;
+	}
+}
+
+vt100_state_t *vt100_state_create(sysarg_t cols, sysarg_t rows,
+    vt100_putchar_t putchar_fn, vt100_control_puts_t control_puts_fn)
+{
+	vt100_state_t *state =
+	    malloc(sizeof(vt100_state_t));
+	if (state == NULL)
+		return NULL;
+	
+	state->putchar = putchar_fn;
+	state->control_puts = control_puts_fn;
+	
+	state->cols = cols;
+	state->rows = rows;
+	
+	state->cur_col = (sysarg_t) -1;
+	state->cur_row = (sysarg_t) -1;
+	
+	state->cur_attrs.type = CHAR_ATTR_STYLE;
+	state->cur_attrs.val.style = STYLE_NORMAL;
+	
+	/* Initialize graphic rendition attributes */
+	vt100_sgr(state, SGR_RESET);
+	vt100_sgr(state, SGR_FGCOLOR + CI_BLACK);
+	vt100_sgr(state, SGR_BGCOLOR + CI_WHITE);
+	state->control_puts("\033[2J");
+	state->control_puts("\033[?25l");
+	
+	return state;
+}
+
+void vt100_state_destroy(vt100_state_t *state)
+{
+	free(state);
+}
+
+void vt100_get_dimensions(vt100_state_t *state, sysarg_t *cols,
+    sysarg_t *rows)
+{
+	*cols = state->cols;
+	*rows = state->rows;
+}
+
+int vt100_yield(vt100_state_t *state)
+{
+	return EOK;
+}
+
+int vt100_claim(vt100_state_t *state)
+{
+	return EOK;
+}
+
+void vt100_goto(vt100_state_t *state, sysarg_t col, sysarg_t row)
+{
+	if ((col >= state->cols) || (row >= state->rows))
+		return;
+	
+	if ((col != state->cur_col) || (row != state->cur_row)) {
+		vt100_set_pos(state, col, row);
+		state->cur_col = col;
+		state->cur_row = row;
+	}
+}
+
+void vt100_set_attr(vt100_state_t *state, char_attrs_t attrs)
+{
+	if (!attrs_same(state->cur_attrs, attrs)) {
+		vt100_set_sgr(state, attrs);
+		state->cur_attrs = attrs;
+	}
+}
+
+void vt100_cursor_visibility(vt100_state_t *state, bool visible)
+{
+	if (visible)
+		state->control_puts("\033[?25h");
+	else
+		state->control_puts("\033[?25l");
+}
+
+void vt100_putchar(vt100_state_t *state, wchar_t ch)
+{
+	state->putchar(ch == 0 ? ' ' : ch);
+	state->cur_col++;
+	
+	if (state->cur_col >= state->cols) {
+		state->cur_row += state->cur_col / state->cols;
+		state->cur_col %= state->cols;
+	}
+}
+
+/** @}
+ */
