1/* 2** Copyright (C) 1991, 1997 Free Software Foundation, Inc. 3** 4** This file is part of TACK. 5** 6** TACK is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2, or (at your option) 9** any later version. 10** 11** TACK is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with TACK; see the file COPYING. If not, write to 18** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19** Boston, MA 02110-1301, USA 20*/ 21 22#include <tack.h> 23 24MODULE_ID("$Id: menu.c,v 1.3 2005/09/17 19:49:16 tom Exp $") 25 26/* 27 Menu control 28 */ 29 30static void test_byname(struct test_menu *, int *, int *); 31 32struct test_list *augment_test; 33char prompt_string[80]; /* menu prompt storage */ 34 35/* 36** menu_prompt() 37** 38** Print the menu prompt string. 39*/ 40void 41menu_prompt(void) 42{ 43 ptext(&prompt_string[1]); 44} 45 46/* 47** menu_test_loop(test-structure, state, control-character) 48** 49** This function implements the repeat test function. 50*/ 51static void 52menu_test_loop( 53 struct test_list *test, 54 int *state, 55 int *ch) 56{ 57 int nch, p; 58 59 if ((test->flags & MENU_REP_MASK) && (augment_test != test)) { 60 /* set the augment variable (first time only) */ 61 p = (test->flags >> 8) & 15; 62 if ((test->flags & MENU_REP_MASK) == MENU_LM1) { 63 augment = lines - 1; 64 } else 65 if ((test->flags & MENU_ONE_MASK) == MENU_ONE) { 66 augment = 1; 67 } else 68 if ((test->flags & MENU_LC_MASK) == MENU_lines) { 69 augment = lines * p / 10; 70 } else 71 if ((test->flags & MENU_LC_MASK) == MENU_columns) { 72 augment = columns * p / 10; 73 } else { 74 augment = 1; 75 } 76 augment_test = test; 77 set_augment_txt(); 78 } 79 do { 80 if ((test->flags | *state) & MENU_CLEAR) { 81 put_clear(); 82 } else 83 if (line_count + test->lines_needed >= lines) { 84 put_clear(); 85 } 86 nch = 0; 87 if (test->test_procedure) { 88 /* The procedure takes precedence so I can pass 89 the menu entry as an argument. 90 */ 91 can_test(test->caps_done, FLAG_TESTED); 92 can_test(test->caps_tested, FLAG_TESTED); 93 test->test_procedure(test, state, &nch); 94 } else 95 if (test->sub_menu) { 96 /* nested menu's */ 97 menu_display(test->sub_menu, &nch); 98 *state = 0; 99 if (nch == 'q' || nch == 's') { 100 /* Quit and skip are killed here */ 101 nch = '?'; 102 } 103 } else { 104 break; /* cya */ 105 } 106 if (nch == '\r' || nch == '\n' || nch == 'n') { 107 nch = 0; 108 break; 109 } 110 } while (nch == 'r'); 111 *ch = nch; 112} 113 114/* 115** menu_display(menu-structure, flags) 116** 117** This function implements menu control. 118*/ 119void 120menu_display( 121 struct test_menu *menu, 122 int *last_ch) 123{ 124 int test_state = 0, run_standard_tests; 125 int hot_topic, ch = 0, nch = 0; 126 struct test_list *mt; 127 struct test_list *repeat_tests = 0; 128 int repeat_state = 0; 129 int prompt_length; 130 131 prompt_length = strlen(prompt_string); 132 if (menu->ident) { 133 sprintf(&prompt_string[prompt_length], "/%s", menu->ident); 134 } 135 hot_topic = menu->default_action; 136 run_standard_tests = menu->standard_tests ? 137 menu->standard_tests[0] : -1; 138 if (!last_ch) { 139 last_ch = &ch; 140 } 141 while (1) { 142 if (ch == 0) { 143 /* Display the menu */ 144 put_crlf(); 145 if (menu->menu_function) { 146 /* 147 this function may be used to restrict menu 148 entries. If used it must print the title. 149 */ 150 menu->menu_function(menu); 151 } else 152 if (menu->menu_title) { 153 ptextln(menu->menu_title); 154 } 155 for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) { 156 if (mt->menu_entry) { 157 ptext(" "); 158 ptextln(mt->menu_entry); 159 } 160 } 161 if (menu->standard_tests) { 162 ptext(" "); 163 ptextln(menu->standard_tests); 164 ptextln(" r) repeat test"); 165 ptextln(" s) skip to next test"); 166 } 167 ptextln(" q) quit"); 168 ptextln(" ?) help"); 169 } 170 if (ch == 0 || ch == REQUEST_PROMPT) { 171 put_crlf(); 172 ptext(&prompt_string[1]); 173 if (hot_topic) { 174 ptext(" ["); 175 putchp(hot_topic); 176 ptext("]"); 177 } 178 ptext(" > "); 179 /* read a character */ 180 ch = wait_here(); 181 } 182 if (ch == '\r' || ch == '\n') { 183 ch = hot_topic; 184 } 185 if (ch == 'q') { 186 break; 187 } 188 if (ch == '?') { 189 ch = 0; 190 continue; 191 } 192 nch = ch; 193 ch = 0; 194 /* Run one of the standard tests (by request) */ 195 for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) { 196 if (mt->menu_entry && (nch == mt->menu_entry[0])) { 197 if (mt->flags & MENU_MENU) { 198 test_byname(menu, &test_state, &nch); 199 } else { 200 menu_test_loop(mt, &test_state, &nch); 201 } 202 ch = nch; 203 if ((mt->flags & MENU_COMPLETE) && ch == 0) { 204 /* top level */ 205 hot_topic = 'q'; 206 ch = '?'; 207 } 208 } 209 } 210 if (menu->standard_tests && nch == 'r') { 211 menu->resume_tests = repeat_tests; 212 test_state = repeat_state; 213 nch = run_standard_tests; 214 } 215 if (nch == run_standard_tests) { 216 if (!(mt = menu->resume_tests)) { 217 mt = menu->tests; 218 } 219 if (mt->flags & MENU_LAST) { 220 mt = menu->tests; 221 } 222 /* Run the standard test suite */ 223 for ( ; (mt->flags & MENU_LAST) == 0; ) { 224 if ((mt->flags & MENU_NEXT) == MENU_NEXT) { 225 repeat_tests = mt; 226 repeat_state = test_state; 227 nch = run_standard_tests; 228 menu_test_loop(mt, &test_state, &nch); 229 if (nch != 0 && nch != 'n') { 230 ch = nch; 231 break; 232 } 233 if (test_state & MENU_STOP) { 234 break; 235 } 236 } 237 mt++; 238 } 239 if (ch == 0) { 240 ch = hot_topic; 241 } 242 menu->resume_tests = mt; 243 menu->resume_state = test_state; 244 menu->resume_char = ch; 245 246 if (ch == run_standard_tests) { 247 /* pop up a level */ 248 break; 249 } 250 } 251 } 252 *last_ch = ch; 253 prompt_string[prompt_length] = '\0'; 254} 255 256/* 257** generic_done_message(test_list) 258** 259** Print the Done message and request input. 260*/ 261void 262generic_done_message( 263 struct test_list *test, 264 int *state, 265 int *ch) 266{ 267 char done_message[128]; 268 269 if (test->caps_done) { 270 sprintf(done_message, "(%s) Done ", test->caps_done); 271 ptext(done_message); 272 } else { 273 ptext("Done "); 274 } 275 *ch = wait_here(); 276 if (*ch == '\r' || *ch == '\n' || *ch == 'n') { 277 *ch = 0; 278 } 279 if (*ch == 's') { 280 *state |= MENU_STOP; 281 *ch = 0; 282 } 283} 284 285/* 286** menu_clear_screen(test, state, ch) 287** 288** Just clear the screen. 289*/ 290void 291menu_clear_screen( 292 struct test_list *test GCC_UNUSED, 293 int *state GCC_UNUSED, 294 int *ch GCC_UNUSED) 295{ 296 put_clear(); 297} 298 299/* 300** menu_reset_init(test, state, ch) 301** 302** Send the reset and init strings. 303*/ 304void 305menu_reset_init( 306 struct test_list *test GCC_UNUSED, 307 int *state GCC_UNUSED, 308 int *ch GCC_UNUSED) 309{ 310 reset_init(); 311 put_crlf(); 312} 313 314/* 315** subtest_menu(test, state, ch) 316** 317** Scan the menu looking for something to execute 318** Return TRUE if we found anything. 319*/ 320int 321subtest_menu( 322 struct test_list *test, 323 int *state, 324 int *ch) 325{ 326 struct test_list *mt; 327 328 if (*ch) { 329 for (mt = test; (mt->flags & MENU_LAST) == 0; mt++) { 330 if (mt->menu_entry && (*ch == mt->menu_entry[0])) { 331 *ch = 0; 332 menu_test_loop(mt, state, ch); 333 return TRUE; 334 } 335 } 336 } 337 return FALSE; 338} 339 340/* 341** menu_can_scan(menu-structure) 342** 343** Recursively scan the menu tree and find which cap names can be tested. 344*/ 345void 346menu_can_scan( 347 const struct test_menu *menu) 348{ 349 struct test_list *mt; 350 351 for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) { 352 can_test(mt->caps_done, FLAG_CAN_TEST); 353 can_test(mt->caps_tested, FLAG_CAN_TEST); 354 if (!(mt->test_procedure)) { 355 if (mt->sub_menu) { 356 menu_can_scan(mt->sub_menu); 357 } 358 } 359 } 360} 361 362/* 363** menu_search(menu-structure, cap) 364** 365** Recursively search the menu tree and execute any tests that use cap. 366*/ 367static void 368menu_search( 369 struct test_menu *menu, 370 int *state, 371 int *ch, 372 char *cap) 373{ 374 struct test_list *mt; 375 int nch; 376 377 for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) { 378 nch = 0; 379 if (cap_match(mt->caps_done, cap) 380 || cap_match(mt->caps_tested, cap)) { 381 menu_test_loop(mt, state, &nch); 382 } 383 if (!(mt->test_procedure)) { 384 if (mt->sub_menu) { 385 menu_search(mt->sub_menu, state, &nch, cap); 386 } 387 } 388 if (*state & MENU_STOP) { 389 break; 390 } 391 if (nch != 0 && nch != 'n') { 392 *ch = nch; 393 break; 394 } 395 } 396} 397 398/* 399** test_byname(menu, state, ch) 400** 401** Get a cap name then run all tests that use that cap. 402*/ 403static void 404test_byname( 405 struct test_menu *menu, 406 int *state GCC_UNUSED, 407 int *ch) 408{ 409 int test_state = 0; 410 char cap[32]; 411 412 if (tty_can_sync == SYNC_NOT_TESTED) { 413 verify_time(); 414 } 415 ptext("enter name: "); 416 read_string(cap, sizeof(cap)); 417 if (cap[0]) { 418 menu_search(menu, &test_state, ch, cap); 419 } 420 *ch = '?'; 421} 422