kconfig/lxdialog/util.c
author "Benoît Thébaudeau" <benoit.thebaudeau@advansee.com>
Mon Apr 16 15:25:36 2012 +0200 (2012-04-16)
changeset 2941 13e40098fffc
parent 943 1cca90ce0481
permissions -rw-r--r--
cc/gcc: update Linaro GCC revisions to 2012.04

Update Linaro GCC with the latest available revisions.

The 4.7 revision is also released, but the infrastructure is not yet ready for
it in CT-NG.

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