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