Пример #1
0
R_API void r_cons_pal_list(int rad, const char *arg) {
	char *name, **color;
	const char *hasnext;
	int i;
	if (rad == 'j') {
		r_cons_print ("{");
	}
	for (i = 0; keys[i].name; i++) {
		RColor *rcolor = RCOLOR_AT (i);
		color = COLOR_AT (i);
		switch (rad) {
		case 'j':
			hasnext = (keys[i + 1].name) ? "," : "";
			r_cons_printf ("\"%s\":[%d,%d,%d]%s",
				keys[i].name, rcolor->r, rcolor->g, rcolor->b, hasnext);
			break;
		case 'c': {
			const char *prefix = r_str_trim_ro (arg);
			if (!prefix) {
				prefix = "";
			}
			hasnext = (keys[i + 1].name) ? "\n" : "";
			// TODO Need to replace the '.' char because this is not valid CSS
			char *name = strdup (keys[i].name);
			int j, len = strlen (name);
			for (j = 0; j < len; j++) {
				if (name[j] == '.') {
					name[j] = '_';
				}
			}
			r_cons_printf (".%s%s { color: rgb(%d, %d, %d); }%s",
				prefix, name, rcolor->r, rcolor->g, rcolor->b, hasnext);
			free (name);
			}
			break;
		case 'h':
			name = strdup (keys[i].name);
			r_str_replace_char (name, '.', '_');
			r_cons_printf (".%s { color:#%02x%02x%02x }\n",
				name, rcolor->r, rcolor->g, rcolor->b);
			free (name);
			break;
		case '*':
		case 'r':
		case 1:
			r_cons_printf ("ec %s rgb:%02x%02x%02x\n",
				keys[i].name, rcolor->r, rcolor->g, rcolor->b);
			break;
		default:
			r_cons_printf (" %s##"Color_RESET"  %s\n", *color,
				keys[i].name);
		}
	}
	if (rad == 'j') {
		r_cons_print ("}\n");
	}
}
Пример #2
0
int main() {
	int i,j ,k;
	//char *str = "\x1b[38;5;231mpop\x1b[0m";
         //char *str ="\x1b]4;%d;rgb:30/20/24pop\x1b[0m";
         char *str ="\x1b\\pop\x1b[0m";
i=j=k =0;

	r_cons_new ();
//	r_cons_rgb_init ();
	printf ("3 == %d\n", r_str_ansi_len (str));
	for (i=0;i<255;i+=40) {
	for (j=0;j<255;j+=40) { for (k=0;k<255;k+=40) {
		r_cons_rgb (i, j, k, 0);
		r_cons_rgb (i, j, k, 1);
		r_cons_print ("__");
		r_cons_reset_colors ();

		r_cons_rgb (i, j, k, 0);
//		r_cons_rgb (155, 200, 200, 1);
		r_cons_printf (" RGB %d %d %d", i, j, k);
		r_cons_reset_colors ();
		r_cons_newline ();
	}
}}
	r_cons_flush ();

	return 0;
}
Пример #3
0
static void r_cons_pal_show_rgb() {
	const int inc = 3;
	int i, j, k, n = 0;
	RColor rc = RColor_BLACK;
	r_cons_print ("\n\nRGB:\n");
	for (i = n = 0; i <= 0xf; i += inc) {
		for (k = 0; k <= 0xf; k += inc) {
			for (j = 0; j <= 0xf; j += inc) {
				char fg[32], bg[32];
				rc.r = i * 16;
				rc.g = j * 16;
				rc.b = k * 16;
				strcpy (fg, ((i < 6) && (j < 5))
					? Color_WHITE: Color_BLACK);
				r_cons_rgb_str (bg, sizeof (bg), &rc);
				r_cons_printf ("%s%s rgb:%02x%02x%02x "
					Color_RESET, fg, bg, rc.r, rc.g, rc.b);
				if (n ++== 5) {
					n = 0;
					r_cons_newline ();
				}
			}
		}
	}
}
Пример #4
0
static void r_cons_pal_show_rgb () {
	const int inc = 3;
	int i, j, k, n = 0;
	r_cons_print ("\n\nRGB:\n");
	for (i = n = 0; i <= 0xf; i += inc) {
		for (k = 0; k <= 0xf; k += inc) {
			for (j = 0; j <= 0xf; j += inc) {
				char fg[32], bg[32];
				int r = i * 16;
				int g = j * 16;
				int b = k * 16;
				strcpy (fg, ((i < 6) && (j < 5))
					? Color_WHITE: Color_BLACK);
				r_cons_rgb_str (bg, r, g, b, 1);
				r_cons_printf ("%s%s rgb:%02x%02x%02x "
					Color_RESET, fg, bg, r, g, b);
				//if (n++==7) {
				if (n ++== 5) {
					n = 0;
					r_cons_newline ();
				}
			}
		}
	}
}
Пример #5
0
static void r_cons_pal_show_256() {
	RColor rc = RColor_BLACK;
	r_cons_print ("\n\nXTerm colors:\n");
	int r = 0;
	int g = 0;
	int b = 0;
	for (r = 0x00; r <= 0xff; r += 0x28) {
		rc.r = r;
		if (rc.r == 0x28) {
			rc.r = 0x5f;
		}
		for (b = 0x00; b <= 0xff; b += 0x28) {
			rc.b = b;
			if (rc.b == 0x28) {
				rc.b = 0x5f;
			}
			for (g = 0x00; g <= 0xff; g += 0x28) {
				rc.g = g;
				char bg[32];
				if (rc.g == 0x28) {
					rc.g = 0x5f;
				}
				const char *fg = ((rc.r <= 0x5f) && (rc.g <= 0x5f)) ? Color_WHITE: Color_BLACK;
				r_cons_rgb_str (bg, sizeof (bg), &rc);
				r_cons_printf ("%s%s rgb:%02x%02x%02x "
					Color_RESET, fg, bg, rc.r, rc.g, rc.b);
			}
			r_cons_newline ();
		}
	}
}
Пример #6
0
static void r_cons_pal_show_256 () {
	int r, g, b;
	r_cons_print ("\n\nXTerm colors:\n");
	for (r = 0x00; r <= 0xff; r += 0x28) {
		if (r == 0x28) {
			r = 0x5f;
		}
		for (b = 0x00; b <= 0xff; b += 0x28) {
			if (b == 0x28) {
				b = 0x5f;
			}
			for (g = 0x00; g <= 0xff; g += 0x28) {
				char fg[32], bg[32];
				if (g == 0x28) {
					g = 0x5f;
				}
				if ((r <= 0x5f) && (g <= 0x5f)) {
					strcpy (fg, Color_WHITE);
				} else {
					strcpy (fg, Color_BLACK);
				}
				r_cons_rgb_str (bg, r, g, b, 1);
				r_cons_printf ("%s%s rgb:%02x%02x%02x "
					Color_RESET, fg, bg, r, g, b);
				if (g == 0xff) {
					r_cons_newline ();
				}
			}
		}
	}
}
Пример #7
0
R_API int r_cons_any_key(const char *msg) {
	if (msg && *msg) {
		r_cons_printf ("\n-- %s --\n", msg);
	} else {
		r_cons_print ("\n--press any key--\n");
	}
	r_cons_flush ();
	return r_cons_readchar ();
	//r_cons_strcat ("\x1b[2J\x1b[0;0H"); // wtf?
}
Пример #8
0
static void r_cons_pal_show_gs () {
	int i, n;
	r_cons_print ("\nGreyscale:\n");
	for (i = 0x08, n = 0;  i <= 0xee; i += 0xa) {
		char fg[32], bg[32];

		if (i < 0x76) strcpy (fg, Color_WHITE);
		else strcpy (fg, Color_BLACK);
		r_cons_rgb_str (bg, i, i, i, 1);
		r_cons_printf ("%s%s rgb:%02x%02x%02x "Color_RESET,
			fg, bg, i, i, i);
		if (n++ == 5) {
			n = 0;
			r_cons_newline ();
		}
	}
}
Пример #9
0
static void rtti_msvc_print_all(RVTableContext *context, int mode) {
	r_cons_break_push (NULL, NULL);
	RList *vtables = r_anal_vtable_search (context);
	RListIter *vtableIter;
	RVTableInfo *table;

	if (vtables) {
		r_list_foreach (vtables, vtableIter, table) {
			if (r_cons_is_breaked ()) {
				break;
			}
			r_anal_rtti_msvc_print_at_vtable (context, table->saddr, mode);
			r_cons_print ("\n");
		}
	}
	r_list_free (vtables);

	r_cons_break_pop ();
}
Пример #10
0
static void r_cons_pal_show_gs() {
	int i, n;
	r_cons_print ("\nGreyscale:\n");
	RColor rcolor = RColor_BLACK;
	for (i = 0x08, n = 0;  i <= 0xee; i += 0xa) {
		char fg[32], bg[32];
		rcolor.r = i;
		rcolor.g = i;
		rcolor.b = i;

		if (i < 0x76) {
			strcpy (fg, Color_WHITE);
		} else {
			strcpy (fg, Color_BLACK);
		}
		r_cons_rgb_str (bg, sizeof (bg), &rcolor);
		r_cons_printf ("%s%s rgb:%02x%02x%02x "Color_RESET,
			fg, bg, i, i, i);
		if (n++ == 5) {
			n = 0;
			r_cons_newline ();
		}
	}
}
Пример #11
0
R_API void r_cons_pal_list (int rad, const char *arg) {
	RConsPalette *pal = & (r_cons_singleton ()->pal);
	ut8 r, g, b, *p = (ut8*)pal;
	char *name, **color, rgbstr[32];
	const char *hasnext;
	int i;
	if (rad == 'j') r_cons_print ("{");
	for (i = 0; keys[i].name; i++) {
		color = (char**) (p + keys[i].off);
		switch (rad) {
		case 'j':
			r = g = b = 0;
			r_cons_rgb_parse (*color, &r, &g, &b, NULL);
			hasnext = (keys[i + 1].name) ? "," : "";
			r_cons_printf ("\"%s\":[%d,%d,%d]%s",
				keys[i].name, r, g, b, hasnext);
			break;
		case 'c': {
			const char *prefix = r_str_chop_ro (arg);
			if (!prefix) {
				prefix = "";
			}
			r = g = b = 0;
			r_cons_rgb_parse (*color, &r, &g, &b, NULL);
			hasnext = (keys[i + 1].name) ? "\n" : "";
			//Need to replace the '.' char because this is not
			//valid CSS
			char *name = strdup (keys[i].name);
			int j, len = strlen (name);
			for (j = 0; j < len; j++) {
				if (name[j] == '.') {
					name[j] = '_';
				}
			}
			r_cons_printf (".%s%s { color: rgb(%d, %d, %d); }%s",
				prefix, name, r, g, b, hasnext);
			free (name);
			}
			break;
		case 'h':
			r = g = b = 0;
			r_cons_rgb_parse (*color, &r, &g, &b, NULL);
			rgbstr[0] = 0;
			name = strdup (keys[i].name);
			r_str_replace_char (name, '.', '_');
			r_cons_printf (".%s { color:#%02x%02x%02x }\n",
				name, r, g, b);
			free (name);
			break;
		case '*':
		case 'r':
		case 1:
			r = g = b = 0;
			r_cons_rgb_parse (*color, &r, &g, &b, NULL);
			rgbstr[0] = 0;
			r_cons_rgb_str (rgbstr, r, g, b, 0);
			r_cons_printf ("ec %s rgb:%02x%02x%02x\n",
				keys[i].name, r, g, b);
			break;
		default:
			r_cons_printf (" %s##"Color_RESET"  %s\n", *color,
				keys[i].name);
		}
	}
	if (rad == 'j') r_cons_print ("}\n");
}
Пример #12
0
R_API void r_cons_println(const char* str) {
	r_cons_print (str);
	r_cons_newline ();
}
Пример #13
0
static void print_format_values(RCore *core, const char *fmt, bool onstack, ut64 src, bool color) {
	char opt;
	ut64 bval = src;
	int i;
	int endian = core->print->big_endian;
	int width = (core->anal->bits == 64)? 8: 4;
	int bsize = R_MIN (64, core->blocksize);

	ut8 *buf = malloc (bsize);
	if (!buf) {
		eprintf ("Cannot allocate %d byte(s)\n", bsize);
		free (buf);
		return;
	}
	if (fmt) {
		opt = *fmt;
	} else {
		opt = 'p'; // void *ptr
	}
	if (onstack || ((opt != 'd' && opt != 'x') && !onstack)) {
		if (color) {
			r_cons_printf (Color_BGREEN"0x%08"PFMT64x Color_RESET" --> ", bval);
		} else {
			r_cons_printf ("0x%08"PFMT64x" --> ", bval);
		}
		r_io_read_at (core->io, bval, buf, bsize);
	}
	if (onstack) { // Fetch value from stack
		bval = get_buf_val (buf, endian, width);
		if (opt != 'd' && opt != 'x') {
			r_io_read_at (core->io, bval, buf, bsize); // update buf with val from stack
		}
	}
	r_cons_print (color? Color_BGREEN: "");
	switch (opt) {
	case 'z' : // Null terminated string
		r_cons_print (color ?Color_RESET Color_BWHITE:"");
		r_cons_print ("\"");
		for (i = 0; i < MAXSTRLEN; i++) {
			if (buf[i] == '\0') {
				break;
			}
			ut8 b = buf[i];
			if (IS_PRINTABLE (b)) {
				r_cons_printf ("%c", b);
			} else {
				r_cons_printf ("\\x%02x", b);
			}
			if (i == MAXSTRLEN - 1) {
				 r_cons_print ("..."); // To show string is truncated
			}
		}
		r_cons_print ("\"");
		r_cons_newline ();
		break;
	case 'd' : // integer
	case 'x' :
		r_cons_printf ("0x%08" PFMT64x, bval);
		r_cons_newline ();
		break;
	case 'c' : // char
		r_cons_print ("\'");
		ut8 ch = buf[0];
		if (IS_PRINTABLE (ch)) {
			r_cons_printf ("%c", ch);
		} else {
			r_cons_printf ("\\x%02x", ch);
		}
		r_cons_print ("\'");
		r_cons_newline ();
		break;
	case 'p' : // pointer
		{
		// Try to deref the pointer once again
		r_cons_printf ("0x%08"PFMT64x, get_buf_val (buf, endian, width));
		r_cons_newline ();
		break;
		}
	default:
		//TODO: support types like structs and unions
		r_cons_println ("unk_format");
	}
	r_cons_print (Color_RESET);
	free (buf);
}
Пример #14
0
R_API void r_cons_println(const char* str) {
	r_cons_print (str);
	r_cons_print ("\n");
}
Пример #15
0
static int cmd_type(void *data, const char *input) {
	RCore *core = (RCore *)data;
	char *res;
	const char *help_message[] = {
		"USAGE tu[...]", "", "",
		"tu", "", "List all loaded unions",
		"tu?", "", "show this help",
		NULL
	};

	switch (input[0]) {
	case 'n': // "tn"
		cmd_type_noreturn (core, input + 1);
		break;
	// t [typename] - show given type in C syntax
	case 'u': // "tu"
		switch (input[1]) {
		case '?':
			r_core_cmd_help (core, help_message);
			break;
		case 0:
			sdb_foreach (core->anal->sdb_types, stdprintifunion, core);
			break;
		}
		break;
	case 'k': // "tk"
		res = (input[1] == ' ')
			? sdb_querys (core->anal->sdb_types, NULL, -1, input + 2)
			: sdb_querys (core->anal->sdb_types, NULL, -1, "*");
		if (res) {
			r_cons_print (res);
		}
		break;
	case 's': // "ts"
		switch (input[1]) {
		case '?': {
			const char *help_message[] = {
				"USAGE ts[...]", "", "",
				"ts", "", "List all loaded structs",
				"ts?", "", "show this help",
				NULL };
			r_core_cmd_help (core, help_message);
		} break;
		case 0:
			sdb_foreach (core->anal->sdb_types, stdprintifstruct, core);
			break;
		}
		break;
	case 'b': {
		char *p, *s = (strlen (input) > 1)? strdup (input + 2): NULL;
		const char *isenum;
		p = s? strchr (s, ' '): NULL;
		if (p) {
			*p++ = 0;
			// dupp in core.c (see getbitfield())
			isenum = sdb_const_get (core->anal->sdb_types, s, 0);
			if (isenum && !strcmp (isenum, "enum")) {
				*--p = '.';
				const char *res = sdb_const_get (core->anal->sdb_types, s, 0);
				if (res)
					r_cons_println (res);
				else eprintf ("Invalid enum member\n");
			} else {
				eprintf ("This is not an enum\n");
			}
		} else {
			eprintf ("Missing value\n");
		}
		free (s);
	} break;
	case 'e': {
		if (!input[1]) {
			char *name = NULL;
			SdbKv *kv;
			SdbListIter *iter;
			SdbList *l = sdb_foreach_list (core->anal->sdb_types);
			ls_foreach (l, iter, kv) {
				if (!strcmp (kv->value, "enum")) {
					if (!name || strcmp (kv->value, name)) {
						free (name);
						name = strdup (kv->key);
						r_cons_println (name);
					}
				}
			}
			free (name);
			ls_free (l);
			break;
		}
		if (input[1] == '?') {
			const char *help_message[] = {
				"USAGE te[...]", "", "",
				"te", "", "List all loaded enums",
				"te", " <enum> <value>", "Show name for given enum number",
				"te?", "", "show this help",
				NULL };
			r_core_cmd_help (core, help_message);
			break;
		}
		char *p, *s = strdup (input + 2);
		const char *isenum;
		p = strchr (s, ' ');
		if (p) {
			*p++ = 0;
			isenum = sdb_const_get (core->anal->sdb_types, s, 0);
			if (isenum && !strncmp (isenum, "enum", 4)) {
				const char *q = sdb_fmt (0, "%s.0x%x", s, (ut32)r_num_math (core->num, p));
				const char *res = sdb_const_get (core->anal->sdb_types, q, 0);
				if (res)
					r_cons_println (res);
			} else {
				eprintf ("This is not an enum\n");
			}
		} else {
			//eprintf ("Missing value\n");
			r_core_cmdf (core, "t~&%s,=0x", s);
		}
		free (s);
	} break;
	case ' ': {
		const char *isenum = sdb_const_get (core->anal->sdb_types, input + 1, 0);
		if (isenum && !strcmp (isenum, "enum")) {
			eprintf ("IS ENUM! \n");
		} else {
			char *fmt = r_anal_type_format (core->anal, input + 1);
			if (fmt) {
				r_str_chop (fmt);
				r_cons_printf ("pf %s\n", fmt);
				free (fmt);
			} else eprintf ("Cannot find '%s' type\n", input + 1);
		}
	} break;
	// t* - list all types in 'pf' syntax
	case '*':
		sdb_foreach (core->anal->sdb_types, typelist, core);
		break;
	case 0:
		sdb_foreach (core->anal->sdb_types, sdbforcb, core);
		break;
	case 'o':
		if (!r_sandbox_enable (0)) {
			if (input[1] == ' ') {
				const char *filename = input + 2;
				char *homefile = NULL;
				if (*filename == '~') {
					if (filename[1] && filename[2]) {
						homefile = r_str_home (filename + 2);
						filename = homefile;
					}
				}
				if (!strcmp (filename, "-")) {
					char *out, *tmp;
					tmp = r_core_editor (core, NULL, "");
					if (tmp) {
						out = r_parse_c_string (tmp);
						if (out) {
							//		r_cons_strcat (out);
							save_parsed_type (core, out);
							free (out);
						}
						free (tmp);
					}
				} else {
					char *out = r_parse_c_file (filename);
					if (out) {
						//r_cons_strcat (out);
						save_parsed_type (core, out);
						free (out);
					}
					//r_anal_type_loadfile (core->anal, filename);
				}
				free (homefile);
			} else if (input[1] == 's') {
				const char *dbpath = input + 3;
				if (r_file_exists (dbpath)) {
					Sdb *db_tmp = sdb_new (0, dbpath, 0);
					sdb_merge (core->anal->sdb_types, db_tmp);
					sdb_close (db_tmp);
					sdb_free (db_tmp);
				}
			}
		} else {
			eprintf ("Sandbox: system call disabled\n");
		}
		break;
	// td - parse string with cparse engine and load types from it
	case 'd':
		if (input[1] == '?') {
			const char *help_message[] = {
				"Usage:", "\"td [...]\"", "",
				"td", "[string]", "Load types from string",
				NULL };
			r_core_cmd_help (core, help_message);
			r_cons_printf ("Note: The td command should be put between double quotes\n"
				"Example: \" td struct foo {int bar;int cow};\""
				"\nt");

		} else if (input[1] == ' ') {
			char tmp[8192];
			snprintf (tmp, sizeof (tmp) - 1, "%s;", input + 2);
			//const char *string = input + 2;
			//r_anal_str_to_type (core->anal, string);
			char *out = r_parse_c_string (tmp);
			if (out) {
				//r_cons_strcat (out);
				save_parsed_type (core, out);
				free (out);
			}
		} else {
			eprintf ("Invalid use of td. See td? for help\n");
		}
		break;
	// tl - link a type to an address
	case 'l':
		switch (input[1]) {
		case '?': {
			const char *help_message[] = {
				"Usage:", "", "",
				"tl", "", "list all links in readable format",
				"tl", "[typename]", "link a type to current adress.",
				"tl", "[typename] = [address]", "link type to given address.",
				"tls", "[address]", "show link at given address",
				"tl-*", "", "delete all links.",
				"tl-", "[address]", "delete link at given address.",
				"tl*", "", "list all links in radare2 command format",
				"tl?", "", "print this help.",
				NULL };
			r_core_cmd_help (core, help_message);
			} break;
		case ' ': {
			char *type = strdup (input + 2);
			char *ptr = strchr (type, '=');
			ut64 addr;

			if (ptr) {
				*ptr++ = 0;
				r_str_chop (ptr);
				if (ptr && *ptr) {
					addr = r_num_math (core->num, ptr);
				} else {
					eprintf ("address is unvalid\n");
					free (type);
					break;
				}
			} else {
				addr = core->offset;
			}
			r_str_chop (type);
			char *tmp = sdb_get (core->anal->sdb_types, type, 0);
			if (tmp && *tmp) {
				r_anal_type_link (core->anal, type, addr);
				free (tmp);
			} else {
				eprintf ("unknown type %s\n", type);
			}
			free (type);
			}
			break;
		case 's': {
			int ptr;
			char *addr = strdup (input + 2);
			SdbKv *kv;
			SdbListIter *sdb_iter;
			SdbList *sdb_list = sdb_foreach_list (core->anal->sdb_types);
			r_str_chop (addr);
			ptr = r_num_math (NULL, addr);
			//r_core_cmdf (core, "tl~0x%08"PFMT64x" = ", addr);
			ls_foreach (sdb_list, sdb_iter, kv) {
				char *linkptr;
				if (strncmp (kv->key, "link.", strlen ("link."))) {
					continue;
				}
				linkptr = sdb_fmt (-1,"0x%s", kv->key + strlen ("link."));
				if (ptr == r_num_math (NULL, linkptr)) {
					linklist_readable (core, kv->key, kv->value);
				}
			}
			free (addr);
			ls_free (sdb_list);
			}
			break;
		case '-':
			switch (input[2]) {
			case '*':
				sdb_foreach (core->anal->sdb_types, sdbdeletelink, core);
				break;
			case ' ': {
				const char *ptr = input + 3;
				ut64 addr = r_num_math (core->num, ptr);
				r_anal_type_unlink (core->anal, addr);
				}
				break;
			}
			break;
		case '*':
			sdb_foreach (core->anal->sdb_types, linklist, core);
			break;
		case '\0':
			sdb_foreach (core->anal->sdb_types, linklist_readable, core);
			break;
		}
Пример #16
0
// Display a list of entries in the hud, filtered and emphasized based
// on the user input.
R_API char *r_cons_hud(RList *list, const char *prompt) {
	const int buf_size = 128;
	int ch, nch, first_line, current_entry_n, j, i = 0;
	char *p, *x, user_input[buf_size], mask[buf_size];
	int last_color_change, top_entry_n = 0;
	char *selected_entry = NULL;
	char tmp, last_mask = 0;
	void *current_entry;
	RListIter *iter;

	user_input[0] = 0;
	r_cons_clear ();
	// Repeat until the user exits the hud
	for (;;) {
		first_line = 1;
		r_cons_gotoxy (0, 0);
		current_entry_n = 0;
		if (top_entry_n < 0) {
			top_entry_n = 0;
		}
		selected_entry = NULL;
		if (prompt && *prompt) {
			r_cons_print (">> ");
			r_cons_println (prompt);
		}
		r_cons_printf ("%d> %s|\n", top_entry_n, user_input);
		int counter = 0;
		int rows;
		(void)r_cons_get_size (&rows);
		// Iterate over each entry in the list
		r_list_foreach (list, iter, current_entry) {
			memset (mask, 0, buf_size);
			if (!user_input[0] || strmatch (current_entry, user_input, mask, buf_size)) {
				counter++;
				if (counter == rows + top_entry_n) {
					break;
				}
				// if the user scrolled down the list, do not print the first entries
				if (!top_entry_n || current_entry_n >= top_entry_n) {
					// remove everything after a tab (in ??, it contains the commands)
					x = strchr (current_entry, '\t');
					if (x) {
						*x = 0;
					}
					p = strdup (current_entry);
					// if the filter is empty, print the entry and move on
					if (!user_input[0]) {
						r_cons_printf (" %c %s\n", first_line? '-': ' ', current_entry);
					} else {
						// otherwise we need to emphasize the matching part
						if (I(use_color)) {
							last_color_change = 0;
							last_mask = 0;
							r_cons_printf (" %c ", first_line? '-': ' ');
							// Instead of printing one char at the time
							// (which would be slow), we group substrings of the same color
							for (j = 0; p[j] && j < buf_size; j++) {
								if (mask[j] != last_mask) {
									tmp = p[j];
									p[j] = 0;
									if (mask[j]) {
										r_cons_printf (Color_RESET"%s", p + last_color_change);
									} else {
										r_cons_printf (Color_GREEN"%s", p + last_color_change);
									}
									p[j] = tmp;
									last_color_change = j;
									last_mask = mask[j];
								} 
							}
							if (last_mask) {
								r_cons_printf (Color_GREEN"%s\n"Color_RESET, p + last_color_change);
							} else {
								r_cons_printf (Color_RESET"%s\n", p + last_color_change);
							}
						} else {
							// Otherwise we print the matching characters uppercase
							for (j = 0; p[j]; j++) {
								if (mask[j])
									p[j] = toupper ((unsigned char)p[j]);
							}
							r_cons_printf (" %c %s\n", first_line? '-': ' ', p);
						}
					}
					// Clean up and restore the tab character (if any)
					free (p);
					if (x) {
						*x = '\t';
					}
					if (first_line) {
						selected_entry = current_entry;
					}	
					first_line = 0;
				}
				current_entry_n++;
			}
		}

		r_cons_visual_flush ();
		ch = r_cons_readchar ();
		nch = r_cons_arrow_to_hjkl (ch);
		(void)r_cons_get_size (&rows);
		if (nch == 'J' && ch != 'J') {
			top_entry_n += (rows - 1);
			if (top_entry_n + 1 >= current_entry_n) {
				top_entry_n = current_entry_n;
			}
		} else if (nch == 'K' && ch != 'K') {
			top_entry_n -= (rows - 1);
			if (top_entry_n < 0) {
				top_entry_n = 0;
			}
		} else if (nch == 'j' && ch != 'j') {
			if (top_entry_n + 1 < current_entry_n) {
				top_entry_n++;
			}
		} else if (nch == 'k' && ch != 'k') {
			if (top_entry_n >= 0) {
				top_entry_n--;
			}
		} else {
			switch (ch) {
			case 9: // \t
				if (top_entry_n + 1 < current_entry_n) {
					top_entry_n++;
				} else {
					top_entry_n = 0;
				}
				break;
			case 10: // \n
			case 13: // \r
				top_entry_n = 0;
				//		if (!*buf)
				//			return NULL;
				if (current_entry_n >= 1) {
					//eprintf ("%s\n", buf);
					//i = buf[0] = 0;
					return strdup (selected_entry);
				} // no match!
				break;
			case 23: // ^w
				top_entry_n = 0;
				i = user_input[0] = 0;
				break;
			case 0x1b: // ESC
				return NULL;
			case 8:   // bs
			case 127: // bs
				top_entry_n = 0;
				if (i < 1) return NULL;
				user_input[--i] = 0;
				break;
			default:
				if (IS_PRINTABLE (ch)) {
					if (i >= buf_size) {
						break;
					}
					top_entry_n = 0;
					if (i + 1 >= buf_size) {
						// too many
						break;
					}
					user_input[i++] = ch;
					user_input[i] = 0;
				}
				break;
			}
		}
	}