/* ** Copyright (C) 1991, 1997 Free Software Foundation, Inc. ** ** This file is part of TACK. ** ** TACK is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2, or (at your option) ** any later version. ** ** TACK is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with TACK; see the file COPYING. If not, write to ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ** Boston, MA 02111-1307, USA. */ #include MODULE_ID("$Id: menu.c,v 1.2 2000/03/04 21:13:53 tom Exp $") /* Menu control */ static void test_byname(struct test_menu *, int *, int *); struct test_list *augment_test; char prompt_string[80]; /* menu prompt storage */ /* ** menu_prompt() ** ** Print the menu prompt string. */ void menu_prompt(void) { ptext(&prompt_string[1]); } /* ** menu_test_loop(test-structure, state, control-character) ** ** This function implements the repeat test function. */ static void menu_test_loop( struct test_list *test, int *state, int *ch) { int nch, p; if ((test->flags & MENU_REP_MASK) && (augment_test != test)) { /* set the augment variable (first time only) */ p = (test->flags >> 8) & 15; if ((test->flags & MENU_REP_MASK) == MENU_LM1) { augment = lines - 1; } else if ((test->flags & MENU_ONE_MASK) == MENU_ONE) { augment = 1; } else if ((test->flags & MENU_LC_MASK) == MENU_lines) { augment = lines * p / 10; } else if ((test->flags & MENU_LC_MASK) == MENU_columns) { augment = columns * p / 10; } else { augment = 1; } augment_test = test; set_augment_txt(); } do { if ((test->flags | *state) & MENU_CLEAR) { put_clear(); } else if (line_count + test->lines_needed >= lines) { put_clear(); } nch = 0; if (test->test_procedure) { /* The procedure takes precedence so I can pass the menu entry as an argument. */ can_test(test->caps_done, FLAG_TESTED); can_test(test->caps_tested, FLAG_TESTED); test->test_procedure(test, state, &nch); } else if (test->sub_menu) { /* nested menu's */ menu_display(test->sub_menu, &nch); *state = 0; if (nch == 'q' || nch == 's') { /* Quit and skip are killed here */ nch = '?'; } } else { break; /* cya */ } if (nch == '\r' || nch == '\n' || nch == 'n') { nch = 0; break; } } while (nch == 'r'); *ch = nch; } /* ** menu_display(menu-structure, flags) ** ** This function implements menu control. */ void menu_display( struct test_menu *menu, int *last_ch) { int test_state = 0, run_standard_tests; int hot_topic, ch = 0, nch = 0; struct test_list *mt; struct test_list *repeat_tests = 0; int repeat_state = 0; int prompt_length; prompt_length = strlen(prompt_string); if (menu->ident) { sprintf(&prompt_string[prompt_length], "/%s", menu->ident); } hot_topic = menu->default_action; run_standard_tests = menu->standard_tests ? menu->standard_tests[0] : -1; if (!last_ch) { last_ch = &ch; } while (1) { if (ch == 0) { /* Display the menu */ put_crlf(); if (menu->menu_function) { /* this function may be used to restrict menu entries. If used it must print the title. */ menu->menu_function(menu); } else if (menu->menu_title) { ptextln(menu->menu_title); } for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) { if (mt->menu_entry) { ptext(" "); ptextln(mt->menu_entry); } } if (menu->standard_tests) { ptext(" "); ptextln(menu->standard_tests); ptextln(" r) repeat test"); ptextln(" s) skip to next test"); } ptextln(" q) quit"); ptextln(" ?) help"); } if (ch == 0 || ch == REQUEST_PROMPT) { put_crlf(); ptext(&prompt_string[1]); if (hot_topic) { ptext(" ["); putchp(hot_topic); ptext("]"); } ptext(" > "); /* read a character */ ch = wait_here(); } if (ch == '\r' || ch == '\n') { ch = hot_topic; } if (ch == 'q') { break; } if (ch == '?') { ch = 0; continue; } nch = ch; ch = 0; /* Run one of the standard tests (by request) */ for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) { if (mt->menu_entry && (nch == mt->menu_entry[0])) { if (mt->flags & MENU_MENU) { test_byname(menu, &test_state, &nch); } else { menu_test_loop(mt, &test_state, &nch); } ch = nch; if ((mt->flags & MENU_COMPLETE) && ch == 0) { /* top level */ hot_topic = 'q'; ch = '?'; } } } if (menu->standard_tests && nch == 'r') { menu->resume_tests = repeat_tests; test_state = repeat_state; nch = run_standard_tests; } if (nch == run_standard_tests) { if (!(mt = menu->resume_tests)) { mt = menu->tests; } if (mt->flags & MENU_LAST) { mt = menu->tests; } /* Run the standard test suite */ for ( ; (mt->flags & MENU_LAST) == 0; ) { if ((mt->flags & MENU_NEXT) == MENU_NEXT) { repeat_tests = mt; repeat_state = test_state; nch = run_standard_tests; menu_test_loop(mt, &test_state, &nch); if (nch != 0 && nch != 'n') { ch = nch; break; } if (test_state & MENU_STOP) { break; } } mt++; } if (ch == 0) { ch = hot_topic; } menu->resume_tests = mt; menu->resume_state = test_state; menu->resume_char = ch; if (ch == run_standard_tests) { /* pop up a level */ break; } } } *last_ch = ch; prompt_string[prompt_length] = '\0'; } /* ** generic_done_message(test_list) ** ** Print the Done message and request input. */ void generic_done_message( struct test_list *test, int *state, int *ch) { char done_message[128]; if (test->caps_done) { sprintf(done_message, "(%s) Done ", test->caps_done); ptext(done_message); } else { ptext("Done "); } *ch = wait_here(); if (*ch == '\r' || *ch == '\n' || *ch == 'n') { *ch = 0; } if (*ch == 's') { *state |= MENU_STOP; *ch = 0; } } /* ** menu_clear_screen(test, state, ch) ** ** Just clear the screen. */ void menu_clear_screen( struct test_list *test GCC_UNUSED, int *state GCC_UNUSED, int *ch GCC_UNUSED) { put_clear(); } /* ** menu_reset_init(test, state, ch) ** ** Send the reset and init strings. */ void menu_reset_init( struct test_list *test GCC_UNUSED, int *state GCC_UNUSED, int *ch GCC_UNUSED) { reset_init(); put_crlf(); } /* ** subtest_menu(test, state, ch) ** ** Scan the menu looking for something to execute ** Return TRUE if we found anything. */ int subtest_menu( struct test_list *test, int *state, int *ch) { struct test_list *mt; if (*ch) { for (mt = test; (mt->flags & MENU_LAST) == 0; mt++) { if (mt->menu_entry && (*ch == mt->menu_entry[0])) { *ch = 0; menu_test_loop(mt, state, ch); return TRUE; } } } return FALSE; } /* ** menu_can_scan(menu-structure) ** ** Recursively scan the menu tree and find which cap names can be tested. */ void menu_can_scan( const struct test_menu *menu) { struct test_list *mt; for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) { can_test(mt->caps_done, FLAG_CAN_TEST); can_test(mt->caps_tested, FLAG_CAN_TEST); if (!(mt->test_procedure)) { if (mt->sub_menu) { menu_can_scan(mt->sub_menu); } } } } /* ** menu_search(menu-structure, cap) ** ** Recursively search the menu tree and execute any tests that use cap. */ static void menu_search( struct test_menu *menu, int *state, int *ch, char *cap) { struct test_list *mt; int nch; for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) { nch = 0; if (cap_match(mt->caps_done, cap) || cap_match(mt->caps_tested, cap)) { menu_test_loop(mt, state, &nch); } if (!(mt->test_procedure)) { if (mt->sub_menu) { menu_search(mt->sub_menu, state, &nch, cap); } } if (*state & MENU_STOP) { break; } if (nch != 0 && nch != 'n') { *ch = nch; break; } } } /* ** test_byname(menu, state, ch) ** ** Get a cap name then run all tests that use that cap. */ static void test_byname( struct test_menu *menu, int *state GCC_UNUSED, int *ch) { int test_state = 0; char cap[32]; if (tty_can_sync == SYNC_NOT_TESTED) { verify_time(); } ptext("enter name: "); read_string(cap, sizeof(cap)); if (cap[0]) { menu_search(menu, &test_state, ch, cap); } *ch = '?'; }