Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / tools / 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  *  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 struct dialog_info dlg;
27
28 static 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) \
62 do {                               \
63         dlg.dialog.fg = (f);       \
64         dlg.dialog.bg = (b);       \
65         dlg.dialog.hl = (h);       \
66 } while (0)
67
68 static 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
101 static 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
143 static 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  */
159 static 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
176 static 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
188 static 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  */
224 static 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  */
239 void 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
252 void 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  */
271 int 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
293 void set_dialog_backtitle(const char *backtitle)
294 {
295         dlg.backtitle = backtitle;
296 }
297
298 /*
299  * End using dialog functions.
300  */
301 void 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  **/
312 void 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  */
329 void 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  */
391 void 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  */
420 void
421 draw_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  */
455 void 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  */
476 int 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  */
504 int 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 */
528 int on_key_resize(void)
529 {
530         dialog_clear();
531         return KEY_RESIZE;
532 }
533
534 struct dialog_list *item_cur;
535 struct dialog_list item_nil;
536 struct dialog_list *item_head;
537
538 void 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
550 void 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
567 void 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
581 void item_set_tag(char tag)
582 {
583         item_cur->node.tag = tag;
584 }
585 void item_set_data(void *ptr)
586 {
587         item_cur->node.data = ptr;
588 }
589
590 void item_set_selected(int val)
591 {
592         item_cur->node.selected = val;
593 }
594
595 int item_activate_selected(void)
596 {
597         item_foreach()
598                 if (item_is_selected())
599                         return 1;
600         return 0;
601 }
602
603 void *item_data(void)
604 {
605         return item_cur->node.data;
606 }
607
608 char item_tag(void)
609 {
610         return item_cur->node.tag;
611 }
612
613 int 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
623 void item_set(int n)
624 {
625         int i = 0;
626         item_foreach()
627                 if (i++ == n)
628                         return;
629 }
630
631 int 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
644 const char *item_str(void)
645 {
646         return item_cur->node.str;
647 }
648
649 int item_is_selected(void)
650 {
651         return (item_cur->node.selected != 0);
652 }
653
654 int item_is_tag(char tag)
655 {
656         return (item_cur->node.tag == tag);
657 }