| 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 |
|
|---|
| 24 | MODULE_ID("$Id: menu.c,v 1.3 2005/09/17 19:49:16 tom Exp $")
|
|---|
| 25 |
|
|---|
| 26 | /*
|
|---|
| 27 | Menu control
|
|---|
| 28 | */
|
|---|
| 29 |
|
|---|
| 30 | static void test_byname(struct test_menu *, int *, int *);
|
|---|
| 31 |
|
|---|
| 32 | struct test_list *augment_test;
|
|---|
| 33 | char prompt_string[80]; /* menu prompt storage */
|
|---|
| 34 |
|
|---|
| 35 | /*
|
|---|
| 36 | ** menu_prompt()
|
|---|
| 37 | **
|
|---|
| 38 | ** Print the menu prompt string.
|
|---|
| 39 | */
|
|---|
| 40 | void
|
|---|
| 41 | menu_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 | */
|
|---|
| 51 | static void
|
|---|
| 52 | menu_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 | */
|
|---|
| 119 | void
|
|---|
| 120 | menu_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 | */
|
|---|
| 261 | void
|
|---|
| 262 | generic_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 | */
|
|---|
| 290 | void
|
|---|
| 291 | menu_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 | */
|
|---|
| 304 | void
|
|---|
| 305 | menu_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 | */
|
|---|
| 320 | int
|
|---|
| 321 | subtest_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 | */
|
|---|
| 345 | void
|
|---|
| 346 | menu_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 | */
|
|---|
| 367 | static void
|
|---|
| 368 | menu_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 | */
|
|---|
| 403 | static void
|
|---|
| 404 | test_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 | }
|
|---|