]> ncurses.scripts.mit.edu Git - ncurses.git/blob - test/demo_menus.c
ncurses 5.9 - patch 20130427
[ncurses.git] / test / demo_menus.c
1 /****************************************************************************
2  * Copyright (c) 2005-2011,2012 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28 /*
29  * $Id: demo_menus.c,v 1.37 2012/11/18 00:18:54 tom Exp $
30  *
31  * Demonstrate a variety of functions from the menu library.
32  * Thomas Dickey - 2005/4/9
33  */
34 /*
35 item_description                -
36 item_init                       -
37 item_opts                       -
38 item_opts_off                   -
39 item_opts_on                    -
40 item_term                       -
41 item_userptr                    -
42 item_visible                    -
43 menu_back                       -
44 menu_fore                       -
45 menu_format                     -
46 menu_grey                       -
47 menu_init                       -
48 menu_opts                       -
49 menu_pad                        -
50 menu_request_by_name            -
51 menu_request_name               -
52 menu_sub                        -
53 menu_term                       -
54 menu_userptr                    -
55 set_current_item                -
56 set_item_init                   -
57 set_item_opts                   -
58 set_item_term                   -
59 set_item_userptr                -
60 set_menu_grey                   -
61 set_menu_init                   -
62 set_menu_items                  -
63 set_menu_opts                   -
64 set_menu_pad                    -
65 set_menu_pattern                -
66 set_menu_spacing                -
67 set_menu_term                   -
68 set_menu_userptr                -
69 set_top_row                     -
70 top_row                         -
71 */
72
73 #include <test.priv.h>
74
75 #if USE_LIBMENU
76
77 #include <menu.h>
78
79 #include <sys/types.h>
80 #include <sys/stat.h>
81
82 #ifdef NCURSES_VERSION
83 #ifdef TRACE
84 static unsigned save_trace = TRACE_ORDINARY | TRACE_CALLS;
85 extern unsigned _nc_tracing;
86 static MENU *mpTrace;
87 #endif
88 #else
89 #undef TRACE
90 #endif
91
92 typedef enum {
93     eBanner = -1
94     ,eFile
95     ,eSelect
96 #ifdef TRACE
97     ,eTrace
98 #endif
99     ,eMAX
100 } MenuNo;
101
102 #define okMenuNo(n) (((n) > eBanner) && ((n) < eMAX))
103
104 #define MENU_Y  1
105
106 static MENU *mpBanner;
107 static MENU *mpFile;
108 static MENU *mpSelect;
109
110 static bool loaded_file = FALSE;
111
112 /* Common function to allow ^T to toggle trace-mode in the middle of a test
113  * so that trace-files can be made smaller.
114  */
115 static int
116 wGetchar(WINDOW *win)
117 {
118     int c;
119 #ifdef TRACE
120     while ((c = wgetch(win)) == CTRL('T')) {
121         if (_nc_tracing) {
122             save_trace = _nc_tracing;
123             Trace(("TOGGLE-TRACING OFF"));
124             _nc_tracing = 0;
125         } else {
126             _nc_tracing = save_trace;
127         }
128         trace(_nc_tracing);
129         if (_nc_tracing)
130             Trace(("TOGGLE-TRACING ON"));
131     }
132 #else
133     c = wgetch(win);
134 #endif
135     return c;
136 }
137 #define Getchar() wGetchar(stdscr)
138
139 static int
140 menu_virtualize(int c)
141 {
142     int result;
143
144     if (c == '\n' || c == KEY_EXIT)
145         result = (MAX_COMMAND + 1);
146     else if (c == 'u')
147         result = (REQ_SCR_ULINE);
148     else if (c == 'd')
149         result = (REQ_SCR_DLINE);
150     else if (c == 'b' || c == KEY_NPAGE)
151         result = (REQ_SCR_UPAGE);
152     else if (c == 'f' || c == KEY_PPAGE)
153         result = (REQ_SCR_DPAGE);
154     else if (c == 'l' || c == KEY_LEFT || c == KEY_BTAB)
155         result = (REQ_LEFT_ITEM);
156     else if (c == 'n' || c == KEY_DOWN)
157         result = (REQ_NEXT_ITEM);
158     else if (c == 'p' || c == KEY_UP)
159         result = (REQ_PREV_ITEM);
160     else if (c == 'r' || c == KEY_RIGHT || c == '\t')
161         result = (REQ_RIGHT_ITEM);
162     else if (c == ' ')
163         result = (REQ_TOGGLE_ITEM);
164     else {
165         if (c != KEY_MOUSE)
166             beep();
167         result = (c);
168     }
169     return result;
170 }
171
172 static int
173 menu_getc(MENU * m)
174 {
175     return wGetchar(menu_win(m));
176 }
177
178 static int
179 menu_offset(MenuNo number)
180 {
181     int result = 0;
182
183     if (okMenuNo(number)) {
184         int spc_desc, spc_rows, spc_cols;
185
186 #ifdef NCURSES_VERSION
187         menu_spacing(mpBanner, &spc_desc, &spc_rows, &spc_cols);
188 #else
189         spc_rows = 0;
190 #endif
191
192         /* FIXME: MENU.itemlen seems the only way to get actual width of items */
193         result = (number - (eBanner + 1)) * (menu_itemwidth(mpBanner) + spc_rows);
194     }
195     return result;
196 }
197
198 static MENU *
199 menu_create(ITEM ** items, int count, int ncols, MenuNo number)
200 {
201     MENU *result;
202     WINDOW *menuwin;
203     int mrows, mcols;
204     int y = okMenuNo(number) ? MENU_Y : 0;
205     int x = menu_offset(number);
206     int margin = (y == MENU_Y) ? 1 : 0;
207     int maxcol = (ncols + x) < COLS ? ncols : (COLS - x - 1);
208     int maxrow = (count + 1) / ncols;
209
210     if ((maxrow + y) >= (LINES - 4))
211         maxrow = LINES - 4 - y;
212
213     result = new_menu(items);
214
215     if (has_colors()) {
216         set_menu_fore(result, (chtype) COLOR_PAIR(1));
217         set_menu_back(result, (chtype) COLOR_PAIR(2));
218     }
219
220     set_menu_format(result, maxrow, maxcol);
221     scale_menu(result, &mrows, &mcols);
222
223     if (mcols + (2 * margin + x) >= COLS)
224         mcols = COLS - (2 * margin + x);
225
226 #ifdef TRACE
227     if (number == eTrace)
228         menu_opts_off(result, O_ONEVALUE);
229     else
230         menu_opts_on(result, O_ONEVALUE);
231 #endif
232
233     menuwin = newwin(mrows + (2 * margin), mcols + (2 * margin), y, x);
234     set_menu_win(result, menuwin);
235     keypad(menuwin, TRUE);
236     if (margin)
237         box(menuwin, 0, 0);
238
239     set_menu_sub(result, derwin(menuwin, mrows, mcols, margin, margin));
240
241     post_menu(result);
242
243     return result;
244 }
245
246 static void
247 menu_destroy(MENU * m)
248 {
249     int count;
250
251     Trace(("menu_destroy %p", (void *) m));
252     if (m != 0) {
253         ITEM **items = menu_items(m);
254         const char *blob = 0;
255
256         count = item_count(m);
257         Trace(("menu_destroy %p count %d", (void *) m, count));
258         if ((count > 0) && (m == mpSelect)) {
259             blob = item_name(*items);
260         }
261
262         unpost_menu(m);
263         free_menu(m);
264
265         /* free the extra data allocated in build_select_menu() */
266         if ((count > 0) && (m == mpSelect)) {
267             if (blob && loaded_file) {
268                 Trace(("freeing blob %p", blob));
269                 free((char *) blob);
270             }
271             free(items);
272             items = 0;
273         }
274 #ifdef TRACE
275         if ((count > 0) && (m == mpTrace)) {
276             ITEM **ip = items;
277             if (ip != 0) {
278                 while (*ip)
279                     free(*ip++);
280             }
281         }
282 #endif
283     }
284 }
285
286 /* force the given menu to appear */
287 static void
288 menu_display(MENU * m)
289 {
290     touchwin(menu_win(m));
291     wrefresh(menu_win(m));
292 }
293
294 /*****************************************************************************/
295
296 static void
297 build_file_menu(MenuNo number)
298 {
299     static CONST_MENUS char *labels[] =
300     {
301         "Exit",
302         (char *) 0
303     };
304     static ITEM *items[SIZEOF(labels)];
305
306     ITEM **ip = items;
307     CONST_MENUS char **ap;
308
309     for (ap = labels; *ap; ap++)
310         *ip++ = new_item(*ap, "");
311     *ip = (ITEM *) 0;
312
313     mpFile = menu_create(items, SIZEOF(labels) - 1, 1, number);
314 }
315
316 static int
317 perform_file_menu(int cmd)
318 {
319     return menu_driver(mpFile, cmd);
320 }
321
322 /*****************************************************************************/
323
324 static void
325 build_select_menu(MenuNo number, char *filename)
326 {
327     static CONST_MENUS char *labels[] =
328     {
329         "Lions",
330         "Tigers",
331         "Bears",
332         "(Oh my!)",
333         "Newts",
334         "Platypi",
335         "Lemurs",
336         "(Oh really?!)",
337         "Leopards",
338         "Panthers",
339         "Pumas",
340         "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs",
341         "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs, Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs",
342         (char *) 0
343     };
344     static ITEM **items;
345
346     ITEM **ip;
347     CONST_MENUS char **ap = 0;
348     CONST_MENUS char **myList = 0;
349     unsigned count = 0;
350
351     if (filename != 0) {
352         struct stat sb;
353         if (stat(filename, &sb) == 0
354             && (sb.st_mode & S_IFMT) == S_IFREG
355             && sb.st_size != 0) {
356             size_t size = (size_t) sb.st_size;
357             unsigned j, k;
358             char *blob = typeMalloc(char, size + 1);
359             CONST_MENUS char **list = typeCalloc(CONST_MENUS char *, size + 1);
360
361             items = typeCalloc(ITEM *, size + 1);
362             Trace(("build_select_menu blob=%p, items=%p",
363                    (void *) blob,
364                    (void *) items));
365             if (blob != 0 && list != 0) {
366                 FILE *fp = fopen(filename, "r");
367                 if (fp != 0) {
368                     if (fread(blob, sizeof(char), size, fp) == size) {
369                         bool mark = TRUE;
370                         for (j = k = 0; j < size; ++j) {
371                             if (mark) {
372                                 list[k++] = blob + j;
373                                 mark = FALSE;
374                             }
375                             if (blob[j] == '\n') {
376                                 blob[j] = '\0';
377                                 if (k > 0 && *list[k - 1] == '\0')
378                                     --k;
379                                 mark = TRUE;
380                             } else if (blob[j] == '\t') {
381                                 blob[j] = ' ';  /* menu items are printable */
382                             }
383                         }
384                         list[k] = 0;
385                         count = k;
386                         ap = myList = list;
387                     }
388                     fclose(fp);
389                 }
390                 loaded_file = TRUE;
391             }
392             if (ap == 0)
393                 free(items);
394         }
395     }
396     if (ap == 0) {
397         count = SIZEOF(labels) - 1;
398         items = typeCalloc(ITEM *, count + 1);
399         ap = labels;
400     }
401
402     ip = items;
403     while (*ap != 0)
404         *ip++ = new_item(*ap++, "");
405     *ip = 0;
406
407     mpSelect = menu_create(items, (int) count, 1, number);
408     if (myList != 0)
409         free(myList);
410 }
411
412 static int
413 perform_select_menu(int cmd)
414 {
415     return menu_driver(mpSelect, cmd);
416 }
417
418 /*****************************************************************************/
419
420 #ifdef TRACE
421 #define T_TBL(name) { #name, name }
422 static struct {
423     const char *name;
424     unsigned mask;
425 } t_tbl[] = {
426
427     T_TBL(TRACE_DISABLE),
428         T_TBL(TRACE_TIMES),
429         T_TBL(TRACE_TPUTS),
430         T_TBL(TRACE_UPDATE),
431         T_TBL(TRACE_MOVE),
432         T_TBL(TRACE_CHARPUT),
433         T_TBL(TRACE_ORDINARY),
434         T_TBL(TRACE_CALLS),
435         T_TBL(TRACE_VIRTPUT),
436         T_TBL(TRACE_IEVENT),
437         T_TBL(TRACE_BITS),
438         T_TBL(TRACE_ICALLS),
439         T_TBL(TRACE_CCALLS),
440         T_TBL(TRACE_DATABASE),
441         T_TBL(TRACE_ATTRS),
442         T_TBL(TRACE_MAXIMUM),
443     {
444         (char *) 0, 0
445     }
446 };
447
448 static void
449 build_trace_menu(MenuNo number)
450 {
451     static ITEM *items[SIZEOF(t_tbl)];
452
453     ITEM **ip = items;
454     int n;
455
456     for (n = 0; t_tbl[n].name != 0; n++)
457         *ip++ = new_item(t_tbl[n].name, "");
458     *ip = (ITEM *) 0;
459
460     mpTrace = menu_create(items, SIZEOF(t_tbl) - 1, 2, number);
461 }
462
463 static char *
464 tracetrace(unsigned tlevel)
465 {
466     static char *buf;
467     int n;
468
469     if (buf == 0) {
470         size_t need = 12;
471         for (n = 0; t_tbl[n].name != 0; n++)
472             need += strlen(t_tbl[n].name) + 2;
473         buf = typeMalloc(char, need);
474     }
475     sprintf(buf, "0x%02x = {", tlevel);
476     if (tlevel == 0) {
477         sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name);
478     } else {
479         for (n = 1; t_tbl[n].name != 0; n++)
480             if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask) {
481                 strcat(buf, t_tbl[n].name);
482                 strcat(buf, ", ");
483             }
484     }
485     if (buf[strlen(buf) - 2] == ',')
486         buf[strlen(buf) - 2] = '\0';
487     return (strcat(buf, "}"));
488 }
489
490 /* fake a dynamically reconfigurable menu using the 0th entry to deselect
491  * the others
492  */
493 static bool
494 update_trace_menu(MENU * m)
495 {
496     ITEM **items;
497     ITEM *i, **p;
498     bool changed = FALSE;
499
500     items = menu_items(m);
501     i = current_item(m);
502     if (i == items[0]) {
503         if (item_value(i)) {
504             for (p = items + 1; *p != 0; p++)
505                 if (item_value(*p)) {
506                     set_item_value(*p, FALSE);
507                     changed = TRUE;
508                 }
509         }
510     }
511     return changed;
512 }
513
514 static int
515 perform_trace_menu(int cmd)
516 /* interactively set the trace level */
517 {
518     ITEM **ip;
519     unsigned newtrace;
520     int result;
521
522     for (ip = menu_items(mpTrace); *ip; ip++) {
523         unsigned mask = t_tbl[item_index(*ip)].mask;
524         if (mask == 0)
525             set_item_value(*ip, _nc_tracing == 0);
526         else if ((mask & _nc_tracing) == mask)
527             set_item_value(*ip, TRUE);
528     }
529
530     result = menu_driver(mpTrace, cmd);
531
532     if (result == E_OK) {
533         if (update_trace_menu(mpTrace) || cmd == REQ_TOGGLE_ITEM) {
534             newtrace = 0;
535             for (ip = menu_items(mpTrace); *ip; ip++) {
536                 if (item_value(*ip))
537                     newtrace |= t_tbl[item_index(*ip)].mask;
538             }
539             trace(newtrace);
540             Trace(("trace level interactively set to %s", tracetrace(_nc_tracing)));
541
542             MvPrintw(LINES - 2, 0,
543                      "Trace level is %s\n", tracetrace(_nc_tracing));
544             refresh();
545         }
546     }
547     return result;
548 }
549 #endif /* TRACE */
550
551 /*****************************************************************************/
552
553 static int
554 menu_number(void)
555 {
556     return item_index(current_item(mpBanner)) - (eBanner + 1);
557 }
558
559 static MENU *
560 current_menu(void)
561 {
562     MENU *result;
563
564     switch (menu_number()) {
565     case eFile:
566         result = mpFile;
567         break;
568     case eSelect:
569         result = mpSelect;
570         break;
571 #ifdef TRACE
572     case eTrace:
573         result = mpTrace;
574         break;
575 #endif
576     default:
577         result = 0;
578         break;
579     }
580     return result;
581 }
582
583 static void
584 build_menus(char *filename)
585 {
586     static CONST_MENUS char *labels[] =
587     {
588         "File",
589         "Select",
590 #ifdef TRACE
591         "Trace",
592 #endif
593         (char *) 0
594     };
595     static ITEM *items[SIZEOF(labels)];
596
597     ITEM **ip = items;
598     CONST_MENUS char **ap;
599
600     for (ap = labels; *ap; ap++)
601         *ip++ = new_item(*ap, "");
602     *ip = (ITEM *) 0;
603
604     mpBanner = menu_create(items, SIZEOF(labels) - 1, SIZEOF(labels) - 1, eBanner);
605     set_menu_mark(mpBanner, ">");
606
607     build_file_menu(eFile);
608     build_select_menu(eSelect, filename);
609 #ifdef TRACE
610     build_trace_menu(eTrace);
611 #endif
612 }
613
614 static int
615 move_menu(MENU * menu, MENU * current, int by_y, int by_x)
616 {
617     WINDOW *top_win = menu_win(menu);
618     WINDOW *sub_win = menu_sub(menu);
619     int y0, x0;
620     int y1, x1;
621     int result;
622
623     getbegyx(top_win, y0, x0);
624     y0 += by_y;
625     x0 += by_x;
626
627     getbegyx(sub_win, y1, x1);
628     y1 += by_y;
629     x1 += by_x;
630
631     if ((result = mvwin(top_win, y0, x0)) != ERR) {
632 #if defined(NCURSES_VERSION_PATCH) && (NCURSES_VERSION_PATCH < 20060218)
633         sub_win->_begy = y1;
634         sub_win->_begx = x1;
635 #else
636         mvwin(sub_win, y1, x1);
637 #endif
638         if (menu == current) {
639             touchwin(top_win);
640             wnoutrefresh(top_win);
641         }
642     }
643     return result;
644 }
645
646 /*
647  * Move the menus around on the screen, to test mvwin().
648  */
649 static void
650 move_menus(MENU * current, int by_y, int by_x)
651 {
652     if (move_menu(mpBanner, current, by_y, by_x) != ERR) {
653         erase();
654         wnoutrefresh(stdscr);
655         move_menu(mpFile, current, by_y, by_x);
656         move_menu(mpSelect, current, by_y, by_x);
657 #ifdef TRACE
658         move_menu(mpTrace, current, by_y, by_x);
659 #endif
660         doupdate();
661     }
662 }
663
664 static void
665 show_status(int ch, MENU * menu)
666 {
667     move(LINES - 1, 0);
668     printw("key %s, menu %d, mark %s, match %s",
669            keyname(ch),
670            menu_number(),
671            menu_mark(menu),
672            menu_pattern(menu));
673     clrtoeol();
674     refresh();
675 }
676
677 static void
678 perform_menus(void)
679 {
680     MENU *this_menu;
681     MENU *last_menu = mpFile;
682     int code = E_UNKNOWN_COMMAND;
683     int cmd;
684     int ch = ERR;
685
686 #ifdef NCURSES_MOUSE_VERSION
687     mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
688 #endif
689
690     menu_display(last_menu);
691
692     for (;;) {
693
694         if (ch != ERR)
695             show_status(ch, last_menu);
696
697         ch = menu_getc(mpBanner);
698
699         /*
700          * Provide for moving the menu around in the screen using shifted
701          * cursor keys.
702          */
703         switch (ch) {
704         case KEY_SF:
705             move_menus(last_menu, 1, 0);
706             continue;
707         case KEY_SR:
708             move_menus(last_menu, -1, 0);
709             continue;
710         case KEY_SLEFT:
711             move_menus(last_menu, 0, -1);
712             continue;
713         case KEY_SRIGHT:
714             move_menus(last_menu, 0, 1);
715             continue;
716         }
717         cmd = menu_virtualize(ch);
718
719         switch (cmd) {
720             /*
721              * The banner menu acts solely to select one of the other menus.
722              * Move between its items, wrapping at the left/right limits.
723              */
724         case REQ_LEFT_ITEM:
725         case REQ_RIGHT_ITEM:
726             code = menu_driver(mpBanner, cmd);
727             if (code == E_REQUEST_DENIED) {
728                 if (menu_number() > 0)
729                     code = menu_driver(mpBanner, REQ_FIRST_ITEM);
730                 else
731                     code = menu_driver(mpBanner, REQ_LAST_ITEM);
732             }
733             break;
734         default:
735             switch (menu_number()) {
736             case eFile:
737                 code = perform_file_menu(cmd);
738                 break;
739             case eSelect:
740                 code = perform_select_menu(cmd);
741                 break;
742 #ifdef TRACE
743             case eTrace:
744                 code = perform_trace_menu(cmd);
745                 break;
746 #endif
747             }
748
749             if ((code == E_REQUEST_DENIED) && (cmd == KEY_MOUSE)) {
750                 code = menu_driver(mpBanner, cmd);
751             }
752
753             break;
754         }
755
756         if (code == E_OK) {
757             this_menu = current_menu();
758             if (this_menu != last_menu) {
759                 move(1, 0);
760                 clrtobot();
761                 box(menu_win(this_menu), 0, 0);
762                 refresh();
763
764                 /* force the current menu to appear */
765                 menu_display(this_menu);
766
767                 last_menu = this_menu;
768             }
769         }
770         wrefresh(menu_win(last_menu));
771         if (code == E_UNKNOWN_COMMAND
772             || code == E_NOT_POSTED) {
773             if (menu_number() == eFile)
774                 break;
775             beep();
776         }
777         if (code == E_REQUEST_DENIED)
778             beep();
779         continue;
780     }
781
782 #ifdef NCURSES_MOUSE_VERSION
783     mousemask(0, (mmask_t *) 0);
784 #endif
785 }
786
787 static void
788 destroy_menus(void)
789 {
790     menu_destroy(mpFile);
791     menu_destroy(mpSelect);
792 #ifdef TRACE
793     menu_destroy(mpTrace);
794 #endif
795     menu_destroy(mpBanner);
796 }
797
798 #if HAVE_RIPOFFLINE
799 static int
800 rip_footer(WINDOW *win, int cols)
801 {
802     wbkgd(win, A_REVERSE);
803     werase(win);
804     wmove(win, 0, 0);
805     wprintw(win, "footer: %d columns", cols);
806     wnoutrefresh(win);
807     return OK;
808 }
809
810 static int
811 rip_header(WINDOW *win, int cols)
812 {
813     wbkgd(win, A_REVERSE);
814     werase(win);
815     wmove(win, 0, 0);
816     wprintw(win, "header: %d columns", cols);
817     wnoutrefresh(win);
818     return OK;
819 }
820 #endif /* HAVE_RIPOFFLINE */
821
822 static void
823 usage(void)
824 {
825     static const char *const tbl[] =
826     {
827         "Usage: demo_menus [options] [menu-file]"
828         ,""
829         ,"Options:"
830 #if HAVE_RIPOFFLINE
831         ,"  -f       rip-off footer line (can repeat)"
832         ,"  -h       rip-off header line (can repeat)"
833 #endif
834 #ifdef TRACE
835         ,"  -t mask  specify default trace-level (may toggle with ^T)"
836 #endif
837     };
838     size_t n;
839     for (n = 0; n < SIZEOF(tbl); n++)
840         fprintf(stderr, "%s\n", tbl[n]);
841     ExitProgram(EXIT_FAILURE);
842 }
843
844 int
845 main(int argc, char *argv[])
846 {
847     int c;
848
849     setlocale(LC_ALL, "");
850
851     while ((c = getopt(argc, argv, "a:de:fhmp:s:t:")) != -1) {
852         switch (c) {
853 #if HAVE_RIPOFFLINE
854         case 'f':
855             ripoffline(-1, rip_footer);
856             break;
857         case 'h':
858             ripoffline(1, rip_header);
859             break;
860 #endif /* HAVE_RIPOFFLINE */
861 #ifdef TRACE
862         case 't':
863             trace((unsigned) strtoul(optarg, 0, 0));
864             break;
865 #endif
866         default:
867             usage();
868         }
869     }
870
871     initscr();
872     noraw();
873     cbreak();
874     noecho();
875
876     if (has_colors()) {
877         start_color();
878         init_pair(1, COLOR_RED, COLOR_BLACK);
879         init_pair(2, COLOR_BLUE, COLOR_WHITE);
880     }
881     build_menus(argc > 1 ? argv[1] : 0);
882     perform_menus();
883     destroy_menus();
884
885     endwin();
886     ExitProgram(EXIT_SUCCESS);
887 }
888 #else
889 int
890 main(void)
891 {
892     printf("This program requires the curses menu library\n");
893     ExitProgram(EXIT_FAILURE);
894 }
895 #endif