cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

util.c (17647B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *  util.c
      4 *
      5 *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
      6 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
      7 */
      8
      9#include <stdarg.h>
     10
     11#include "dialog.h"
     12
     13/* Needed in signal handler in mconf.c */
     14int saved_x, saved_y;
     15
     16struct dialog_info dlg;
     17
     18static void set_mono_theme(void)
     19{
     20	dlg.screen.atr = A_NORMAL;
     21	dlg.shadow.atr = A_NORMAL;
     22	dlg.dialog.atr = A_NORMAL;
     23	dlg.title.atr = A_BOLD;
     24	dlg.border.atr = A_NORMAL;
     25	dlg.button_active.atr = A_REVERSE;
     26	dlg.button_inactive.atr = A_DIM;
     27	dlg.button_key_active.atr = A_REVERSE;
     28	dlg.button_key_inactive.atr = A_BOLD;
     29	dlg.button_label_active.atr = A_REVERSE;
     30	dlg.button_label_inactive.atr = A_NORMAL;
     31	dlg.inputbox.atr = A_NORMAL;
     32	dlg.inputbox_border.atr = A_NORMAL;
     33	dlg.searchbox.atr = A_NORMAL;
     34	dlg.searchbox_title.atr = A_BOLD;
     35	dlg.searchbox_border.atr = A_NORMAL;
     36	dlg.position_indicator.atr = A_BOLD;
     37	dlg.menubox.atr = A_NORMAL;
     38	dlg.menubox_border.atr = A_NORMAL;
     39	dlg.item.atr = A_NORMAL;
     40	dlg.item_selected.atr = A_REVERSE;
     41	dlg.tag.atr = A_BOLD;
     42	dlg.tag_selected.atr = A_REVERSE;
     43	dlg.tag_key.atr = A_BOLD;
     44	dlg.tag_key_selected.atr = A_REVERSE;
     45	dlg.check.atr = A_BOLD;
     46	dlg.check_selected.atr = A_REVERSE;
     47	dlg.uarrow.atr = A_BOLD;
     48	dlg.darrow.atr = A_BOLD;
     49}
     50
     51#define DLG_COLOR(dialog, f, b, h) \
     52do {                               \
     53	dlg.dialog.fg = (f);       \
     54	dlg.dialog.bg = (b);       \
     55	dlg.dialog.hl = (h);       \
     56} while (0)
     57
     58static void set_classic_theme(void)
     59{
     60	DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
     61	DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
     62	DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
     63	DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
     64	DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
     65	DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
     66	DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
     67	DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
     68	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
     69	DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
     70	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
     71	DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
     72	DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
     73	DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
     74	DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
     75	DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
     76	DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
     77	DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
     78	DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
     79	DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
     80	DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
     81	DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
     82	DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
     83	DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
     84	DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
     85	DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
     86	DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
     87	DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
     88	DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
     89}
     90
     91static void set_blackbg_theme(void)
     92{
     93	DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
     94	DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
     95	DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
     96	DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
     97	DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
     98
     99	DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
    100	DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
    101	DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
    102	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
    103	DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
    104	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
    105
    106	DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
    107	DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
    108
    109	DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
    110	DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
    111	DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
    112
    113	DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
    114
    115	DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
    116	DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
    117
    118	DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
    119	DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
    120
    121	DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
    122	DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
    123	DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
    124	DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
    125
    126	DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
    127	DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
    128
    129	DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
    130	DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
    131}
    132
    133static void set_bluetitle_theme(void)
    134{
    135	set_classic_theme();
    136	DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
    137	DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
    138	DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
    139	DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
    140	DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
    141	DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
    142	DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
    143
    144}
    145
    146/*
    147 * Select color theme
    148 */
    149static int set_theme(const char *theme)
    150{
    151	int use_color = 1;
    152	if (!theme)
    153		set_bluetitle_theme();
    154	else if (strcmp(theme, "classic") == 0)
    155		set_classic_theme();
    156	else if (strcmp(theme, "bluetitle") == 0)
    157		set_bluetitle_theme();
    158	else if (strcmp(theme, "blackbg") == 0)
    159		set_blackbg_theme();
    160	else if (strcmp(theme, "mono") == 0)
    161		use_color = 0;
    162
    163	return use_color;
    164}
    165
    166static void init_one_color(struct dialog_color *color)
    167{
    168	static int pair = 0;
    169
    170	pair++;
    171	init_pair(pair, color->fg, color->bg);
    172	if (color->hl)
    173		color->atr = A_BOLD | COLOR_PAIR(pair);
    174	else
    175		color->atr = COLOR_PAIR(pair);
    176}
    177
    178static void init_dialog_colors(void)
    179{
    180	init_one_color(&dlg.screen);
    181	init_one_color(&dlg.shadow);
    182	init_one_color(&dlg.dialog);
    183	init_one_color(&dlg.title);
    184	init_one_color(&dlg.border);
    185	init_one_color(&dlg.button_active);
    186	init_one_color(&dlg.button_inactive);
    187	init_one_color(&dlg.button_key_active);
    188	init_one_color(&dlg.button_key_inactive);
    189	init_one_color(&dlg.button_label_active);
    190	init_one_color(&dlg.button_label_inactive);
    191	init_one_color(&dlg.inputbox);
    192	init_one_color(&dlg.inputbox_border);
    193	init_one_color(&dlg.searchbox);
    194	init_one_color(&dlg.searchbox_title);
    195	init_one_color(&dlg.searchbox_border);
    196	init_one_color(&dlg.position_indicator);
    197	init_one_color(&dlg.menubox);
    198	init_one_color(&dlg.menubox_border);
    199	init_one_color(&dlg.item);
    200	init_one_color(&dlg.item_selected);
    201	init_one_color(&dlg.tag);
    202	init_one_color(&dlg.tag_selected);
    203	init_one_color(&dlg.tag_key);
    204	init_one_color(&dlg.tag_key_selected);
    205	init_one_color(&dlg.check);
    206	init_one_color(&dlg.check_selected);
    207	init_one_color(&dlg.uarrow);
    208	init_one_color(&dlg.darrow);
    209}
    210
    211/*
    212 * Setup for color display
    213 */
    214static void color_setup(const char *theme)
    215{
    216	int use_color;
    217
    218	use_color = set_theme(theme);
    219	if (use_color && has_colors()) {
    220		start_color();
    221		init_dialog_colors();
    222	} else
    223		set_mono_theme();
    224}
    225
    226/*
    227 * Set window to attribute 'attr'
    228 */
    229void attr_clear(WINDOW * win, int height, int width, chtype attr)
    230{
    231	int i, j;
    232
    233	wattrset(win, attr);
    234	for (i = 0; i < height; i++) {
    235		wmove(win, i, 0);
    236		for (j = 0; j < width; j++)
    237			waddch(win, ' ');
    238	}
    239	touchwin(win);
    240}
    241
    242void dialog_clear(void)
    243{
    244	int lines, columns;
    245
    246	lines = getmaxy(stdscr);
    247	columns = getmaxx(stdscr);
    248
    249	attr_clear(stdscr, lines, columns, dlg.screen.atr);
    250	/* Display background title if it exists ... - SLH */
    251	if (dlg.backtitle != NULL) {
    252		int i, len = 0, skip = 0;
    253		struct subtitle_list *pos;
    254
    255		wattrset(stdscr, dlg.screen.atr);
    256		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
    257
    258		for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
    259			/* 3 is for the arrow and spaces */
    260			len += strlen(pos->text) + 3;
    261		}
    262
    263		wmove(stdscr, 1, 1);
    264		if (len > columns - 2) {
    265			const char *ellipsis = "[...] ";
    266			waddstr(stdscr, ellipsis);
    267			skip = len - (columns - 2 - strlen(ellipsis));
    268		}
    269
    270		for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
    271			if (skip == 0)
    272				waddch(stdscr, ACS_RARROW);
    273			else
    274				skip--;
    275
    276			if (skip == 0)
    277				waddch(stdscr, ' ');
    278			else
    279				skip--;
    280
    281			if (skip < strlen(pos->text)) {
    282				waddstr(stdscr, pos->text + skip);
    283				skip = 0;
    284			} else
    285				skip -= strlen(pos->text);
    286
    287			if (skip == 0)
    288				waddch(stdscr, ' ');
    289			else
    290				skip--;
    291		}
    292
    293		for (i = len + 1; i < columns - 1; i++)
    294			waddch(stdscr, ACS_HLINE);
    295	}
    296	wnoutrefresh(stdscr);
    297}
    298
    299/*
    300 * Do some initialization for dialog
    301 */
    302int init_dialog(const char *backtitle)
    303{
    304	int height, width;
    305
    306	initscr();		/* Init curses */
    307
    308	/* Get current cursor position for signal handler in mconf.c */
    309	getyx(stdscr, saved_y, saved_x);
    310
    311	getmaxyx(stdscr, height, width);
    312	if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
    313		endwin();
    314		return -ERRDISPLAYTOOSMALL;
    315	}
    316
    317	dlg.backtitle = backtitle;
    318	color_setup(getenv("MENUCONFIG_COLOR"));
    319
    320	keypad(stdscr, TRUE);
    321	cbreak();
    322	noecho();
    323	dialog_clear();
    324
    325	return 0;
    326}
    327
    328void set_dialog_backtitle(const char *backtitle)
    329{
    330	dlg.backtitle = backtitle;
    331}
    332
    333void set_dialog_subtitles(struct subtitle_list *subtitles)
    334{
    335	dlg.subtitles = subtitles;
    336}
    337
    338/*
    339 * End using dialog functions.
    340 */
    341void end_dialog(int x, int y)
    342{
    343	/* move cursor back to original position */
    344	move(y, x);
    345	refresh();
    346	endwin();
    347}
    348
    349/* Print the title of the dialog. Center the title and truncate
    350 * tile if wider than dialog (- 2 chars).
    351 **/
    352void print_title(WINDOW *dialog, const char *title, int width)
    353{
    354	if (title) {
    355		int tlen = MIN(width - 2, strlen(title));
    356		wattrset(dialog, dlg.title.atr);
    357		mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
    358		mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
    359		waddch(dialog, ' ');
    360	}
    361}
    362
    363/*
    364 * Print a string of text in a window, automatically wrap around to the
    365 * next line if the string is too long to fit on one line. Newline
    366 * characters '\n' are properly processed.  We start on a new line
    367 * if there is no room for at least 4 nonblanks following a double-space.
    368 */
    369void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
    370{
    371	int newl, cur_x, cur_y;
    372	int prompt_len, room, wlen;
    373	char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
    374
    375	strcpy(tempstr, prompt);
    376
    377	prompt_len = strlen(tempstr);
    378
    379	if (prompt_len <= width - x * 2) {	/* If prompt is short */
    380		wmove(win, y, (width - prompt_len) / 2);
    381		waddstr(win, tempstr);
    382	} else {
    383		cur_x = x;
    384		cur_y = y;
    385		newl = 1;
    386		word = tempstr;
    387		while (word && *word) {
    388			sp = strpbrk(word, "\n ");
    389			if (sp && *sp == '\n')
    390				newline_separator = sp;
    391
    392			if (sp)
    393				*sp++ = 0;
    394
    395			/* Wrap to next line if either the word does not fit,
    396			   or it is the first word of a new sentence, and it is
    397			   short, and the next word does not fit. */
    398			room = width - cur_x;
    399			wlen = strlen(word);
    400			if (wlen > room ||
    401			    (newl && wlen < 4 && sp
    402			     && wlen + 1 + strlen(sp) > room
    403			     && (!(sp2 = strpbrk(sp, "\n "))
    404				 || wlen + 1 + (sp2 - sp) > room))) {
    405				cur_y++;
    406				cur_x = x;
    407			}
    408			wmove(win, cur_y, cur_x);
    409			waddstr(win, word);
    410			getyx(win, cur_y, cur_x);
    411
    412			/* Move to the next line if the word separator was a newline */
    413			if (newline_separator) {
    414				cur_y++;
    415				cur_x = x;
    416				newline_separator = 0;
    417			} else
    418				cur_x++;
    419
    420			if (sp && *sp == ' ') {
    421				cur_x++;	/* double space */
    422				while (*++sp == ' ') ;
    423				newl = 1;
    424			} else
    425				newl = 0;
    426			word = sp;
    427		}
    428	}
    429}
    430
    431/*
    432 * Print a button
    433 */
    434void print_button(WINDOW * win, const char *label, int y, int x, int selected)
    435{
    436	int i, temp;
    437
    438	wmove(win, y, x);
    439	wattrset(win, selected ? dlg.button_active.atr
    440		 : dlg.button_inactive.atr);
    441	waddstr(win, "<");
    442	temp = strspn(label, " ");
    443	label += temp;
    444	wattrset(win, selected ? dlg.button_label_active.atr
    445		 : dlg.button_label_inactive.atr);
    446	for (i = 0; i < temp; i++)
    447		waddch(win, ' ');
    448	wattrset(win, selected ? dlg.button_key_active.atr
    449		 : dlg.button_key_inactive.atr);
    450	waddch(win, label[0]);
    451	wattrset(win, selected ? dlg.button_label_active.atr
    452		 : dlg.button_label_inactive.atr);
    453	waddstr(win, (char *)label + 1);
    454	wattrset(win, selected ? dlg.button_active.atr
    455		 : dlg.button_inactive.atr);
    456	waddstr(win, ">");
    457	wmove(win, y, x + temp + 1);
    458}
    459
    460/*
    461 * Draw a rectangular box with line drawing characters
    462 */
    463void
    464draw_box(WINDOW * win, int y, int x, int height, int width,
    465	 chtype box, chtype border)
    466{
    467	int i, j;
    468
    469	wattrset(win, 0);
    470	for (i = 0; i < height; i++) {
    471		wmove(win, y + i, x);
    472		for (j = 0; j < width; j++)
    473			if (!i && !j)
    474				waddch(win, border | ACS_ULCORNER);
    475			else if (i == height - 1 && !j)
    476				waddch(win, border | ACS_LLCORNER);
    477			else if (!i && j == width - 1)
    478				waddch(win, box | ACS_URCORNER);
    479			else if (i == height - 1 && j == width - 1)
    480				waddch(win, box | ACS_LRCORNER);
    481			else if (!i)
    482				waddch(win, border | ACS_HLINE);
    483			else if (i == height - 1)
    484				waddch(win, box | ACS_HLINE);
    485			else if (!j)
    486				waddch(win, border | ACS_VLINE);
    487			else if (j == width - 1)
    488				waddch(win, box | ACS_VLINE);
    489			else
    490				waddch(win, box | ' ');
    491	}
    492}
    493
    494/*
    495 * Draw shadows along the right and bottom edge to give a more 3D look
    496 * to the boxes
    497 */
    498void draw_shadow(WINDOW * win, int y, int x, int height, int width)
    499{
    500	int i;
    501
    502	if (has_colors()) {	/* Whether terminal supports color? */
    503		wattrset(win, dlg.shadow.atr);
    504		wmove(win, y + height, x + 2);
    505		for (i = 0; i < width; i++)
    506			waddch(win, winch(win) & A_CHARTEXT);
    507		for (i = y + 1; i < y + height + 1; i++) {
    508			wmove(win, i, x + width);
    509			waddch(win, winch(win) & A_CHARTEXT);
    510			waddch(win, winch(win) & A_CHARTEXT);
    511		}
    512		wnoutrefresh(win);
    513	}
    514}
    515
    516/*
    517 *  Return the position of the first alphabetic character in a string.
    518 */
    519int first_alpha(const char *string, const char *exempt)
    520{
    521	int i, in_paren = 0, c;
    522
    523	for (i = 0; i < strlen(string); i++) {
    524		c = tolower(string[i]);
    525
    526		if (strchr("<[(", c))
    527			++in_paren;
    528		if (strchr(">])", c) && in_paren > 0)
    529			--in_paren;
    530
    531		if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
    532			return i;
    533	}
    534
    535	return 0;
    536}
    537
    538/*
    539 * ncurses uses ESC to detect escaped char sequences. This resutl in
    540 * a small timeout before ESC is actually delivered to the application.
    541 * lxdialog suggest <ESC> <ESC> which is correctly translated to two
    542 * times esc. But then we need to ignore the second esc to avoid stepping
    543 * out one menu too much. Filter away all escaped key sequences since
    544 * keypad(FALSE) turn off ncurses support for escape sequences - and that's
    545 * needed to make notimeout() do as expected.
    546 */
    547int on_key_esc(WINDOW *win)
    548{
    549	int key;
    550	int key2;
    551	int key3;
    552
    553	nodelay(win, TRUE);
    554	keypad(win, FALSE);
    555	key = wgetch(win);
    556	key2 = wgetch(win);
    557	do {
    558		key3 = wgetch(win);
    559	} while (key3 != ERR);
    560	nodelay(win, FALSE);
    561	keypad(win, TRUE);
    562	if (key == KEY_ESC && key2 == ERR)
    563		return KEY_ESC;
    564	else if (key != ERR && key != KEY_ESC && key2 == ERR)
    565		ungetch(key);
    566
    567	return -1;
    568}
    569
    570/* redraw screen in new size */
    571int on_key_resize(void)
    572{
    573	dialog_clear();
    574	return KEY_RESIZE;
    575}
    576
    577struct dialog_list *item_cur;
    578struct dialog_list item_nil;
    579struct dialog_list *item_head;
    580
    581void item_reset(void)
    582{
    583	struct dialog_list *p, *next;
    584
    585	for (p = item_head; p; p = next) {
    586		next = p->next;
    587		free(p);
    588	}
    589	item_head = NULL;
    590	item_cur = &item_nil;
    591}
    592
    593void item_make(const char *fmt, ...)
    594{
    595	va_list ap;
    596	struct dialog_list *p = malloc(sizeof(*p));
    597
    598	if (item_head)
    599		item_cur->next = p;
    600	else
    601		item_head = p;
    602	item_cur = p;
    603	memset(p, 0, sizeof(*p));
    604
    605	va_start(ap, fmt);
    606	vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
    607	va_end(ap);
    608}
    609
    610void item_add_str(const char *fmt, ...)
    611{
    612	va_list ap;
    613	size_t avail;
    614
    615	avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
    616
    617	va_start(ap, fmt);
    618	vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
    619		  avail, fmt, ap);
    620	item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
    621	va_end(ap);
    622}
    623
    624void item_set_tag(char tag)
    625{
    626	item_cur->node.tag = tag;
    627}
    628void item_set_data(void *ptr)
    629{
    630	item_cur->node.data = ptr;
    631}
    632
    633void item_set_selected(int val)
    634{
    635	item_cur->node.selected = val;
    636}
    637
    638int item_activate_selected(void)
    639{
    640	item_foreach()
    641		if (item_is_selected())
    642			return 1;
    643	return 0;
    644}
    645
    646void *item_data(void)
    647{
    648	return item_cur->node.data;
    649}
    650
    651char item_tag(void)
    652{
    653	return item_cur->node.tag;
    654}
    655
    656int item_count(void)
    657{
    658	int n = 0;
    659	struct dialog_list *p;
    660
    661	for (p = item_head; p; p = p->next)
    662		n++;
    663	return n;
    664}
    665
    666void item_set(int n)
    667{
    668	int i = 0;
    669	item_foreach()
    670		if (i++ == n)
    671			return;
    672}
    673
    674int item_n(void)
    675{
    676	int n = 0;
    677	struct dialog_list *p;
    678
    679	for (p = item_head; p; p = p->next) {
    680		if (p == item_cur)
    681			return n;
    682		n++;
    683	}
    684	return 0;
    685}
    686
    687const char *item_str(void)
    688{
    689	return item_cur->node.str;
    690}
    691
    692int item_is_selected(void)
    693{
    694	return (item_cur->node.selected != 0);
    695}
    696
    697int item_is_tag(char tag)
    698{
    699	return (item_cur->node.tag == tag);
    700}