linux/scripts/kconfig/lxdialog/util.c
<<
>>
Prefs
   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 propperly 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 thats
 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}
 701