Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  util.c
0004  *
0005  *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
0006  *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
0007  */
0008 
0009 #include <stdarg.h>
0010 
0011 #include "dialog.h"
0012 
0013 /* Needed in signal handler in mconf.c */
0014 int saved_x, saved_y;
0015 
0016 struct dialog_info dlg;
0017 
0018 static void set_mono_theme(void)
0019 {
0020     dlg.screen.atr = A_NORMAL;
0021     dlg.shadow.atr = A_NORMAL;
0022     dlg.dialog.atr = A_NORMAL;
0023     dlg.title.atr = A_BOLD;
0024     dlg.border.atr = A_NORMAL;
0025     dlg.button_active.atr = A_REVERSE;
0026     dlg.button_inactive.atr = A_DIM;
0027     dlg.button_key_active.atr = A_REVERSE;
0028     dlg.button_key_inactive.atr = A_BOLD;
0029     dlg.button_label_active.atr = A_REVERSE;
0030     dlg.button_label_inactive.atr = A_NORMAL;
0031     dlg.inputbox.atr = A_NORMAL;
0032     dlg.inputbox_border.atr = A_NORMAL;
0033     dlg.searchbox.atr = A_NORMAL;
0034     dlg.searchbox_title.atr = A_BOLD;
0035     dlg.searchbox_border.atr = A_NORMAL;
0036     dlg.position_indicator.atr = A_BOLD;
0037     dlg.menubox.atr = A_NORMAL;
0038     dlg.menubox_border.atr = A_NORMAL;
0039     dlg.item.atr = A_NORMAL;
0040     dlg.item_selected.atr = A_REVERSE;
0041     dlg.tag.atr = A_BOLD;
0042     dlg.tag_selected.atr = A_REVERSE;
0043     dlg.tag_key.atr = A_BOLD;
0044     dlg.tag_key_selected.atr = A_REVERSE;
0045     dlg.check.atr = A_BOLD;
0046     dlg.check_selected.atr = A_REVERSE;
0047     dlg.uarrow.atr = A_BOLD;
0048     dlg.darrow.atr = A_BOLD;
0049 }
0050 
0051 #define DLG_COLOR(dialog, f, b, h) \
0052 do {                               \
0053     dlg.dialog.fg = (f);       \
0054     dlg.dialog.bg = (b);       \
0055     dlg.dialog.hl = (h);       \
0056 } while (0)
0057 
0058 static void set_classic_theme(void)
0059 {
0060     DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
0061     DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
0062     DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
0063     DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
0064     DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
0065     DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
0066     DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
0067     DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
0068     DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
0069     DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
0070     DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
0071     DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
0072     DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
0073     DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
0074     DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
0075     DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
0076     DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
0077     DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
0078     DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
0079     DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
0080     DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
0081     DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
0082     DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
0083     DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
0084     DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
0085     DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
0086     DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
0087     DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
0088     DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
0089 }
0090 
0091 static void set_blackbg_theme(void)
0092 {
0093     DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
0094     DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
0095     DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
0096     DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
0097     DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
0098 
0099     DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
0100     DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
0101     DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
0102     DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
0103     DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
0104     DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
0105 
0106     DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
0107     DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
0108 
0109     DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
0110     DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
0111     DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
0112 
0113     DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
0114 
0115     DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
0116     DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
0117 
0118     DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
0119     DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
0120 
0121     DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
0122     DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
0123     DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
0124     DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
0125 
0126     DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
0127     DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
0128 
0129     DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
0130     DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
0131 }
0132 
0133 static void set_bluetitle_theme(void)
0134 {
0135     set_classic_theme();
0136     DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
0137     DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
0138     DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
0139     DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
0140     DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
0141     DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
0142     DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
0143 
0144 }
0145 
0146 /*
0147  * Select color theme
0148  */
0149 static int set_theme(const char *theme)
0150 {
0151     int use_color = 1;
0152     if (!theme)
0153         set_bluetitle_theme();
0154     else if (strcmp(theme, "classic") == 0)
0155         set_classic_theme();
0156     else if (strcmp(theme, "bluetitle") == 0)
0157         set_bluetitle_theme();
0158     else if (strcmp(theme, "blackbg") == 0)
0159         set_blackbg_theme();
0160     else if (strcmp(theme, "mono") == 0)
0161         use_color = 0;
0162 
0163     return use_color;
0164 }
0165 
0166 static void init_one_color(struct dialog_color *color)
0167 {
0168     static int pair = 0;
0169 
0170     pair++;
0171     init_pair(pair, color->fg, color->bg);
0172     if (color->hl)
0173         color->atr = A_BOLD | COLOR_PAIR(pair);
0174     else
0175         color->atr = COLOR_PAIR(pair);
0176 }
0177 
0178 static void init_dialog_colors(void)
0179 {
0180     init_one_color(&dlg.screen);
0181     init_one_color(&dlg.shadow);
0182     init_one_color(&dlg.dialog);
0183     init_one_color(&dlg.title);
0184     init_one_color(&dlg.border);
0185     init_one_color(&dlg.button_active);
0186     init_one_color(&dlg.button_inactive);
0187     init_one_color(&dlg.button_key_active);
0188     init_one_color(&dlg.button_key_inactive);
0189     init_one_color(&dlg.button_label_active);
0190     init_one_color(&dlg.button_label_inactive);
0191     init_one_color(&dlg.inputbox);
0192     init_one_color(&dlg.inputbox_border);
0193     init_one_color(&dlg.searchbox);
0194     init_one_color(&dlg.searchbox_title);
0195     init_one_color(&dlg.searchbox_border);
0196     init_one_color(&dlg.position_indicator);
0197     init_one_color(&dlg.menubox);
0198     init_one_color(&dlg.menubox_border);
0199     init_one_color(&dlg.item);
0200     init_one_color(&dlg.item_selected);
0201     init_one_color(&dlg.tag);
0202     init_one_color(&dlg.tag_selected);
0203     init_one_color(&dlg.tag_key);
0204     init_one_color(&dlg.tag_key_selected);
0205     init_one_color(&dlg.check);
0206     init_one_color(&dlg.check_selected);
0207     init_one_color(&dlg.uarrow);
0208     init_one_color(&dlg.darrow);
0209 }
0210 
0211 /*
0212  * Setup for color display
0213  */
0214 static void color_setup(const char *theme)
0215 {
0216     int use_color;
0217 
0218     use_color = set_theme(theme);
0219     if (use_color && has_colors()) {
0220         start_color();
0221         init_dialog_colors();
0222     } else
0223         set_mono_theme();
0224 }
0225 
0226 /*
0227  * Set window to attribute 'attr'
0228  */
0229 void attr_clear(WINDOW * win, int height, int width, chtype attr)
0230 {
0231     int i, j;
0232 
0233     wattrset(win, attr);
0234     for (i = 0; i < height; i++) {
0235         wmove(win, i, 0);
0236         for (j = 0; j < width; j++)
0237             waddch(win, ' ');
0238     }
0239     touchwin(win);
0240 }
0241 
0242 void dialog_clear(void)
0243 {
0244     int lines, columns;
0245 
0246     lines = getmaxy(stdscr);
0247     columns = getmaxx(stdscr);
0248 
0249     attr_clear(stdscr, lines, columns, dlg.screen.atr);
0250     /* Display background title if it exists ... - SLH */
0251     if (dlg.backtitle != NULL) {
0252         int i, len = 0, skip = 0;
0253         struct subtitle_list *pos;
0254 
0255         wattrset(stdscr, dlg.screen.atr);
0256         mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
0257 
0258         for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
0259             /* 3 is for the arrow and spaces */
0260             len += strlen(pos->text) + 3;
0261         }
0262 
0263         wmove(stdscr, 1, 1);
0264         if (len > columns - 2) {
0265             const char *ellipsis = "[...] ";
0266             waddstr(stdscr, ellipsis);
0267             skip = len - (columns - 2 - strlen(ellipsis));
0268         }
0269 
0270         for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
0271             if (skip == 0)
0272                 waddch(stdscr, ACS_RARROW);
0273             else
0274                 skip--;
0275 
0276             if (skip == 0)
0277                 waddch(stdscr, ' ');
0278             else
0279                 skip--;
0280 
0281             if (skip < strlen(pos->text)) {
0282                 waddstr(stdscr, pos->text + skip);
0283                 skip = 0;
0284             } else
0285                 skip -= strlen(pos->text);
0286 
0287             if (skip == 0)
0288                 waddch(stdscr, ' ');
0289             else
0290                 skip--;
0291         }
0292 
0293         for (i = len + 1; i < columns - 1; i++)
0294             waddch(stdscr, ACS_HLINE);
0295     }
0296     wnoutrefresh(stdscr);
0297 }
0298 
0299 /*
0300  * Do some initialization for dialog
0301  */
0302 int init_dialog(const char *backtitle)
0303 {
0304     int height, width;
0305 
0306     initscr();      /* Init curses */
0307 
0308     /* Get current cursor position for signal handler in mconf.c */
0309     getyx(stdscr, saved_y, saved_x);
0310 
0311     getmaxyx(stdscr, height, width);
0312     if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
0313         endwin();
0314         return -ERRDISPLAYTOOSMALL;
0315     }
0316 
0317     dlg.backtitle = backtitle;
0318     color_setup(getenv("MENUCONFIG_COLOR"));
0319 
0320     keypad(stdscr, TRUE);
0321     cbreak();
0322     noecho();
0323     dialog_clear();
0324 
0325     return 0;
0326 }
0327 
0328 void set_dialog_backtitle(const char *backtitle)
0329 {
0330     dlg.backtitle = backtitle;
0331 }
0332 
0333 void set_dialog_subtitles(struct subtitle_list *subtitles)
0334 {
0335     dlg.subtitles = subtitles;
0336 }
0337 
0338 /*
0339  * End using dialog functions.
0340  */
0341 void end_dialog(int x, int y)
0342 {
0343     /* move cursor back to original position */
0344     move(y, x);
0345     refresh();
0346     endwin();
0347 }
0348 
0349 /* Print the title of the dialog. Center the title and truncate
0350  * tile if wider than dialog (- 2 chars).
0351  **/
0352 void print_title(WINDOW *dialog, const char *title, int width)
0353 {
0354     if (title) {
0355         int tlen = MIN(width - 2, strlen(title));
0356         wattrset(dialog, dlg.title.atr);
0357         mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
0358         mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
0359         waddch(dialog, ' ');
0360     }
0361 }
0362 
0363 /*
0364  * Print a string of text in a window, automatically wrap around to the
0365  * next line if the string is too long to fit on one line. Newline
0366  * characters '\n' are properly processed.  We start on a new line
0367  * if there is no room for at least 4 nonblanks following a double-space.
0368  */
0369 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
0370 {
0371     int newl, cur_x, cur_y;
0372     int prompt_len, room, wlen;
0373     char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
0374 
0375     strcpy(tempstr, prompt);
0376 
0377     prompt_len = strlen(tempstr);
0378 
0379     if (prompt_len <= width - x * 2) {  /* If prompt is short */
0380         wmove(win, y, (width - prompt_len) / 2);
0381         waddstr(win, tempstr);
0382     } else {
0383         cur_x = x;
0384         cur_y = y;
0385         newl = 1;
0386         word = tempstr;
0387         while (word && *word) {
0388             sp = strpbrk(word, "\n ");
0389             if (sp && *sp == '\n')
0390                 newline_separator = sp;
0391 
0392             if (sp)
0393                 *sp++ = 0;
0394 
0395             /* Wrap to next line if either the word does not fit,
0396                or it is the first word of a new sentence, and it is
0397                short, and the next word does not fit. */
0398             room = width - cur_x;
0399             wlen = strlen(word);
0400             if (wlen > room ||
0401                 (newl && wlen < 4 && sp
0402                  && wlen + 1 + strlen(sp) > room
0403                  && (!(sp2 = strpbrk(sp, "\n "))
0404                  || wlen + 1 + (sp2 - sp) > room))) {
0405                 cur_y++;
0406                 cur_x = x;
0407             }
0408             wmove(win, cur_y, cur_x);
0409             waddstr(win, word);
0410             getyx(win, cur_y, cur_x);
0411 
0412             /* Move to the next line if the word separator was a newline */
0413             if (newline_separator) {
0414                 cur_y++;
0415                 cur_x = x;
0416                 newline_separator = 0;
0417             } else
0418                 cur_x++;
0419 
0420             if (sp && *sp == ' ') {
0421                 cur_x++;    /* double space */
0422                 while (*++sp == ' ') ;
0423                 newl = 1;
0424             } else
0425                 newl = 0;
0426             word = sp;
0427         }
0428     }
0429 }
0430 
0431 /*
0432  * Print a button
0433  */
0434 void print_button(WINDOW * win, const char *label, int y, int x, int selected)
0435 {
0436     int i, temp;
0437 
0438     wmove(win, y, x);
0439     wattrset(win, selected ? dlg.button_active.atr
0440          : dlg.button_inactive.atr);
0441     waddstr(win, "<");
0442     temp = strspn(label, " ");
0443     label += temp;
0444     wattrset(win, selected ? dlg.button_label_active.atr
0445          : dlg.button_label_inactive.atr);
0446     for (i = 0; i < temp; i++)
0447         waddch(win, ' ');
0448     wattrset(win, selected ? dlg.button_key_active.atr
0449          : dlg.button_key_inactive.atr);
0450     waddch(win, label[0]);
0451     wattrset(win, selected ? dlg.button_label_active.atr
0452          : dlg.button_label_inactive.atr);
0453     waddstr(win, (char *)label + 1);
0454     wattrset(win, selected ? dlg.button_active.atr
0455          : dlg.button_inactive.atr);
0456     waddstr(win, ">");
0457     wmove(win, y, x + temp + 1);
0458 }
0459 
0460 /*
0461  * Draw a rectangular box with line drawing characters
0462  */
0463 void
0464 draw_box(WINDOW * win, int y, int x, int height, int width,
0465      chtype box, chtype border)
0466 {
0467     int i, j;
0468 
0469     wattrset(win, 0);
0470     for (i = 0; i < height; i++) {
0471         wmove(win, y + i, x);
0472         for (j = 0; j < width; j++)
0473             if (!i && !j)
0474                 waddch(win, border | ACS_ULCORNER);
0475             else if (i == height - 1 && !j)
0476                 waddch(win, border | ACS_LLCORNER);
0477             else if (!i && j == width - 1)
0478                 waddch(win, box | ACS_URCORNER);
0479             else if (i == height - 1 && j == width - 1)
0480                 waddch(win, box | ACS_LRCORNER);
0481             else if (!i)
0482                 waddch(win, border | ACS_HLINE);
0483             else if (i == height - 1)
0484                 waddch(win, box | ACS_HLINE);
0485             else if (!j)
0486                 waddch(win, border | ACS_VLINE);
0487             else if (j == width - 1)
0488                 waddch(win, box | ACS_VLINE);
0489             else
0490                 waddch(win, box | ' ');
0491     }
0492 }
0493 
0494 /*
0495  * Draw shadows along the right and bottom edge to give a more 3D look
0496  * to the boxes
0497  */
0498 void draw_shadow(WINDOW * win, int y, int x, int height, int width)
0499 {
0500     int i;
0501 
0502     if (has_colors()) { /* Whether terminal supports color? */
0503         wattrset(win, dlg.shadow.atr);
0504         wmove(win, y + height, x + 2);
0505         for (i = 0; i < width; i++)
0506             waddch(win, winch(win) & A_CHARTEXT);
0507         for (i = y + 1; i < y + height + 1; i++) {
0508             wmove(win, i, x + width);
0509             waddch(win, winch(win) & A_CHARTEXT);
0510             waddch(win, winch(win) & A_CHARTEXT);
0511         }
0512         wnoutrefresh(win);
0513     }
0514 }
0515 
0516 /*
0517  *  Return the position of the first alphabetic character in a string.
0518  */
0519 int first_alpha(const char *string, const char *exempt)
0520 {
0521     int i, in_paren = 0, c;
0522 
0523     for (i = 0; i < strlen(string); i++) {
0524         c = tolower(string[i]);
0525 
0526         if (strchr("<[(", c))
0527             ++in_paren;
0528         if (strchr(">])", c) && in_paren > 0)
0529             --in_paren;
0530 
0531         if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
0532             return i;
0533     }
0534 
0535     return 0;
0536 }
0537 
0538 /*
0539  * ncurses uses ESC to detect escaped char sequences. This resutl in
0540  * a small timeout before ESC is actually delivered to the application.
0541  * lxdialog suggest <ESC> <ESC> which is correctly translated to two
0542  * times esc. But then we need to ignore the second esc to avoid stepping
0543  * out one menu too much. Filter away all escaped key sequences since
0544  * keypad(FALSE) turn off ncurses support for escape sequences - and that's
0545  * needed to make notimeout() do as expected.
0546  */
0547 int on_key_esc(WINDOW *win)
0548 {
0549     int key;
0550     int key2;
0551     int key3;
0552 
0553     nodelay(win, TRUE);
0554     keypad(win, FALSE);
0555     key = wgetch(win);
0556     key2 = wgetch(win);
0557     do {
0558         key3 = wgetch(win);
0559     } while (key3 != ERR);
0560     nodelay(win, FALSE);
0561     keypad(win, TRUE);
0562     if (key == KEY_ESC && key2 == ERR)
0563         return KEY_ESC;
0564     else if (key != ERR && key != KEY_ESC && key2 == ERR)
0565         ungetch(key);
0566 
0567     return -1;
0568 }
0569 
0570 /* redraw screen in new size */
0571 int on_key_resize(void)
0572 {
0573     dialog_clear();
0574     return KEY_RESIZE;
0575 }
0576 
0577 struct dialog_list *item_cur;
0578 struct dialog_list item_nil;
0579 struct dialog_list *item_head;
0580 
0581 void item_reset(void)
0582 {
0583     struct dialog_list *p, *next;
0584 
0585     for (p = item_head; p; p = next) {
0586         next = p->next;
0587         free(p);
0588     }
0589     item_head = NULL;
0590     item_cur = &item_nil;
0591 }
0592 
0593 void item_make(const char *fmt, ...)
0594 {
0595     va_list ap;
0596     struct dialog_list *p = malloc(sizeof(*p));
0597 
0598     if (item_head)
0599         item_cur->next = p;
0600     else
0601         item_head = p;
0602     item_cur = p;
0603     memset(p, 0, sizeof(*p));
0604 
0605     va_start(ap, fmt);
0606     vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
0607     va_end(ap);
0608 }
0609 
0610 void item_add_str(const char *fmt, ...)
0611 {
0612     va_list ap;
0613     size_t avail;
0614 
0615     avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
0616 
0617     va_start(ap, fmt);
0618     vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
0619           avail, fmt, ap);
0620     item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
0621     va_end(ap);
0622 }
0623 
0624 void item_set_tag(char tag)
0625 {
0626     item_cur->node.tag = tag;
0627 }
0628 void item_set_data(void *ptr)
0629 {
0630     item_cur->node.data = ptr;
0631 }
0632 
0633 void item_set_selected(int val)
0634 {
0635     item_cur->node.selected = val;
0636 }
0637 
0638 int item_activate_selected(void)
0639 {
0640     item_foreach()
0641         if (item_is_selected())
0642             return 1;
0643     return 0;
0644 }
0645 
0646 void *item_data(void)
0647 {
0648     return item_cur->node.data;
0649 }
0650 
0651 char item_tag(void)
0652 {
0653     return item_cur->node.tag;
0654 }
0655 
0656 int item_count(void)
0657 {
0658     int n = 0;
0659     struct dialog_list *p;
0660 
0661     for (p = item_head; p; p = p->next)
0662         n++;
0663     return n;
0664 }
0665 
0666 void item_set(int n)
0667 {
0668     int i = 0;
0669     item_foreach()
0670         if (i++ == n)
0671             return;
0672 }
0673 
0674 int item_n(void)
0675 {
0676     int n = 0;
0677     struct dialog_list *p;
0678 
0679     for (p = item_head; p; p = p->next) {
0680         if (p == item_cur)
0681             return n;
0682         n++;
0683     }
0684     return 0;
0685 }
0686 
0687 const char *item_str(void)
0688 {
0689     return item_cur->node.str;
0690 }
0691 
0692 int item_is_selected(void)
0693 {
0694     return (item_cur->node.selected != 0);
0695 }
0696 
0697 int item_is_tag(char tag)
0698 {
0699     return (item_cur->node.tag == tag);
0700 }