]> git.sur5r.net Git - u-boot/blob - scripts/kconfig/lxdialog/util.c
Add more SPDX-License-Identifier tags
[u-boot] / scripts / kconfig / lxdialog / util.c
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 */
15 int saved_x, saved_y;
16
17 struct dialog_info dlg;
18
19 static 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) \
53 do {                               \
54         dlg.dialog.fg = (f);       \
55         dlg.dialog.bg = (b);       \
56         dlg.dialog.hl = (h);       \
57 } while (0)
58
59 static 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
92 static 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
134 static 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  */
150 static 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
167 static 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
179 static 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  */
215 static 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  */
230 void 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
243 void 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  */
303 int 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
329 void set_dialog_backtitle(const char *backtitle)
330 {
331         dlg.backtitle = backtitle;
332 }
333
334 void set_dialog_subtitles(struct subtitle_list *subtitles)
335 {
336         dlg.subtitles = subtitles;
337 }
338
339 /*
340  * End using dialog functions.
341  */
342 void 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  **/
353 void 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  */
370 void 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  */
435 void 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  */
464 void
465 draw_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  */
499 void 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  */
520 int 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  */
548 int 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 */
572 int on_key_resize(void)
573 {
574         dialog_clear();
575         return KEY_RESIZE;
576 }
577
578 struct dialog_list *item_cur;
579 struct dialog_list item_nil;
580 struct dialog_list *item_head;
581
582 void 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
594 void 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
611 void 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
625 void item_set_tag(char tag)
626 {
627         item_cur->node.tag = tag;
628 }
629 void item_set_data(void *ptr)
630 {
631         item_cur->node.data = ptr;
632 }
633
634 void item_set_selected(int val)
635 {
636         item_cur->node.selected = val;
637 }
638
639 int item_activate_selected(void)
640 {
641         item_foreach()
642                 if (item_is_selected())
643                         return 1;
644         return 0;
645 }
646
647 void *item_data(void)
648 {
649         return item_cur->node.data;
650 }
651
652 char item_tag(void)
653 {
654         return item_cur->node.tag;
655 }
656
657 int 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
667 void item_set(int n)
668 {
669         int i = 0;
670         item_foreach()
671                 if (i++ == n)
672                         return;
673 }
674
675 int 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
688 const char *item_str(void)
689 {
690         return item_cur->node.str;
691 }
692
693 int item_is_selected(void)
694 {
695         return (item_cur->node.selected != 0);
696 }
697
698 int item_is_tag(char tag)
699 {
700         return (item_cur->node.tag == tag);
701 }