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