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