ncurses 5.0
[ncurses.git] / tack / tack.c
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., 59 Temple Place - Suite 330,
19 ** Boston, MA 02111-1307, USA.
20 */
21
22 #include <tack.h>
23
24 MODULE_ID("$Id: tack.c,v 1.1 1998/01/10 01:34:45 tom Exp $")
25
26 /*
27    This program is designed to test terminfo, not curses.  Therefore
28    I have used as little of curses as possible.
29
30    Pads associated with the following capabilities are used to set
31    delay times in the handler:  (cr), (ind), (cub1), (ff), (tab).
32
33    I use the (nxon) capability to set the tty handler with/without
34    xon/xoff.  If (smxon)/(rmxon) is defined I will change the terminal
35    too.
36
37    (xon) inhibits the sending of delay characters in putp().
38    If the terminal is defined with no padding then the (xon) boolean
39    is a don't care.  In this case I recommend that it be reset.
40  */
41
42 /*****************************************************************************
43  *
44  * Option processing
45  *
46  *****************************************************************************/
47
48 /* options and modes */
49 int debug_level;                /* debugging level */
50 int translate_mode;             /* translate tab, bs, cr, lf, ff */
51 int scan_mode;                  /* use scan codes */
52 int char_mask;                  /* either 0xFF else 0x7F, eight bit data mask */
53 int select_delay_type;          /* set handler delays for <cr><lf> */
54 int select_xon_xoff;            /* TTY driver XON/XOFF mode select */
55 int hex_out;                    /* Display output in hex */
56 int send_reset_init;            /* Send the reset and initialization strings */
57 FILE *log_fp;                   /* Terminal logfile */
58
59 /*****************************************************************************
60  *
61  * Menu definitions
62  *
63  *****************************************************************************/
64
65 extern struct test_menu sync_menu;
66
67 static void tools_hex_echo(struct test_list *, int *, int *);
68 static void tools_debug(struct test_list *, int *, int *);
69
70 static char hex_echo_menu_entry[80];
71
72 struct test_list tools_test_list[] = {
73         {0, 0, 0, 0, "s) ANSI status reports", tools_status, 0},
74         {0, 0, 0, 0, "g) ANSI SGR modes (bold, underline, reverse)", tools_sgr, 0},
75         {0, 0, 0, 0, "c) ANSI character sets", tools_charset, 0},
76         {0, 0, 0, 0, hex_echo_menu_entry, tools_hex_echo, 0},
77         {0, 0, 0, 0, "e) echo tool", tools_report, 0},
78         {1, 0, 0, 0, "r) reply tool", tools_report, 0},
79         {0, 0, 0, 0, "p) performance testing", 0, &sync_menu},
80         {0, 0, 0, 0, "i) send reset and init", menu_reset_init, 0},
81         {0, 0, "u8) (u9", 0, "u) test ENQ/ACK handshake", sync_handshake, 0},
82         {0, 0, 0, 0, "d) change debug level", tools_debug, 0},
83         {MENU_LAST, 0, 0, 0, 0, 0, 0}
84 };
85
86 struct test_menu tools_menu = {
87         0, 'q', 0, "Tools Menu", "tools",
88         0, 0, tools_test_list, 0, 0, 0
89 };
90
91 static void tty_width(struct test_list *, int *, int *);
92 static void tty_delay(struct test_list *, int *, int *);
93 static void tty_xon(struct test_list *, int *, int *);
94 static void tty_trans(struct test_list *, int *, int *);
95 static void tty_show_state(struct test_menu *);
96
97 static char tty_width_menu[80];
98 static char tty_delay_menu[80];
99 static char tty_xon_menu[80];
100 static char tty_trans_menu[80];
101 static char enable_xon_xoff[] = {"x) enable xon/xoff"};
102 static char disable_xon_xoff[] = {"x) disable xon/xoff"};
103
104 static struct test_list tty_test_list[] = {
105         {0, 0, 0, 0, tty_width_menu, tty_width, 0},
106         {0, 0, 0, 0, tty_delay_menu, tty_delay, 0},
107         {0, 0, 0, 0, tty_xon_menu, tty_xon, 0},
108         {0, 0, 0, 0, tty_trans_menu, tty_trans, 0},
109         {MENU_LAST, 0, 0, 0, 0, 0, 0}
110 };
111
112 static struct test_menu tty_menu = {
113         0, 'q', 0, "Terminal and driver configuration",
114         "tty", 0,
115         tty_show_state, tty_test_list, 0, 0, 0
116 };
117
118 extern struct test_list edit_test_list[];
119
120 struct test_menu edit_menu = {
121         0, 'q', 0, "Edit terminfo menu",
122         "edit", 0,
123         0, edit_test_list, 0, 0, 0
124 };
125
126 extern struct test_list mode_test_list[];
127
128 struct test_menu mode_menu = {
129         0, 'n', 0, "Mode test menu",
130         "mode", "n) run standard tests",
131         0, mode_test_list, 0, 0, 0
132 };
133
134 extern struct test_list acs_test_list[];
135
136 static struct test_menu acs_menu = {
137         0, 'n', 0,
138         "Alternate character set and graphics rendition test menu",
139         "acs", "n) run standard tests",
140         0, acs_test_list, 0, 0, 0
141 };
142
143 extern struct test_list color_test_list[];
144
145 struct test_menu color_menu = {
146         0, 'n', 0,
147         "Color test menu",
148         "color", "n) run standard tests",
149         0, color_test_list, 0, 0, 0
150 };
151
152 extern struct test_list crum_test_list[];
153
154 static struct test_menu crum_menu = {
155         0, 'n', 0,
156         "Cursor movement test menu",
157         "move", "n) run standard tests",
158         0, crum_test_list, 0, 0, 0
159 };
160
161 extern struct test_list funkey_test_list[];
162
163 static struct test_menu funkey_menu = {
164         0, 'n', 0,
165         "Function key test menu",
166         "fkey", "n) run standard tests",
167         sync_test, funkey_test_list, 0, 0, 0
168 };
169
170 extern struct test_list printer_test_list[];
171
172 static struct test_menu printer_menu = {
173         0, 'n', 0,
174         "Printer test menu",
175         "printer", "n) run standard tests",
176         0, printer_test_list, 0, 0, 0
177 };
178
179 static void pad_gen(struct test_list *, int *, int *);
180 extern struct test_list pad_test_list[];
181
182 static struct test_menu pad_menu = {
183         0, 'n', 0,
184         "Pad test menu",
185         "pad", "n) run standard tests",
186         sync_test, pad_test_list, 0, 0, 0
187 };
188
189 static struct test_list normal_test_list[] = {
190         {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
191         {0, 0, 0, 0, "i) send reset and init", menu_reset_init, 0},
192         {MENU_NEXT, 0, 0, 0, "x) test modes and glitches", 0, &mode_menu},
193         {MENU_NEXT, 0, 0, 0, "a) test alternate character sets", 0, &acs_menu},
194         {MENU_NEXT, 0, 0, 0, "c) test color", 0, &color_menu},
195         {MENU_NEXT, 0, 0, 0, "m) test cursor movement", 0, &crum_menu},
196         {MENU_NEXT, 0, 0, 0, "f) test function keys", 0, &funkey_menu},
197         {MENU_NEXT, 0, 0, 0, "p) test string capabilities", 0, &pad_menu},
198         {0, 0, 0, 0, "P) test printer", 0, &printer_menu},
199         {MENU_MENU, 0, 0, 0, "/) test a specific capability", 0, 0},
200         {0, 0, 0, 0, "t) auto generate pad delays", pad_gen, &pad_menu},
201         {0, 0, "u8) (u9", 0, 0, sync_handshake, 0},
202         {MENU_LAST, 0, 0, 0, 0, 0, 0}
203 };
204
205
206 struct test_menu normal_menu = {
207         0, 'n', 0, "Main test menu",
208         "test", "n) run standard tests",
209         0, normal_test_list, 0, 0, 0
210 };
211
212 static void start_tools(struct test_list *, int *, int *);
213 static void start_modes(struct test_list *, int *, int *);
214 static void start_basic(struct test_list *, int *, int *);
215 static void start_log(struct test_list *, int *, int *);
216
217 static char logging_menu_entry[80] = "l) start logging";
218
219 struct test_list start_test_list[] = {
220         {0, 0, 0, 0, "b) display basic information", start_basic, 0},
221         {0, 0, 0, 0, "m) change modes", start_modes, 0},
222         {0, 0, 0, 0, "t) tools", start_tools, 0},
223         {MENU_COMPLETE, 0, 0, 0, "n) begin testing", 0, &normal_menu},
224         {0, 0, 0, 0, logging_menu_entry, start_log, 0},
225         {MENU_LAST, 0, 0, 0, 0, 0, 0}
226 };
227         
228
229 struct test_menu start_menu = {
230         0, 'n', 0, "Main Menu", "tack", 0,
231         0, start_test_list, 0, 0, 0
232 };
233
234 static struct test_list write_terminfo_list[] = {
235         {0, 0, 0, 0, "w) write the current terminfo to a file", save_info, 0},
236         {MENU_LAST, 0, 0, 0, 0, 0, 0}
237 };
238
239 /*****************************************************************************
240  *
241  * Menu command interpretation.
242  *
243  *****************************************************************************/
244
245 /*
246 **      tools_hex_echo(testlist, state, ch)
247 **
248 **      Flip the hex echo flag.
249 */
250 static void
251 tools_hex_echo(
252         struct test_list *t GCC_UNUSED,
253         int *state GCC_UNUSED,
254         int *ch GCC_UNUSED)
255 {
256         if (hex_out) {
257                 hex_out = FALSE;
258                 strcpy(hex_echo_menu_entry,
259                         "h) enable hex output on echo tool");
260         } else {
261                 hex_out = TRUE;
262                 strcpy(hex_echo_menu_entry,
263                         "h) disable hex output on echo tool");
264         }
265 }
266
267 /*
268 **      tools_debug(testlist, state, ch)
269 **
270 **      Change the debug level.
271 */
272 static void
273 tools_debug(
274         struct test_list *t GCC_UNUSED,
275         int *state GCC_UNUSED,
276         int *ch)
277 {
278         char buf[32];
279
280         ptext("Enter a new value: ");
281         read_string(buf, sizeof(buf));
282         if (buf[0]) {
283                 sscanf(buf, "%d", &debug_level);
284         }
285         sprintf(temp, "Debug level is now %d", debug_level);
286         ptext(temp);
287         *ch = REQUEST_PROMPT;
288 }
289
290 /*
291 **      start_tools(testlist, state, ch)
292 **
293 **      Run the generic test tools
294 */
295 static void
296 start_tools(
297         struct test_list *t GCC_UNUSED,
298         int *state GCC_UNUSED,
299         int *ch GCC_UNUSED)
300 {
301         if (hex_out) {
302                 strcpy(hex_echo_menu_entry,
303                         "h) disable hex output on echo tool");
304         } else {
305                 strcpy(hex_echo_menu_entry,
306                         "h) enable hex output on echo tool");
307         }
308         menu_display(&tools_menu, 0);
309 }
310
311 /*
312 **      tty_show_state()
313 **
314 **      Display the current state on the tty driver settings
315 */
316 static void
317 tty_show_state(
318         struct test_menu *menu GCC_UNUSED)
319 {
320         put_crlf();
321         (void) sprintf(temp,
322                 "Accepting %d bits, UNIX delays %d, XON/XOFF %sabled, speed %ld, translate %s, scan-code mode %s.",
323                 (char_mask == ALLOW_PARITY) ? 8 : 7,
324                 select_delay_type,
325                 select_xon_xoff ? "en" : "dis",
326                 tty_baud_rate,
327                 translate_mode ? "on" : "off",
328                 scan_mode ? "on" : "off");
329         ptextln(temp);
330         put_crlf();
331 }
332
333 /*
334 **      tty_width(testlist, state, ch)
335 **
336 **      Change the character width
337 */
338 static void
339 tty_width(
340         struct test_list *t GCC_UNUSED,
341         int *state GCC_UNUSED,
342         int *ch GCC_UNUSED)
343 {
344         if (char_mask == STRIP_PARITY) {
345                 char_mask = ALLOW_PARITY;
346                 strcpy(tty_width_menu, "7) treat terminal as 7-bit");
347         } else {
348                 char_mask = STRIP_PARITY;
349                 strcpy(tty_width_menu, "8) treat terminal as 8-bit");
350         }
351 }
352
353 /*
354 **      tty_delay(testlist, state, ch)
355 **
356 **      Change the delay for <cr><lf> in the TTY driver
357 */
358 static void
359 tty_delay(
360         struct test_list *t GCC_UNUSED,
361         int *state GCC_UNUSED,
362         int *ch GCC_UNUSED)
363 {
364         if (select_delay_type) {
365                 select_delay_type = FALSE;
366                 strcpy(tty_delay_menu,
367                         "d) enable UNIX tty driver delays for <cr><lf>");
368         } else {
369                 select_delay_type = TRUE;
370                 strcpy(tty_delay_menu,
371                         "d) disable UNIX tty driver delays for <cr><lf>");
372         }
373 }
374
375 /*
376 **      tty_xon(testlist, state, ch)
377 **
378 **      Change the XON/XOFF flags in the TTY driver
379 */
380 static void
381 tty_xon(
382         struct test_list *t GCC_UNUSED,
383         int *state GCC_UNUSED,
384         int *ch GCC_UNUSED)
385 {
386         if (select_xon_xoff) {
387                 if (needs_xon_xoff) {
388                         ptextln("This terminal is marked as needing XON/XOFF protocol with (nxon)");
389                 }
390                 if (exit_xon_mode) {
391                         tc_putp(exit_xon_mode);
392                 }
393                 xon_xoff = select_xon_xoff = FALSE;
394                 strcpy(tty_xon_menu, enable_xon_xoff);
395         } else {
396                 if (enter_xon_mode) {
397                         tc_putp(enter_xon_mode);
398                 }
399                 xon_xoff = select_xon_xoff = TRUE;
400                 strcpy(tty_xon_menu, disable_xon_xoff);
401         }
402         tty_set();
403 }
404
405 /*
406 **      tty_trans(testlist, state, ch)
407 **
408 **      Change the translation mode for special characters
409 */
410 static void
411 tty_trans(
412         struct test_list *t GCC_UNUSED,
413         int *state GCC_UNUSED,
414         int *ch GCC_UNUSED)
415 {
416         if (translate_mode) {
417                 translate_mode = FALSE;
418                 strcpy(tty_trans_menu,
419                         "t) use terminfo values for \\b\\f\\n\\r\\t");
420         } else {
421                 translate_mode = TRUE;
422                 strcpy(tty_trans_menu,
423                         "t) override terminfo values for \\b\\f\\n\\r\\t");
424         }
425 }
426
427 /*
428 **      pad_gen(testlist, state, ch)
429 **
430 **      Menu function for automatic pad generation
431 */
432 static void
433 pad_gen(
434         struct test_list *t,
435         int *state GCC_UNUSED,
436         int *ch)
437 {
438         control_init();
439         if (tty_can_sync == SYNC_NOT_TESTED) {
440                 verify_time();
441         }
442         auto_pad_mode = TRUE;
443         menu_display(t->sub_menu, ch);
444         auto_pad_mode = FALSE;
445 }
446
447 /*
448 **      start_modes(testlist, state, ch)
449 **
450 **      Change the TTY modes
451 */
452 static void
453 start_modes(
454         struct test_list *t GCC_UNUSED,
455         int *state GCC_UNUSED,
456         int *ch GCC_UNUSED)
457 {
458
459         if (select_delay_type) {
460                 strcpy(tty_delay_menu,
461                         "d) disable UNIX tty driver delays for <cr><lf>");
462         } else {
463                 strcpy(tty_delay_menu,
464                         "d) enable UNIX tty driver delays for <cr><lf>");
465         }
466         if (char_mask == ALLOW_PARITY) {
467                 strcpy(tty_width_menu,
468                         "7) treat terminal as 7-bit");
469         } else {
470                 strcpy(tty_width_menu,
471                         "8) treat terminal as 8-bit");
472         }
473         if (select_xon_xoff) {
474                 strcpy(tty_xon_menu, disable_xon_xoff);
475         } else {
476                 strcpy(tty_xon_menu, enable_xon_xoff);
477         }
478         if (translate_mode) {
479                 strcpy(tty_trans_menu,
480                         "t) override terminfo values for \\b\\f\\n\\r\\t");
481         } else {
482                 strcpy(tty_trans_menu,
483                         "t) use terminfo values for \\b\\f\\n\\r\\t");
484         }
485         menu_display(&tty_menu, 0);
486         tty_set();
487 }
488
489 /*
490 **      start_basic(testlist, state, ch)
491 **
492 **      Display basic terminal information
493 */
494 static void
495 start_basic(
496         struct test_list *t GCC_UNUSED,
497         int *state GCC_UNUSED,
498         int *ch)
499 {
500         display_basic();
501         *ch = REQUEST_PROMPT;
502 }
503
504 /*
505 **      start_log(testlist, state, ch)
506 **
507 **      Start/stop in logging function
508 */
509 static void
510 start_log(
511         struct test_list *t GCC_UNUSED,
512         int *state GCC_UNUSED,
513         int *ch GCC_UNUSED)
514 {
515         if (logging_menu_entry[5] == 'a') {
516                 ptextln("The log file will capture all characters sent to the terminal.");
517                 if ((log_fp = fopen("tack.log", "w"))) {
518                         ptextln("Start logging to file: tack.log");
519                         strcpy(logging_menu_entry, "l) stop logging");
520                 } else {
521                         ptextln("File open error: tack.log");
522                 }
523         } else {
524                 if (log_fp) {
525                         fclose(log_fp);
526                         log_fp = 0;
527                 }
528                 ptextln("Terminal output logging stopped.");
529                 strcpy(logging_menu_entry, "l) start logging");
530         }
531 }
532
533 /*
534 **      show_usage()
535 **
536 **      Tell the user how its done.
537 */
538 void
539 show_usage(
540         char *name)
541 {
542         (void) fprintf(stderr, "usage: %s [-itV] [term]\n", name);
543 }
544
545 /*
546 **      print_version()
547 **
548 **      Print version and other useful information.
549 */
550 void
551 print_version(void)
552 {
553         printf("tack version %d.%02d\n", MAJOR_VERSION, MINOR_VERSION);
554         printf("Copyright (C) 1997 Free Software Foundation, Inc.\n");
555         printf("Tack comes with NO WARRANTY, to the extent permitted by law.\n");
556         printf("You may redistribute copies of Tack under the terms of the\n");
557         printf("GNU General Public License.  For more information about\n");
558         printf("these matters, see the file named COPYING.\n");
559 }
560
561
562 /*****************************************************************************
563  *
564  * Main sequence
565  *
566  *****************************************************************************/
567
568 int
569 main(int argc, char *argv[])
570 {
571         int i, j;
572         char *term_variable;
573
574         /* scan the option flags */
575         send_reset_init = TRUE;
576         translate_mode = FALSE;
577         term_variable = getenv("TERM");
578         tty_can_sync = SYNC_NOT_TESTED;
579         for (i = 1; i < argc; i++) {
580                 if (argv[i][0] == '-') {
581                         for (j = 1; argv[i][j]; j++) {
582                                 switch (argv[i][j]) {
583                                 case 'V':
584                                         print_version();
585                                         return (1);
586                                 case 'i':
587                                         send_reset_init = FALSE;
588                                         break;
589                                 case 't':
590                                         translate_mode = FALSE;
591                                         break;
592                                 default:
593                                         show_usage(argv[0]);
594                                         return (0);
595                                 }
596                         }
597                 } else {
598                         term_variable = argv[i];
599                 }
600         }
601         (void) strcpy(tty_basename, term_variable);
602
603         curses_setup(argv[0]);
604
605         menu_can_scan(&normal_menu);    /* extract which caps can be tested */
606         menu_display(&start_menu, 0);
607
608         if (user_modified()) {
609                 sprintf(temp, "Hit y to save changes to file: %s  ? ",
610                         tty_basename);
611                 ptext(temp);
612                 if (wait_here() == 'y') {
613                         save_info(write_terminfo_list, &i, &j);
614                 }
615         }
616
617         put_str("\nTerminal test complete\n");
618         bye_kids(0);
619         return (0);
620 }