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