kconfig/lxdialog/util.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Feb 17 22:08:06 2008 +0000 (2008-02-17)
changeset 431 8bde4c6ea47a
child 943 1cca90ce0481
permissions -rw-r--r--
Robert P. J. DAY says:

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