Get rid of the #define mess for other platforms. We're just Unix.
[dragonfly.git] / usr.sbin / pcvt / vttest / main.c
1 /*
2                                VTTEST.C
3
4          Written Novemeber 1983 - July 1984 by Per Lindberg,
5          Stockholm University Computer Center (QZ), Sweden.
6
7                   THE MAD PROGRAMMER STRIKES AGAIN!
8
9                    This software is (c) 1984 by QZ
10                Non-commercial use and copying allowed.
11
12 If you are developing a commercial product, and use this program to do
13 it, and that product is successful, please send a sum of money of your
14 choice to the address below.
15
16 */
17
18 /* $FreeBSD: src/usr.sbin/pcvt/vttest/main.c,v 1.4.6.1 2000/12/11 01:03:35 obrien Exp $ */
19 /* $DragonFly: src/usr.sbin/pcvt/vttest/Attic/main.c,v 1.4 2005/02/20 17:19:11 asmodai Exp $ */
20
21 #include "header.h"
22
23 char inchar(), *instr(), *lookup();
24
25 struct table {
26     int key;
27     char *msg;
28 } paritytable[] = {
29     { 1, "NONE" },
30     { 4, "ODD"  },
31     { 5, "EVEN" },
32     { -1, "" }
33 },nbitstable[] = {
34     { 1, "8" },
35     { 2, "7" },
36     { -1,"" }
37 },speedtable[] = {
38     {   0,    "50" },
39     {   8,    "75" },
40     {  16,   "110" },
41     {  24,   "132.5"},
42     {  32,   "150" },
43     {  40,   "200" },
44     {  48,   "300" },
45     {  56,   "600" },
46     {  64,  "1200" },
47     {  72,  "1800" },
48     {  80,  "2000" },
49     {  88,  "2400" },
50     {  96,  "3600" },
51     { 104,  "4800" },
52     { 112,  "9600" },
53     { 120, "19200" },
54     { -1, "" }
55 };
56
57 #ifdef USEMYSTTY
58 #ifndef stty
59 int stty(fd,ptr)
60 int fd;
61 struct sgttyb *ptr;
62 {
63         return(ioctl(fd, TIOCSETP, ptr));
64 }
65 #endif
66 #ifndef gtty
67 int gtty(fd,ptr)
68 int fd;
69 struct sgttyb *ptr;
70 {
71         return(ioctl(fd, TIOCGETP, ptr));
72 }
73 #endif
74 #endif
75
76 main() {
77
78   int menuchoice;
79
80   static char *mainmenu[] = {
81       "Exit",
82       "Test of cursor movements",
83       "Test of screen features",
84       "Test of character sets",
85       "Test of double-sized characters",
86       "Test of keyboard",
87       "Test of terminal reports",
88       "Test of VT52 mode",
89       "Test of VT102 features (Insert/Delete Char/Line)",
90       "Test of known bugs",
91       "Test of reset and self-test",
92       ""
93     };
94
95   initterminal(setjmp(intrenv));
96   signal(SIGINT, onbrk);
97   signal(SIGTERM, onterm);
98   reading = 0;
99   do {
100     ed(2);
101     cup(5,10); printf("VT100 test program, version %s", VERSION);
102     cup(7,10); println("Choose test type:");
103     menuchoice = menu(mainmenu);
104     switch (menuchoice) {
105       case 1:  tst_movements();   break;
106       case 2:  tst_screen();      break;
107       case 3:  tst_characters();  break;
108       case 4:  tst_doublesize();  break;
109       case 5:  tst_keyboard();    break;
110       case 6:  tst_reports();     break;
111       case 7:  tst_vt52();        break;
112       case 8:  tst_insdel();      break;
113       case 9:  tst_bugs();        break;
114       case 10: tst_rst();         break;
115     }
116   } while (menuchoice);
117   bye();
118 }
119
120 tst_movements() {
121
122   /* Test of:
123      CUF (Cursor Forward)
124      CUB (Cursor Backward)
125      CUD (Cursor Down)      IND (Index)  NEL (Next Line)
126      CUU (Cursor Up)        RI  (Reverse Index)
127      CUP (Cursor Position)  HVP (Horizontal and Vertical Position)
128      ED  (Erase in Display)
129      EL  (Erase in Line)
130      DECALN (Screen Alignment Display)
131      <CR> <BS>
132      Cursor control characters inside CSI sequences
133   */
134
135   int i, row, col, pass, width, hlfxtra;
136   char c, *ctext = "This is a correct sentence";
137
138   for (pass = 0; pass <= 1; pass++) {
139     if (pass == 0) { rm("?3"); width =  80; hlfxtra =  0; }
140     else           { sm("?3"); width = 132; hlfxtra = 26; }
141
142     decaln();
143     cup( 9,10+hlfxtra); ed(1);
144     cup(18,60+hlfxtra); ed(0); el(1);
145     cup( 9,71+hlfxtra); el(0);
146     for (row = 10; row <= 16; row++) {
147       cup(row, 10+hlfxtra); el(1);
148       cup(row, 71+hlfxtra); el(0);
149     }
150     cup(17,30); el(2);
151     for (col = 1; col <= width; col++) {
152       hvp(24, col); printf("*");
153       hvp( 1, col); printf("*");
154     }
155     cup(2,2);
156     for (row = 2; row <= 23; row++) {
157       printf("+");
158       cub(1);
159       ind();
160     }
161     cup(23,width-1);
162     for (row = 23; row >=2; row--) {
163       printf("+");
164       cub(1); ri();
165     }
166     cup(2,1);
167     for (row = 2; row <= 23; row++) {
168       printf("*");
169         cup(row, width);
170       printf("*");
171       cub(10);
172       if(row < 10)
173         nel();
174       else
175         printf("\n");
176     }
177     cup(2,10);
178     cub(42+hlfxtra); cuf(2);
179     for (col = 3; col <= width-2; col++) {
180       printf("+");
181       cuf(0); cub(2); cuf(1);
182     }
183     cup(23,70+hlfxtra);
184     cuf(42+hlfxtra); cub(2);
185     for (col = width-2; col >= 3; col--) {
186       printf("+");
187       cub(1); cuf(1); cub(0); printf("%c", 8);
188     }
189     cup( 1, 1); cuu(10); cuu(1); cuu(0);
190     cup(24,width); cud(10); cud(1); cud(0);
191
192     cup(10,12+hlfxtra);
193     for (row = 10; row <= 15; row++) {
194       for (col = 12+hlfxtra; col <= 69+hlfxtra; col++) printf(" ");
195       cud(1); cub(58);
196     }
197     cuu(5); cuf(1);
198     printf("The screen should be cleared,  and have an unbroken bor-");
199     cup(12,13+hlfxtra);
200     printf("der of *'s and +'s around the edge,   and exactly in the");
201     cup(13,13+hlfxtra);
202     printf("middle  there should be a frame of E's around this  text");
203     cup(14,13+hlfxtra);
204     printf("with  one (1) free position around it.    ");
205     holdit();
206   }
207   rm("?3");
208
209   ed(2);
210   cup(1,1);
211   println("Test of cursor-control characters inside ESC sequences.");
212   println("Below should be two identical lines:");
213   println("");
214   println("A B C D E F G H I J K L M N O P Q R S");
215   for (i = 1; i < 20; i++) {
216     printf("%c", 64 + i);
217     brcstr("2\010", 'C');       /* Two forward, one backspace */
218   }
219   println("");
220   println("");
221   holdit();
222
223   ed(2);
224   cup(1,1);
225   println("Test of leading zeros in ESC sequences.");
226   printf("Two lines below you should see the sentence \"%s\".",ctext);
227   for (col = 1; *ctext; col++)
228    printf("\033[00000000004;00000000%dH%c",col,*ctext++);
229   cup(20,1);
230   holdit();
231 }
232
233 tst_screen() {
234
235   /* Test of:
236      - DECSTBM (Set Top and Bottom Margins)
237      - TBC     (Tabulation Clear)
238      - HTS     (Horizontal Tabulation Set)
239      - SM RM   (Set/Reset mode): - 80/132 chars
240                                  - Origin: Realtive/absolute
241                                  - Scroll: Smooth/jump
242                                  - Wraparound
243      - SGR     (Select Graphic Rendition)
244      - SM RM   (Set/Reset Mode) - Inverse
245      - DECSC   (Save Cursor)
246      - DECRC   (Restore Cursor)
247   */
248
249   int i, j, cset, row, col, down, soft, background;
250
251   static char *tststr = "*qx`";
252   static char *attr[5] = { ";0", ";1", ";4", ";5", ";7" };
253
254   cup(1,1);
255   sm("?7");  /* Wrap Around ON */
256   for (col = 1; col <= 160; col++) printf("*");
257   rm("?7");  /* Wrap Around OFF */
258   cup(3,1);
259   for (col = 1; col <= 160; col++) printf("*");
260   sm("?7");  /* Wrap Around ON */
261   cup(5,1);
262   println("This should be three identical lines of *'s completely filling");
263   println("the top of the screen without any empty lines between.");
264   println("(Test of WRAP AROUND mode setting.)");
265   holdit();
266
267   ed(2);
268   tbc(3);
269   cup(1,1);
270   for (col = 1; col <= 78; col += 3) {
271     cuf(3); hts();
272   }
273   cup(1,4);
274   for (col = 4; col <= 78; col += 6) {
275     tbc(0); cuf(6);
276   }
277   cup(1,7); tbc(1); tbc(2); /* no-op */
278   cup(1,1); for (col = 1; col <= 78; col += 6) printf("\t*");
279   cup(2,2); for (col = 2; col <= 78; col += 6) printf("     *");
280   cup(4,1);
281   println("Test of TAB setting/resetting. These two lines");
282   printf("should look the same. ");
283   holdit();
284   for (background = 0; background <= 1; background++) {
285     if (background) rm("?5");
286     else            sm("?5");
287     sm("?3"); /* 132 cols */
288     ed(2);    /* VT100 clears screen on SM3/RM3, but not obviously, so... */
289     cup(1,1); tbc(3);
290     for (col = 1; col <= 132; col += 8) {
291       cuf(8); hts();
292     }
293     cup(1,1); for (col = 1; col <= 130; col += 10) printf("1234567890");
294     printf("12");
295     for (row = 3; row <= 20; row++) {
296       cup(row,row);
297       printf("This is 132 column mode, %s background.",
298       background ? "dark" : "light");
299     }
300     holdit();
301     rm("?3"); /* 80 cols */
302     ed(2);    /* VT100 clears screen on SM3/RM3, but not obviously, so... */
303     cup(1,1); for (col = 1; col <= 80; col += 10) printf("1234567890");
304     for (row = 3; row <= 20; row++) {
305       cup(row,row);
306       printf("This is 80 column mode, %s background.",
307       background ? "dark" : "light");
308     }
309     holdit();
310   }
311
312   ed(2);
313   sm("?6"); /* Origin mode (relative) */
314   for (soft = -1; soft <= 0; soft++) {
315     if (soft) sm("?4");
316     else      rm("?4");
317     for (row = 12; row >= 1; row -= 11) {
318       decstbm(row, 24-row+1);
319       ed(2);
320       for (down = 0; down >= -1; down--) {
321         if (down) cuu(24);
322         else      cud(24);
323         for (i = 1; i <= 30; i++) {
324           printf("%s scroll %s region %d Line %d\n",
325                  soft ? "Soft" : "Jump",
326                  down ? "down" : "up",
327                  2*(13-row), i);
328           if (down) { ri(); ri(); }
329         }
330       }
331       holdit();
332     }
333   }
334   ed(2);
335   decstbm(23,24);
336   printf(
337   "\nOrigin mode test. This line should be at the bottom of the screen.");
338   cup(1,1);
339   printf("%s",
340   "This line should be the one above the bottom of the screeen. ");
341   holdit();
342   ed(2);
343   rm("?6"); /* Origin mode (absolute) */
344   cup(24,1);
345   printf(
346   "Origin mode test. This line should be at the bottom of the screen.");
347   cup(1,1);
348   printf("%s", "This line should be at the top if the screen. ");
349   holdit();
350   decstbm(1,24);
351
352   ed(2);
353   cup( 1,20); printf("Graphic rendition test pattern:");
354   cup( 4, 1); sgr("0");         printf("vanilla");
355   cup( 4,40); sgr("0;1");       printf("bold");
356   cup( 6, 6); sgr(";4");        printf("underline");
357   cup( 6,45);sgr(";1");sgr("4");printf("bold underline");
358   cup( 8, 1); sgr("0;5");       printf("blink");
359   cup( 8,40); sgr("0;5;1");     printf("bold blink");
360   cup(10, 6); sgr("0;4;5");     printf("underline blink");
361   cup(10,45); sgr("0;1;4;5");   printf("bold underline blink");
362   cup(12, 1); sgr("1;4;5;0;7"); printf("negative");
363   cup(12,40); sgr("0;1;7");     printf("bold negative");
364   cup(14, 6); sgr("0;4;7");     printf("underline negative");
365   cup(14,45); sgr("0;1;4;7");   printf("bold underline negative");
366   cup(16, 1); sgr("1;4;;5;7");  printf("blink negative");
367   cup(16,40); sgr("0;1;5;7");   printf("bold blink negative");
368   cup(18, 6); sgr("0;4;5;7");   printf("underline blink negative");
369   cup(18,45); sgr("0;1;4;5;7"); printf("bold underline blink negative");
370   sgr("");
371
372   rm("?5"); /* Inverse video off */
373   cup(23,1); el(0); printf("Dark background. "); holdit();
374   sm("?5"); /* Inverse video */
375   cup(23,1); el(0); printf("Light background. "); holdit();
376   rm("?5");
377   ed(2);
378   cup(8,12); printf("normal");
379   cup(8,24); printf("bold");
380   cup(8,36); printf("underscored");
381   cup(8,48); printf("blinking");
382   cup(8,60); printf("reversed");
383   cup(10,1); printf("stars:");
384   cup(12,1); printf("line:");
385   cup(14,1); printf("x'es:");
386   cup(16,1); printf("diamonds:");
387   for (cset = 0; cset <= 3; cset++) {
388     for (i = 0; i <= 4; i++) {
389     cup(10 + 2 * cset, 12 + 12 * i);
390     sgr(attr[i]);
391     if (cset == 0 || cset == 2) scs(0,'B');
392     else                        scs(0,'0');
393       for (j = 0; j <= 4; j++) {
394         printf("%c", tststr[cset]);
395       }
396       decsc();
397       cup(cset + 1, i + 1); sgr(""); scs(0,'B'); printf("A");
398       decrc();
399       for (j = 0; j <= 4; j++) {
400         printf("%c", tststr[cset]);
401       }
402     }
403   }
404   sgr("0"); scs(0,'B'); cup(21,1);
405   println("Test of the SAVE/RESTORE CURSOR feature. There should");
406   println("be ten characters of each flavour, and a rectangle");
407   println("of 5 x 4 A's filling the top left of the screen.");
408   holdit();
409 }
410
411 tst_characters() {
412   /* Test of:
413      SCS    (Select character Set)
414   */
415
416   int i, j, g, cset;
417   char chcode[5], *setmsg[5];
418
419   chcode[0] = 'A';
420   chcode[1] = 'B';
421   chcode[2] = '0';
422   chcode[3] = '1';
423   chcode[4] = '2';
424   setmsg[0] = "UK / national";
425   setmsg[1] = "US ASCII";
426   setmsg[2] = "Special graphics and line drawing";
427   setmsg[3] = "Alternate character ROM standard characters";
428   setmsg[4] = "Alternate character ROM special graphics";
429
430   cup(1,10); printf("Selected as G0 (with SI)");
431   cup(1,48); printf("Selected as G1 (with SO)");
432   for (cset = 0; cset <= 4; cset++) {
433     scs(1,'B');
434     cup(3 + 4 * cset, 1);
435     sgr("1");
436     printf("Character set %c (%s)",chcode[cset], setmsg[cset]);
437     sgr("0");
438     for (g = 0; g <= 1; g++) {
439       scs(g,chcode[cset]);
440       for (i = 1; i <= 3; i++) {
441         cup(3 + 4 * cset + i, 10 + 38 * g);
442         for (j = 0; j <= 31; j++) {
443           printf("%c", i * 32 + j);
444         }
445       }
446     }
447   }
448   scs(1,'B');
449   cup(24,1); printf("These are the installed character sets. ");
450   holdit();
451 }
452
453 tst_doublesize() {
454   /* Test of:
455      DECSWL  (Single Width Line)
456      DECDWL  (Double Width Line)
457      DECDHL  (Double Height Line) (also implicit double width)
458   */
459
460   int col, i, w, w1;
461
462   /* Print the test pattern in both 80 and 132 character width  */
463
464   for(w = 0; w <= 1; w++) {
465     w1 = 13 * w;
466
467     ed(2);
468     cup(1, 1);
469     if (w) { sm("?3"); printf("132 column mode"); }
470     else   { rm("?3"); printf(" 80 column mode"); }
471
472     cup( 5, 3 + 2 * w1);
473     printf("v------- left margin");
474
475     cup( 7, 3 + 2 * w1);
476     printf("This is a normal-sized line");
477     decdhl(0); decdhl(1); decdwl(); decswl();
478
479     cup( 9, 2 + w1);
480     printf("This is a Double-width line");
481     decswl(); decdhl(0); decdhl(1); decdwl();
482
483     cup(11, 2 + w1);
484     decdwl(); decswl(); decdhl(1); decdhl(0);
485     printf("This is a Double-width-and-height line");
486     cup(12, 2 + w1);
487     decdwl(); decswl(); decdhl(0); decdhl(1);
488     printf("This is a Double-width-and-height line");
489
490     cup(14, 2 + w1);
491     decdwl(); decswl(); decdhl(1); decdhl(0); el(2);
492     printf("This is another such line");
493     cup(15, 2 + w1);
494     decdwl(); decswl(); decdhl(0); decdhl(1);
495     printf("This is another such line");
496
497     cup(17, 3 + 2 * w1);
498     printf("^------- left margin");
499
500     cup(21, 1);
501     printf("This is not a double-width line");
502     for (i = 0; i <= 1; i++) {
503       cup(21,6);
504       if (i) { printf("**is**"); decdwl(); }
505       else   { printf("is not"); decswl(); }
506       cup(23,1); holdit();
507     }
508   }
509   /* Set vanilla tabs for next test */
510   cup(1,1); tbc(3); for (col = 1; col <= 132; col += 8) { cuf(8); hts(); }
511   rm("?3");
512   ed(2);
513   scs(0,'0');
514
515   cup( 8,1); decdhl(0); printf("lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk");
516   cup( 9,1); decdhl(1); printf("lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk");
517   cup(10,1); decdhl(0); printf("x%c%c%c%c%cx",9,9,9,9,9);
518   cup(11,1); decdhl(1); printf("x%c%c%c%c%cx",9,9,9,9,9);
519   cup(12,1); decdhl(0); printf("x%c%c%c%c%cx",9,9,9,9,9);
520   cup(13,1); decdhl(1); printf("x%c%c%c%c%cx",9,9,9,9,9);
521   cup(14,1); decdhl(0); printf("x                                      x");
522   cup(15,1); decdhl(1); printf("x                                      x");
523   cup(16,1); decdhl(0); printf("mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj");
524   cup(17,1); decdhl(1); printf("mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj");
525   scs(0,'B'); sgr("1;5");
526   cup(12,3);
527   printf("* The mad programmer strikes again * ");
528   cup(13,3); printf("%c",9); cub(6);
529   printf("* The mad programmer strikes again *");
530   sgr("0");
531   cup(22,1);
532   println("Another test pattern...  a frame with blinking bold text,");
533   printf("all in double-height double-width size. ");
534   holdit();
535
536   decstbm(8,24); /* Absolute origin mode, so cursor is set at (1,1) */
537   cup(8,1);
538   for (i = 1; i <= 12; i++)
539     ri();
540   decstbm(0,0); /* No scroll region     */
541   cup(1,1);
542   printf("%s", "Exactly half of the box should remain. ");
543   holdit();
544 }
545
546 tst_keyboard() {
547
548 /* Test of:
549      - DECLL   (Load LEDs)
550      - Keyboard return messages
551      - SM RM   (Set/Reset Mode) - Cursor Keys
552                                 - Auto repeat
553      - DECKPAM (Keypad Application Mode)
554      - DECKPNM (Keypad Numeric Mode)
555
556 The standard VT100 keayboard layout:
557
558                                                         UP   DN   LE  RI
559
560 ESC   1!   2@   3#   4$   5%   6^   7&   8*   9(   0)   -_   =+   `~  BS
561
562 TAB*    qQ   wW   eE   rR   tT   yY   uU   iI   oO   pP   [{   ]}      DEL
563
564 **   **   aA   sS   dD   fF   gG   hH   jJ   kK   lL   ;:   ,"   RETN  \|
565
566 **   ****   zZ   xX   cC   vV   bB   nN   mM   ,<   .>   /?   ****   LF
567
568              ****************SPACE BAR****************
569
570                                                            PF1 PF2 PF3 PF4
571
572                                                            *7* *8* *9* *-*
573
574                                                            *4* *5* *6* *,*
575
576                                                            *1* *2* *3*
577
578                                                            ***0*** *.* ENT
579 */
580
581   char *ledmsg[6], *ledseq[6];
582
583   int  i, j, okflag;
584   int  kblayout;
585   int  ckeymode;
586   int  fkeymode;
587   char kbdc;
588   char *kbds = " ";
589   char *curkeystr, *fnkeystr, *abmstr;
590   char arptstring[500];
591
592   static struct key {
593       char c;
594       int  row;
595       int  col;
596       char *symbol;
597   } keytab [] = {
598       { 27, 1,  0, "ESC" },
599       { '1', 1,  6, "1" },    { '!', 1,  7, "!" },
600       { '2', 1, 11, "2" },    { '@', 1, 12, "@" },
601       { '3', 1, 16, "3" },    { '#', 1, 17, "#" },
602       { '4', 1, 21, "4" },    { '$', 1, 22, "$" },
603       { '5', 1, 26, "5" },    { '%', 1, 27, "%" },
604       { '6', 1, 31, "6" },    { '^', 1, 32, "^" },
605       { '7', 1, 36, "7" },    { '&', 1, 37, "&" },
606       { '8', 1, 41, "8" },    { '*', 1, 42, "*" },
607       { '9', 1, 46, "9" },    { '(', 1, 47, "(" },
608       { '0', 1, 51, "0" },    { ')', 1, 52, ")" },
609       { '-', 1, 56, "-" },    { '_', 1, 57, "_" },
610       { '=', 1, 61, "=" },    { '+', 1, 62, "+" },
611       { '`', 1, 66, "`" },    { '~', 1, 67, "~" },
612       {   8, 1, 70, "BS" },
613       {   9, 2,  0, " TAB " },
614       { 'q', 2,  8, "q" },    { 'Q', 2,  9, "Q" },
615       { 'w', 2, 13, "w" },    { 'W', 2, 14, "W" },
616       { 'e', 2, 18, "e" },    { 'E', 2, 19, "E" },
617       { 'r', 2, 23, "r" },    { 'R', 2, 24, "R" },
618       { 't', 2, 28, "t" },    { 'T', 2, 29, "T" },
619       { 'y', 2, 33, "y" },    { 'Y', 2, 34, "Y" },
620       { 'u', 2, 38, "u" },    { 'U', 2, 39, "U" },
621       { 'i', 2, 43, "i" },    { 'I', 2, 44, "I" },
622       { 'o', 2, 48, "o" },    { 'O', 2, 49, "O" },
623       { 'p', 2, 53, "p" },    { 'P', 2, 54, "P" },
624       { '[', 2, 58, "[" },    { '{', 2, 59, "{" },
625       { ']', 2, 63, "]" },    { '}', 2, 64, "}" },
626       { 127, 2, 71, "DEL" },
627       { 'a', 3, 10, "a" },    { 'A', 3, 11, "A" },
628       { 's', 3, 15, "s" },    { 'S', 3, 16, "S" },
629       { 'd', 3, 20, "d" },    { 'D', 3, 21, "D" },
630       { 'f', 3, 25, "f" },    { 'F', 3, 26, "F" },
631       { 'g', 3, 30, "g" },    { 'G', 3, 31, "G" },
632       { 'h', 3, 35, "h" },    { 'H', 3, 36, "H" },
633       { 'j', 3, 40, "j" },    { 'J', 3, 41, "J" },
634       { 'k', 3, 45, "k" },    { 'K', 3, 46, "K" },
635       { 'l', 3, 50, "l" },    { 'L', 3, 51, "L" },
636       { ';', 3, 55, ";" },    { ':', 3, 56, ":" },
637       {'\'', 3, 60, "'" },    { '"', 3, 61,"\"" },
638       {  13, 3, 65, "RETN"},
639       {'\\', 3, 71,"\\" },    { '|', 3, 72, "|" },
640       { 'z', 4, 12, "z" },    { 'Z', 4, 13, "Z" },
641       { 'x', 4, 17, "x" },    { 'X', 4, 18, "X" },
642       { 'c', 4, 22, "c" },    { 'C', 4, 23, "C" },
643       { 'v', 4, 27, "v" },    { 'V', 4, 28, "V" },
644       { 'b', 4, 32, "b" },    { 'B', 4, 33, "B" },
645       { 'n', 4, 37, "n" },    { 'N', 4, 38, "N" },
646       { 'm', 4, 42, "m" },    { 'M', 4, 43, "M" },
647       { ',', 4, 47, "," },    { '<', 4, 48, "<" },
648       { '.', 4, 52, "." },    { '>', 4, 53, ">" },
649       { '/', 4, 57, "/" },    { '?', 4, 58, "?" },
650       {  10, 4, 69, "LF" },
651       { ' ', 5, 13, "                SPACE BAR                "},
652       {'\0', 0,  0, ""  }
653     };
654
655   static struct natkey {
656       char natc;
657       int  natrow;
658       int  natcol;
659       char *natsymbol;
660   } natkeytab [][29] = {
661       {
662         { '"', 1, 12, "\""},
663         { '&', 1, 32, "&" },
664         { '/', 1, 37, "/" },
665         { '(', 1, 42, "(" },
666         { ')', 1, 47, ")" },
667         { '=', 1, 52, "=" },
668         { '+', 1, 56, "+" },    { '?', 1, 57, "?" },
669         { '`', 1, 61, "`" },    { '@', 1, 62, "@" },
670         { '<', 1, 66, "<" },    { '>', 1, 67, ">" },
671         { '}', 2, 58, "}" },    { ']', 2, 59, "]" },
672         { '^', 2, 63, "^" },    { '~', 2, 64, "~" },
673         { '|', 3, 55, "|" },    {'\\', 3, 56,"\\" },
674         { '{', 3, 60, "{" },    { '[', 3, 61, "[" },
675         {'\'', 3, 71, "'" },    { '*', 3, 72, "*" },
676         { ',', 4, 47, "," },    { ';', 4, 48, ";" },
677         { '.', 4, 52, "." },    { ':', 4, 53, ":" },
678         { '-', 4, 57, "-" },    { '_', 4, 58, "_" },
679         {'\0', 0,  0, ""  }
680       },
681       {
682         { '"', 1, 12, "\""},
683         { '&', 1, 32, "&" },
684         { '/', 1, 37, "/" },
685         { '(', 1, 42, "(" },
686         { ')', 1, 47, ")" },
687         { '=', 1, 52, "=" },
688         { '+', 1, 56, "+" },    { '?', 1, 57, "?" },
689         { '`', 1, 61, "`" },    { '@', 1, 62, "@" },
690         { '<', 1, 66, "<" },    { '>', 1, 67, ">" },
691         { '}', 2, 58, "}" },    { ']', 2, 59, "]" },
692         { '~', 2, 63, "~" },    { '^', 2, 64, "^" },
693         { '|', 3, 55, "|" },    {'\\', 3, 56,"\\" },
694         { '{', 3, 60, "{" },    { '[', 3, 61, "[" },
695         {'\'', 3, 71, "'" },    { '*', 3, 72, "*" },
696         { ',', 4, 47, "," },    { ';', 4, 48, ";" },
697         { '.', 4, 52, "." },    { ':', 4, 53, ":" },
698         { '-', 4, 57, "-" },    { '_', 4, 58, "_" },
699         {'\0', 0,  0, ""  }
700       }
701   };
702
703   static struct curkey {
704       char *curkeymsg[3];
705       int  curkeyrow;
706       int  curkeycol;
707       char *curkeysymbol;
708       char *curkeyname;
709   } curkeytab [] = {
710
711       /* A Reset, A Set,  VT52  */
712
713       {{"\033[A","\033OA","\033A"}, 0, 56, "UP",  "Up arrow"   },
714       {{"\033[B","\033OB","\033B"}, 0, 61, "DN",  "Down arrow" },
715       {{"\033[D","\033OD","\033D"}, 0, 66, "LT",  "Left arrow" },
716       {{"\033[C","\033OC","\033C"}, 0, 71, "RT",  "Right arrow"},
717       {{"",      "",       ""     }, 0,  0, "",    "" }
718   };
719
720   static struct fnkey {
721       char *fnkeymsg[4];
722       int  fnkeyrow;
723       int  fnkeycol;
724       char *fnkeysymbol;
725       char *fnkeyname;
726   } fnkeytab [] = {
727
728       /* ANSI-num,ANSI-app,VT52-nu,VT52-ap,  r, c,  symb   name         */
729
730       {{"\033OP","\033OP","\033P","\033P" }, 6, 59, "PF1", "PF1"        },
731       {{"\033OQ","\033OQ","\033Q","\033Q" }, 6, 63, "PF2", "PF2"        },
732       {{"\033OR","\033OR","\033R","\033R" }, 6, 67, "PF3", "PF3"        },
733       {{"\033OS","\033OS","\033S","\033S" }, 6, 71, "PF4", "PF4"        },
734       {{"7",     "\033Ow","7",    "\033?w"}, 7, 59, " 7 ", "Numeric 7"  },
735       {{"8",     "\033Ox","8",    "\033?x"}, 7, 63, " 8 ", "Numeric 8"  },
736       {{"9",     "\033Oy","9",    "\033?y"}, 7, 67, " 9 ", "Numeric 9"  },
737       {{"-",     "\033Om","-",    "\033?m"}, 7, 71, " - ", "Minus"      },
738       {{"4",     "\033Ot","4",    "\033?t"}, 8, 59, " 4 ", "Numeric 4"  },
739       {{"5",     "\033Ou","5",    "\033?u"}, 8, 63, " 5 ", "Numeric 5"  },
740       {{"6",     "\033Ov","6",    "\033?v"}, 8, 67, " 6 ", "Numeric 6"  },
741       {{",",     "\033Ol",",",    "\033?l"}, 8, 71, " , ", "Comma"      },
742       {{"1",     "\033Oq","1",    "\033?q"}, 9, 59, " 1 ", "Numeric 1"  },
743       {{"2",     "\033Or","2",    "\033?r"}, 9, 63, " 2 ", "Numeric 2"  },
744       {{"3",     "\033Os","3",    "\033?s"}, 9, 67, " 3 ", "Numeric 3"  },
745       {{"0",     "\033Op","0",    "\033?p"},10, 59,"   O   ","Numeric 0"},
746       {{".",     "\033On",".",    "\033?n"},10, 67, " . ", "Point"      },
747       {{"\015",  "\033OM","\015", "\033?M"},10, 71, "ENT", "ENTER"      },
748       {{"","","",""},       0,  0, "",    ""           }
749     };
750
751   static struct ckey {
752       int  ccount;
753       char *csymbol;
754   } ckeytab [] = {
755       { 0, "NUL (CTRL-@ or CTRL-Space)" },
756       { 0, "SOH (CTRL-A)" },
757       { 0, "STX (CTRL-B)" },
758       { 0, "ETX (CTRL-C)" },
759       { 0, "EOT (CTRL-D)" },
760       { 0, "ENQ (CTRL-E)" },
761       { 0, "ACK (CTRL-F)" },
762       { 0, "BEL (CTRL-G)" },
763       { 0, "BS  (CTRL-H) (BACK SPACE)" },
764       { 0, "HT  (CTRL-I) (TAB)" },
765       { 0, "LF  (CTRL-J) (LINE FEED)" },
766       { 0, "VT  (CTRL-K)" },
767       { 0, "FF  (CTRL-L)" },
768       { 0, "CR  (CTRL-M) (RETURN)" },
769       { 0, "SO  (CTRL-N)" },
770       { 0, "SI  (CTRL-O)" },
771       { 0, "DLE (CTRL-P)" },
772       { 0, "DC1 (CTRL-Q) (X-On)" },
773       { 0, "DC2 (CTRL-R)" },
774       { 0, "DC3 (CTRL-S) (X-Off)" },
775       { 0, "DC4 (CTRL-T)" },
776       { 0, "NAK (CTRL-U)" },
777       { 0, "SYN (CTRL-V)" },
778       { 0, "ETB (CTRL-W)" },
779       { 0, "CAN (CTRL-X)" },
780       { 0, "EM  (CTRL-Y)" },
781       { 0, "SUB (CTRL-Z)" },
782       { 0, "ESC (CTRL-[) (ESCAPE)" },
783       { 0, "FS  (CTRL-\\ or CTRL-? or CTRL-_)" },
784       { 0, "GS  (CTRL-])" },
785       { 0, "RS  (CTRL-^ or CTRL-~ or CTRL-`)" },
786       { 0, "US  (CTRL-_ or CTRL-?)" }
787   };
788
789   static char *keyboardmenu[] = {
790       "Standard American ASCII layout",
791       "Swedish national layout D47",
792       "Swedish national layout E47",
793       /* add new keyboard layouts here */
794       ""
795     };
796
797   static char *curkeymodes[3] = {
798       "ANSI / Cursor key mode RESET",
799       "ANSI / Cursor key mode SET",
800       "VT52 Mode"
801   };
802
803   static char *fnkeymodes[4] = {
804       "ANSI Numeric mode",
805       "ANSI Application mode",
806       "VT52 Numeric mode",
807       "VT52 Application mode"
808   };
809
810   ledmsg[0] = "L1 L2 L3 L4"; ledseq[0] = "1;2;3;4";
811   ledmsg[1] = "   L2 L3 L4"; ledseq[1] = "1;0;4;3;2";
812   ledmsg[2] = "   L2 L3";    ledseq[2] = "1;4;;2;3";
813   ledmsg[3] = "L1 L2";       ledseq[3] = ";;2;1";
814   ledmsg[4] = "L1";          ledseq[4] = "1";
815   ledmsg[5] = "";            ledseq[5] = "";
816
817   fflush(stdout);
818   ed(2);
819   cup(10,1);
820   println("These LEDs (\"lamps\") on the keyboard should be on:");
821   for (i = 0; i <= 5; i++) {
822     cup(10,52); el(0); printf("%s", ledmsg[i]);
823     decll("0");
824     decll(ledseq[i]);
825     cup(12,1); holdit();
826   }
827
828   ed(2);
829   cup(10,1);
830   println("Test of the AUTO REPEAT feature");
831   println("");
832   println("Hold down an alphanumeric key for a while, then push RETURN.");
833   printf("%s", "Auto Repeat OFF: ");
834   rm("?8");
835   inputline(arptstring);
836   if (strlen(arptstring) == 0)      println("No characters read!??");
837   else if (strlen(arptstring) == 1) println("OK.");
838   else                              println("Too many characters read.");
839   println("");
840   println("Hold down an alphanumeric key for a while, then push RETURN.");
841   printf("%s", "Auto Repeat ON: ");
842   sm("?8");
843   inputline(arptstring);
844   if (strlen(arptstring) == 0)      println("No characters read!??");
845   else if (strlen(arptstring) == 1) println("Not enough characters read.");
846   else                              println("OK.");
847   println("");
848   holdit();
849
850   ed(2);
851   cup(5,10);
852   println("Choose keyboard layout:");
853   kblayout = menu(keyboardmenu);
854   if (kblayout) {
855     kblayout--;
856     for (j = 0; natkeytab[kblayout][j].natc != '\0'; j++) {
857       for (i = 0; keytab[i].c != '\0'; i++) {
858         if (keytab[i].row == natkeytab[kblayout][j].natrow &&
859             keytab[i].col == natkeytab[kblayout][j].natcol) {
860           keytab[i].c = natkeytab[kblayout][j].natc;
861           keytab[i].symbol = natkeytab[kblayout][j].natsymbol;
862           break;
863         }
864       }
865     }
866   }
867
868   ed(2);
869   for (i = 0; keytab[i].c != '\0'; i++) {
870     cup(1 + 2 * keytab[i].row, 1 + keytab[i].col);
871     sgr("7");
872     printf("%s", keytab[i].symbol);
873     sgr("");
874   }
875   cup(22,1);
876   sgttyNew.sg_flags &= ~CRMOD;
877   sgttyNew.sg_flags &= ~ECHO;
878   stty(0, &sgttyNew);
879   inflush();
880   printf("Press each key, both shifted and unshifted. Finish with RETURN:");
881   do { /* while (kbdc != 13) */
882     cup(23,1); kbdc = inchar();
883     cup(23,1); el(0);
884     sprintf(kbds, "%c", kbdc);
885     chrprint(kbds);
886     for (i = 0; keytab[i].c != '\0'; i++) {
887       if (keytab[i].c == kbdc) {
888         cup(1 + 2 * keytab[i].row, 1 + keytab[i].col);
889         printf("%s", keytab[i].symbol);
890         break;
891       }
892     }
893   } while (kbdc != 13);
894   cup(23,1); el(0);
895
896   for (ckeymode = 0; ckeymode <= 2; ckeymode++) {
897     if (ckeymode) sm("?1");
898     else            rm("?1");
899     for (i = 0; curkeytab[i].curkeysymbol[0] != '\0'; i++) {
900       cup(1 + 2 * curkeytab[i].curkeyrow, 1 + curkeytab[i].curkeycol);
901       sgr("7");
902       printf("%s", curkeytab[i].curkeysymbol);
903       sgr("");
904     }
905     cup(20,1); printf("<%s>%20s", curkeymodes[ckeymode], "");
906     cup(22,1); el(0);
907     cup(22,1); printf("%s", "Press each cursor key. Finish with TAB.");
908     for(;;) {
909       cup(23,1);
910       if (ckeymode == 2) rm("?2"); /* VT52 mode */
911       curkeystr = instr();
912       esc("<");                      /* ANSI mode */
913       cup(23,1); el(0);
914       cup(23,1); chrprint(curkeystr);
915       if (!strcmp(curkeystr,"\t")) break;
916       for (i = 0; curkeytab[i].curkeysymbol[0] != '\0'; i++) {
917         if (!strcmp(curkeystr,curkeytab[i].curkeymsg[ckeymode])) {
918           sgr("7");
919           printf(" (%s key) ", curkeytab[i].curkeyname);
920           sgr("");
921           cup(1 + 2 * curkeytab[i].curkeyrow,
922               1 + curkeytab[i].curkeycol);
923           printf("%s", curkeytab[i].curkeysymbol);
924           break;
925         }
926       }
927       if (i == sizeof(curkeytab) / sizeof(struct curkey) - 1) {
928         sgr("7");
929         printf("%s", " (Unknown cursor key) ");
930         sgr("");
931       }
932     }
933   }
934
935   for (fkeymode = 0; fkeymode <= 3; fkeymode++) {
936     for (i = 0; fnkeytab[i].fnkeysymbol[0] != '\0'; i++) {
937       cup(1 + 2 * fnkeytab[i].fnkeyrow, 1 + fnkeytab[i].fnkeycol);
938       sgr("7");
939       printf("%s", fnkeytab[i].fnkeysymbol);
940       sgr("");
941     }
942     cup(20,1); printf("<%s>%20s", fnkeymodes[fkeymode], "");
943     cup(22,1); el(0);
944     cup(22,1); printf("%s", "Press each function key. Finish with TAB.");
945     for(;;) {
946       cup(23,1);
947       if (fkeymode >= 2)  rm("?2");    /* VT52 mode */
948       if (fkeymode % 2)   deckpam();   /* Application mode */
949       else                 deckpnm();   /* Numeric mode     */
950       fnkeystr = instr();
951       esc("<");                         /* ANSI mode */
952       cup(23,1); el(0);
953       cup(23,1); chrprint(fnkeystr);
954       if (!strcmp(fnkeystr,"\t")) break;
955       for (i = 0; fnkeytab[i].fnkeysymbol[0] != '\0'; i++) {
956         if (!strcmp(fnkeystr,fnkeytab[i].fnkeymsg[fkeymode])) {
957           sgr("7");
958           printf(" (%s key) ", fnkeytab[i].fnkeyname);
959           sgr("");
960           cup(1 + 2 * fnkeytab[i].fnkeyrow, 1 + fnkeytab[i].fnkeycol);
961           printf("%s", fnkeytab[i].fnkeysymbol);
962           break;
963         }
964       }
965       if (i == sizeof(fnkeytab) / sizeof(struct fnkey) - 1) {
966         sgr("7");
967         printf("%s", " (Unknown function key) ");
968         sgr("");
969       }
970     }
971   }
972
973   sgttyNew.sg_flags |= CRMOD;
974   stty(0, &sgttyNew);
975   ed(2);
976   cup(5,1);
977   println("Finally, a check of the ANSWERBACK MESSAGE, which can be sent");
978   println("by pressing CTRL-BREAK. The answerback message can be loaded");
979   println("in SET-UP B by pressing SHIFT-A and typing e.g.");
980   println("");
981   println("         \" H e l l o , w o r l d Return \"");
982   println("");
983   println("(the double-quote characters included).  Do that, and then try");
984   println("to send an answerback message with CTRL-BREAK.  If it works,");
985   println("the answerback message should be displayed in reverse mode.");
986   println("Finish with a single RETURN.");
987
988   sgttyNew.sg_flags &= ~CRMOD;
989   stty(0, &sgttyNew);
990   do {
991     cup(17,1);
992     inflush();
993     abmstr = instr();
994     cup(17,1);
995     el(0);
996     chrprint(abmstr);
997   } while (strcmp(abmstr,"\r"));
998
999   ed(2);
1000   for (i = 0; i < 32; i++) {
1001     cup(1 + (i % 16), 1 + 40 * (i / 16));
1002     sgr("7");
1003     printf("%s", ckeytab[i].csymbol);
1004     sgr("0");
1005   }
1006   cup(19,1);
1007   sgttyNew.sg_flags |= CRMOD;
1008   stty(0, &sgttyNew);
1009   println(
1010   "Push each CTRL-key TWICE. Note that you should be able to send *all*");
1011   println(
1012   "CTRL-codes twice, including CTRL-S (X-Off) and CTRL-Q (X-Off)!");
1013   println(
1014   "Finish with DEL (also called DELETE or RUB OUT), or wait 1 minute.");
1015   sgttyNew.sg_flags |= RAW;
1016   stty(0, &sgttyNew);
1017   ttybin(1);
1018   do {
1019     cup(23,1); kbdc = inchar();
1020     cup(23,1); el(0);
1021     if (kbdc < 32) printf("  %s", ckeytab[kbdc].csymbol);
1022     else {
1023       sprintf(kbds, "%c", kbdc);
1024       chrprint(kbds);
1025       printf("%s", " -- not a CTRL key");
1026     }
1027     if (kbdc < 32) ckeytab[kbdc].ccount++;
1028     if (ckeytab[kbdc].ccount == 2) {
1029       cup(1 + (kbdc % 16), 1 + 40 * (kbdc / 16));
1030       printf("%s", ckeytab[kbdc].csymbol);
1031     }
1032   } while (kbdc != '\177');
1033   sgttyNew.sg_flags &= ~RAW;
1034   sgttyNew.sg_flags |= ECHO;
1035   stty(0, &sgttyNew);
1036   ttybin(0);
1037   cup(24,1);
1038   okflag = 1;
1039   for (i = 0; i < 32; i++) if (ckeytab[i].ccount < 2) okflag = 0;
1040   if (okflag) printf("%s", "OK. ");
1041   else        printf("%s", "You have not been able to send all CTRL keys! ");
1042   holdit();
1043 }
1044
1045 tst_reports() {
1046   /* Test of:
1047        <ENQ>       (AnswerBack Message)
1048        SM RM       (Set/Reset Mode) - LineFeed / Newline
1049        DSR         (Device Status Report)
1050        DA          (Device Attributes)
1051        DECREQTPARM (Request Terminal Parameters)
1052   */
1053
1054   int parity, nbits, xspeed, rspeed, clkmul, flags;
1055   int i, reportpos;
1056   char *report, *report2;
1057   static char *attributes[][2] = {
1058     { "\033[?1;0c",   "No options (vanilla VT100)" },
1059     { "\033[?1;1c",   "VT100 with STP" },
1060     { "\033[?1;2c",   "VT100 with AVO (could be a VT102)" },
1061     { "\033[?1;3c",   "VT100 with STP and AVO" },
1062     { "\033[?1;4c",   "VT100 with GPO" },
1063     { "\033[?1;5c",   "VT100 with STP and GPO" },
1064     { "\033[?1;6c",   "VT100 with AVO and GPO" },
1065     { "\033[?1;7c",   "VT100 with STP, AVO and GPO" },
1066     { "\033[?1;11c",  "VT100 with PP and AVO" },
1067     { "\033[?1;15c",  "VT100 with PP, GPO and AVO" },
1068     { "\033[?4;2c",   "VT132 with AVO" },
1069     { "\033[?4;3c",   "VT132 with AVO and STP" },
1070     { "\033[?4;6c",   "VT132 with GPO and AVO" },
1071     { "\033[?4;7c",   "VT132 with GPO, AVO, and STP" },
1072     { "\033[?4;11c",  "VT132 with PP and AVO" },
1073     { "\033[?4;15c",  "VT132 with PP, GPO and AVO" },
1074     { "\033[?7c",     "VT131" },
1075     { "\033[?12;5c",  "VT125" },           /* VT125 also has ROM version */
1076     { "\033[?12;7c",  "VT125 with AVO" },  /* number, so this won't work */
1077     { "\033[?5;0c",   "VK100 (GIGI)" },
1078     { "\033[?5c",     "VK100 (GIGI)" },
1079     { "", "" }
1080   };
1081
1082   sgttyNew.sg_flags &= ~ECHO;
1083   stty(0, &sgttyNew);
1084   cup(5,1);
1085   println("This is a test of the ANSWERBACK MESSAGE. (To load the A.B.M.");
1086   println("see the TEST KEYBOARD part of this program). Below here, the");
1087   println("current answerback message in your terminal should be");
1088   println("displayed. Finish this test with RETURN.");
1089   cup(10,1);
1090   inflush();
1091   printf("%c", 5); /* ENQ */
1092   report = instr();
1093   cup(10,1);
1094   chrprint(report);
1095   cup(12,1);
1096   holdit();
1097
1098   ed(2);
1099   cup(1,1);
1100   println("Test of LineFeed/NewLine mode.");
1101   cup(3,1);
1102   sm("20");
1103   sgttyNew.sg_flags &= ~CRMOD;
1104   stty(0, &sgttyNew);
1105   printf("NewLine mode set. Push the RETURN key: ");
1106   report = instr();
1107   cup(4,1);
1108   el(0);
1109   chrprint(report);
1110   if (!strcmp(report, "\015\012")) printf(" -- OK");
1111   else                             printf(" -- Not expected");
1112   cup(6,1);
1113   rm("20");
1114   printf("NewLine mode reset. Push the RETURN key: ");
1115   report = instr();
1116   cup(7,1);
1117   el(0);
1118   chrprint(report);
1119   if (!strcmp(report, "\015")) printf(" -- OK");
1120   else                         printf(" -- Not expected");
1121   cup(9,1);
1122   sgttyNew.sg_flags |= CRMOD;
1123   stty(0, &sgttyNew);
1124   holdit();
1125
1126   ed(2);
1127   cup(1,1);
1128   printf("Test of Device Status Report 5 (report terminal status).");
1129   cup(2,1);
1130   dsr(5);
1131   report = instr();
1132   cup(2,1);
1133   el(0);
1134   printf("Report is: ");
1135   chrprint(report);
1136   if      (!strcmp(report,"\033[0n")) printf(" -- means \"TERMINAL OK\"");
1137   else if (!strcmp(report,"\033[3n")) printf(" -- means \"TERMINAL OK\"");
1138   else                                printf(" -- Unknown response!");
1139
1140   cup(4,1);
1141   println("Test of Device Status Report 6 (report cursor position).");
1142   cup(5,1);
1143   dsr(6);
1144   report = instr();
1145   cup(5,1);
1146   el(0);
1147   printf("Report is: ");
1148   chrprint(report);
1149   if (!strcmp(report,"\033[5;1R")) printf(" -- OK");
1150   else                             printf(" -- Unknown response!");
1151
1152   cup(7,1);
1153   println("Test of Device Attributes report (what are you)");
1154   cup(8,1);
1155   da(0);
1156   report = instr();
1157   cup(8,1);
1158   el(0);
1159   printf("Report is: ");
1160   chrprint(report);
1161   for (i = 0; *attributes[i][0] != '\0'; i++) {
1162     if (!strcmp(report,attributes[i][0])) break;
1163   }
1164   if (*attributes[i][0] == '\0')
1165   printf(" -- Unknown response, refer to the manual");
1166   else {
1167     printf(" -- means %s", attributes[i][1]);
1168     if (i) {
1169       cup(9,1);
1170       println("Legend: STP = Processor Option");
1171       println("        AVO = Advanced Video Option");
1172       println("        GPO = Graphics Processor Option");
1173       println("        PP  = Printer Port");
1174     }
1175   }
1176
1177   cup(14,1);
1178   println("Test of the \"Request Terminal Parameters\" feature, argument 0.");
1179   cup(15,1);
1180   decreqtparm(0);
1181   report = instr();
1182   cup(15,1);
1183   el(0);
1184   printf("Report is: ");
1185   chrprint(report);
1186   if (strlen(report) < 16
1187    || report[0] != '\033'
1188    || report[1] != '['
1189    || report[2] != '2'
1190    || report[3] != ';')
1191   println(" -- Bad format");
1192   else {
1193     reportpos = 4;
1194     parity = scanto(report, &reportpos, ';');
1195     nbits  = scanto(report, &reportpos, ';');
1196     xspeed = scanto(report, &reportpos, ';');
1197     rspeed = scanto(report, &reportpos, ';');
1198     clkmul = scanto(report, &reportpos, ';');
1199     flags  = scanto(report, &reportpos, 'x');
1200     if (parity == 0 || nbits == 0 || clkmul == 0) println(" -- Bad format");
1201     else                                          println(" -- OK");
1202     printf(
1203     "This means: Parity %s, %s bits, xmitspeed %s, recvspeed %s.\n",
1204     lookup(paritytable, parity),
1205     lookup(nbitstable, nbits),
1206     lookup(speedtable, xspeed),
1207     lookup(speedtable, rspeed));
1208     printf("(CLoCk MULtiplier = %d, STP option flags = %d)\n", clkmul, flags);
1209   }
1210
1211   cup(19,1);
1212   println("Test of the \"Request Terminal Parameters\" feature, argument 1.");
1213   cup(20,1);
1214   decreqtparm(1);       /* Does the same as decreqtparm(0), reports "3" */
1215   report2 = instr();
1216   cup(20,1);
1217   el(0);
1218   printf("Report is: ");
1219   chrprint(report2);
1220   if (strlen(report2) < 3
1221    || report2[2] != '3')
1222   println(" -- Bad format");
1223   else {
1224     report2[2] = '2';
1225     if (!strcmp(report,report2)) println(" -- OK");
1226     else                         println(" -- Bad format");
1227   }
1228   cup(24,1);
1229   holdit();
1230   sgttyNew.sg_flags |= ECHO;
1231   stty(0, &sgttyNew);
1232 }
1233
1234 tst_vt52() {
1235
1236   static struct rtabl {
1237       char *rcode;
1238       char *rmsg;
1239   } resptable[] = {
1240       { "\033/K", " -- OK (means Standard VT52)" },
1241       { "\033/Z", " -- OK (means VT100 emulating VT52)" },
1242       { "",       " -- Unknown response"}
1243   };
1244
1245   int i,j;
1246   char *response;
1247
1248   rm("?2");  /* Reset ANSI (VT100) mode, Set VT52 mode  */
1249   esc("H");  /* Cursor home     */
1250   esc("J");  /* Erase to end of screen  */
1251   esc("H");  /* Cursor home     */
1252   for (i = 0; i <= 23; i++) {
1253     for (j = 0; j <= 9; j++)
1254     printf("%s", "FooBar ");
1255     println("Bletch");
1256   }
1257   esc("H");  /* Cursor home     */
1258   esc("J");  /* Erase to end of screen  */
1259
1260   vt52cup(7,47);
1261   printf("nothing more.");
1262   for (i = 1; i <= 10; i++) printf("THIS SHOULD GO AWAY! ");
1263   for (i = 1; i <= 5; i++) {
1264     vt52cup(1,1);
1265     printf("%s", "Back scroll (this should go away)");
1266     esc("I");           /* Reverse LineFeed (with backscroll!)  */
1267   }
1268   vt52cup(12,60);
1269   esc("J");  /* Erase to end of screen  */
1270   for (i = 2; i <= 6; i++) {
1271     vt52cup(i,1);
1272     esc("K");           /* Erase to end of line */
1273   }
1274
1275   for (i = 2; i <= 23; i++) {
1276     vt52cup(i,70); printf("%s", "**Foobar");
1277   }
1278   vt52cup(23,10);
1279   for (i = 23; i >= 2; i--) {
1280     printf("%s", "*");
1281     printf("%c", 8);    /* BS */
1282     esc("I");           /* Reverse LineFeed (LineStarve)        */
1283   }
1284   vt52cup(1,70);
1285   for (i = 70; i >= 10; i--) {
1286     printf("%s", "*");
1287     esc("D"); esc("D"); /* Cursor Left */
1288   }
1289   vt52cup(24,10);
1290   for (i = 10; i <= 70; i++) {
1291     printf("%s", "*");
1292     printf("%c", 8);    /* BS */
1293     esc("C");           /* Cursor Right */
1294   }
1295   vt52cup(2,11);
1296   for (i = 2; i <= 23; i++) {
1297     printf("%s", "!");
1298     printf("%c", 8);    /* BS */
1299     esc("B");           /* Cursor Down  */
1300   }
1301   vt52cup(23,69);
1302   for (i = 23; i >= 2; i--) {
1303     printf("%s", "!");
1304     printf("%c", 8);    /* BS */
1305     esc("A");           /* Cursor Up    */
1306   }
1307   for (i = 2; i <= 23; i++) {
1308     vt52cup(i,71);
1309     esc("K");           /* Erase to end of line */
1310   }
1311
1312   vt52cup(10,16);
1313   printf("%s", "The screen should be cleared, and have a centered");
1314   vt52cup(11,16);
1315   printf("%s", "rectangle of \"*\"s with \"!\"s on the inside to the");
1316   vt52cup(12,16);
1317   printf("%s", "left and right. Only this, and");
1318   vt52cup(13,16);
1319   holdit();
1320
1321   esc("H");  /* Cursor home     */
1322   esc("J");  /* Erase to end of screen  */
1323   printf("%s", "This is the normal character set:");
1324   for (j =  0; j <=  1; j++) {
1325     vt52cup(3 + j, 16);
1326     for (i = 0; i <= 47; i++)
1327     printf("%c", 32 + i + 48 * j);
1328   }
1329   vt52cup(6,1);
1330   printf("%s", "This is the special graphics character set:");
1331   esc("F");     /* Select Special Graphics character set        */
1332   for (j =  0; j <=  1; j++) {
1333     vt52cup(8 + j, 16);
1334     for (i = 0; i <= 47; i++)
1335     printf("%c", 32 + i + 48 * j);
1336   }
1337   esc("G");     /* Select ASCII character set   */
1338   vt52cup(12,1);
1339   holdit();
1340
1341   esc("H");  /* Cursor home     */
1342   esc("J");  /* Erase to end of screen  */
1343   println("Test of terminal response to IDENTIFY command");
1344   esc("Z");     /* Identify     */
1345   response = instr();
1346   println("");
1347   printf("Response was");
1348   esc("<");  /* Enter ANSI mode (VT100 mode) */
1349   chrprint(response);
1350   for(i = 0; resptable[i].rcode[0] != '\0'; i++)
1351     if (!strcmp(response, resptable[i].rcode))
1352       break;
1353   printf("%s", resptable[i].rmsg);
1354   println("");
1355   println("");
1356   holdit();
1357 }
1358
1359 tst_insdel() {
1360
1361     /* Test of:
1362        SM/RM(4) (= IRM (Insertion/replacement mode))
1363        ICH (Insert Character)
1364        DCH (Delete character)
1365        IL  (Insert line)
1366        DL  (Delete line)
1367     */
1368
1369   int i, row, col, sw, dblchr, scr132;
1370
1371   for(scr132 = 0; scr132 <= 1; scr132++) {
1372     if (scr132) { sm("?3"); sw = 132; }
1373     else        { rm("?3"); sw =  80; }
1374     ed(2);
1375     cup(1,1);
1376     for (row=1; row<=24; row++) {
1377         cup(row,1);
1378         for (col=1; col<=sw; col++)
1379             printf("%c", 'A'-1+row);
1380     }
1381     cup(4,1);
1382     printf("Screen accordion test (Insert & Delete Line). "); holdit();
1383     ri(); el(2);
1384     decstbm( 2,23);
1385     sm("?6");
1386     cup(1,1);
1387     for (row=1; row<=24; row++) {
1388       il(row);
1389       dl(row);
1390     }
1391     rm("?6");
1392     decstbm( 0, 0);
1393     cup(2,1);
1394     printf(
1395     "Top line: A's, bottom line: X's, this line, nothing more. ");
1396     holdit();
1397     cup(2,1); ed(0);
1398     cup(1,2);
1399     printf("B");
1400     cub(1);
1401     sm("4");
1402     for (col=2; col<=sw-1; col++)
1403       printf("*");
1404     rm("4");
1405     cup(4,1);
1406     printf("Test of 'Insert Mode'. The top line should be 'A*** ... ***B'. ");
1407     holdit(); ri(); el(2);
1408     cup(1,2);
1409     dch(sw-2);
1410     cup(4,1);
1411     printf("Test of 'Delete Character'. The top line should be 'AB'. ");
1412     holdit();
1413
1414     for(dblchr = 1; dblchr <= 2; dblchr++) {
1415       ed(2);
1416       for (row=1; row<=24; row++) {
1417         cup(row,1);
1418         if (dblchr == 2) decdwl();
1419         for (col=1; col<=sw/dblchr; col++)
1420           printf("%c", 'A'-1+row);
1421         cup(row,sw/dblchr-row);
1422         dch(row);
1423       }
1424       cup(4,1);
1425       println("The right column should be staggered ");
1426       printf("by one.  ");
1427       holdit();
1428     }
1429     ed(2);
1430     cup(1,1);
1431     println("If your terminal has the ANSI 'Insert Character' function");
1432     println("(the VT102 does not), then you should see a line like this");
1433     println("  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z");
1434     println("below:");
1435     println("");
1436     for (i = 'Z'; i >= 'A'; i--) {
1437       printf("%c\010",i);
1438       ich(2);
1439     }
1440     cup(10,1);
1441     holdit();
1442
1443     if (sw == 132) rm("?3");
1444   }
1445 }
1446
1447 dch(pn) int pn; { brc(pn, 'P'); }  /* Delete character */
1448 ich(pn) int pn; { brc(pn, '@'); }  /* Insert character -- not in VT102 */
1449 dl(pn)  int pn; { brc(pn, 'M'); }  /* Delete line */
1450 il(pn)  int pn; { brc(pn, 'L'); }  /* Insert line */
1451
1452 /*  Test of some known VT100 bugs and misfeatures  */
1453
1454 tst_bugs() {
1455
1456   int i, menuchoice;
1457
1458   static char *menutable[] = {
1459     "Exit to main menu",
1460     "Bug A: Smooth scroll to jump scroll",
1461     "Bug B: Scrolling region",
1462     "Bug C: Wide to narrow screen",
1463     "Bug D: Narrow to wide screen",
1464     "Bug E: Cursor move from double- to single-wide line",
1465     "Bug F: Column mode escape sequence",
1466     "Wrap around with cursor addressing",
1467     "Erase right half of double width lines",
1468     "Funny scroll regions",
1469     /* Add more here */
1470     ""
1471   };
1472
1473   static char *hmsg[] = {
1474   "Test of known bugs in the DEC VT100 series. The numbering of some of",
1475   "the bugs (A-F) refers to the article 'VT100 MAGIC' by Sami Tabih in",
1476   "the 'Proceedings of the DEC Users Society' at St. Louis, Missouri, May",
1477   "1983. To understand some of the tests, you have to look at the source",
1478   "code or the article. Of course, a good VT100-compatible terminal",
1479   "should not have these bugs (or have some means of disabling them)! If",
1480   "a bug appears, you might want to RESET the terminal before continuing",
1481   "the test. There is a test of the RESET function in the main menu.",
1482   "" };
1483
1484   do {
1485     ed(2); cup(1,1);
1486     for (i = 0; *hmsg[i]; i++) println(hmsg[i]);
1487     println("");
1488     println("          Choose bug test number:");
1489     menuchoice = menu(menutable);
1490     switch (menuchoice) {
1491       case  1:  bug_a();  break;
1492       case  2:  bug_b();  break;
1493       case  3:  bug_c();  break;
1494       case  4:  bug_d();  break;
1495       case  5:  bug_e();  break;
1496       case  6:  bug_f();  break;
1497       case  7:  bug_w();  break;
1498       case  8:  bug_l();  break;
1499       case  9:  bug_s();  break;
1500     }
1501   } while (menuchoice);
1502 }
1503
1504 /* Bug A: Smooth scroll to jump scroll */
1505
1506 bug_a() {
1507   int i;
1508
1509   cup (10, 1);
1510   println("This is a test of the VT100 'Scroll while toggle softscroll'");
1511   println("bug.  The cursor may disappear, or move UP the screen, or");
1512   println("multiple copies of some lines may appear.");
1513   holdit();
1514
1515   /*  Invoke the bug  */
1516
1517   esc ("[24H");                         /* Simplified cursor movement   */
1518   rm("?4"); for (i = 1; i <= 20; i++) printf("\n");
1519   sm("?4"); for (i = 1; i <= 10; i++) printf("\n");
1520   rm("?4"); for (i = 1; i <=  5; i++) printf("\n");
1521
1522   /* That should be enough to show the bug. But we'll try another way:  */
1523   sm ("?4");                            /* Set soft scroll              */
1524   nel ();                               /* "NextLine", move down        */
1525   rm ("?4");                            /* Reset soft scroll            */
1526   nel ();                               /* "NextLine", move down        */
1527   for (i = 1; i <= 10; i++) {           /* Show the bug                 */
1528       printf ("Softscroll bug test, line %d.  ", i);
1529       holdit();
1530   }
1531   println("That should have been enough to show the bug, if present.");
1532   holdit();
1533 }
1534
1535 /*  Bug B: Scrolling region  */
1536
1537 bug_b() {
1538   char c;
1539
1540   decaln();
1541   cup( 1,1); el(0);
1542   printf("Line 11 should be double-wide, line 12 should be cleared.");
1543   cup( 2,1); el(0);
1544   printf("Then, the letters A-P should be written at the beginning");
1545   cup( 3,1); el(0);
1546   printf("of lines 12-24, and the empty line and A-E are scrolled away.");
1547   cup( 4,1); el(0);
1548   printf("If the bug is present, some lines are confused, look at K-P.");
1549   cup(11,1); decdwl();
1550   decstbm(12,24);
1551   cup(12,1); el(0); printf("Here we go... "); holdit();
1552   cup(12,1); ri();                                      /* Bug comes here */
1553   for (c = 'A'; c <= 'P'; c++) printf("%c\n",c);        /* Bug shows here */
1554   holdit();
1555   decstbm(0,0);                                         /* No scr. region */
1556 }
1557
1558 /*  Bug C: Wide to narrow screen  */
1559
1560 bug_c() {
1561   sm("?3");                                             /* 132 column mode */
1562   cup(1,81);
1563   rm("?3");                                             /*  80 column mode */
1564   cup(12,5);
1565   printf("Except for this line, the screen should be blank. ");
1566   holdit();
1567 }
1568
1569 /*  Bug D: Narrow to wide screen  */
1570
1571 bug_d() {
1572   int i;
1573   char result;
1574   /* Make the bug appear */
1575   do {
1576     cup(14,1);
1577
1578     /* The original code in the article says
1579      * PRINT ESC$; "[13;1H"; CHR$(10%);
1580      * but I guess a cup(14,1); would do.
1581      * (To output a pure LF might be tricky).
1582      */
1583
1584     sm("?3");                 /* Make the bug visible */
1585     cup(1,9); decdwl();
1586     println("You should see blinking text at the bottom line.");
1587     cup(3,9); decdwl();
1588     println("Enter 0 to exit, 1 to try to invoke the bug again.");
1589     cup(24,9); decdwl(); sgr("1;5;7");
1590     printf("If you can see this then the bug did not appear."); sgr("");
1591     cup(4,9); decdwl();
1592     result = inchar(); readnl();
1593     rm("?3");
1594   } while (result == '1');
1595   sm("?4");     /* Syrup scroll */
1596   cup(23,1);
1597   for (i = 1; i <= 5; i++)
1598   println("If the bug is present, this should make things much worse!");
1599   holdit();
1600   rm("?4");     /* Jump scroll */
1601 }
1602
1603 /*  Bug E: Cursor move from double- to single-wide line  */
1604
1605 bug_e() {
1606   int i;
1607   static char *rend[2] = { "\033[m", "\033[7m" };
1608   sm("?3");
1609   cup(1,1); decdwl();
1610   println("This test should put an 'X' at line 3 column 100.");
1611   for (i = 1; i <= 12; i++) printf("1234567890%s",rend[i & 1]);
1612   cup(1,1);     /* The bug appears when we jump from a dobule-wide line */
1613   cup(3,100);   /* to a single-wide line, column > 66.                  */
1614   printf("X");
1615   cup(4, 66); printf("!                                 !");
1616   cup(5,1);
1617   printf("--------------------------- The 'X' should NOT be above here -");
1618   printf("---+------------ but above here -----+");
1619   cup(10,1); decdwl(); holdit();
1620   rm("?3");
1621 }
1622
1623 /*  Bug F: Column mode escape sequence  */
1624
1625 bug_f() {
1626   int i, row, col;
1627
1628  /*
1629   *  VT100 "toggle origin mode, forget rest" bug.  If you try to set
1630   *     (or clear) parameters and one of them is the "origin mode"
1631   *     ("?6") parameter, parameters that appear after the "?6"
1632   *     remain unaffected.  This is also true on CIT-101 terminals.
1633   */
1634   sm ("?5");                            /* Set reverse mode             */
1635   sm ("?3");                            /* Set 132 column mode          */
1636   println("Test VT100 'Toggle origin mode, forget rest' bug, part 1.");
1637   println("The screen should be in reverse, 132 column mode.");
1638   holdit();
1639   ed (2);
1640   rm ("?6;5;3");                /* Reset (origin, reverse, 132 col)     */
1641   println("Test VT100 'Toggle origin mode, forget rest' bug, part 2.\n");
1642   println("The screen should be in non-reverse, 80 column mode.");
1643   holdit();
1644 }
1645
1646   /*    Bug W:
1647    *    The dreaded "wraparound" bug!  You CUP to col 80, write a char,
1648    *    CUP to another line in col 80, write a char. And the brain-damaged
1649    *    terminal thinks that "Hokay, so he's written a char in col 80, so
1650    *    I stay in col 80 and wait for next character. Let's see now, here
1651    *    comes another character, and I'm still in col 80, so I must make
1652    *    a NewLine first." -- It doesn't clear that "still in col 80" flag
1653    *    on a CUP. Argh!
1654    */
1655
1656 bug_w() {
1657   int row, col;
1658
1659   cup (16,1);
1660   println("   This illustrates the \"wrap around bug\" which exists on a");
1661   println("   standard VT100. At the top of the screen there should be");
1662   println("   a row of +'s, and the rightmost column should be filled");
1663   println("   with *'s. But if the bug is present, some of the *'s may");
1664   println("   be placed in other places, e.g. in the leftmost column,");
1665   println("   and the top line of +'s may be scrolled away.");
1666
1667   cup(1,1);
1668   for (col = 1; col <= 79; col++)
1669       printf ("+");
1670   for (row = 1; row <= 24; row++) {
1671       hvp (row, 80);
1672       printf ("*");
1673   }
1674   cup(24,1);
1675   holdit();
1676 }
1677
1678   /*    Bug L:
1679    *    Check if the right half of double-width lines comes back
1680    *    when a line is first set to single-width, filled with stuff,
1681    *    set to double-width, and finally reset to single-width.
1682    *
1683    *    A VT100 has this misfeature, and many others. Foo!
1684    */
1685
1686 bug_l() {
1687   cup(15, 1);
1688   printf("This-is-a-long-line-This-is-a-long-line-");
1689   printf("This-is-a-long-line-This-is-a-long-line-");
1690   cup(1, 1);
1691   printf("This is a test of what happens to the right half of double-width");
1692   println(" lines.");
1693   printf("A common misfeature is that the right half does not come back");
1694   println(" when a long");
1695   printf("single-width line is set to double-width and then reset to");
1696   println(" single-width.");
1697
1698   cup(5, 1);
1699   println("Now the line below should contain 80 characters in single width.");
1700   holdit();
1701   cup(15, 1); decdwl();
1702   cup(8, 1);
1703   println("Now the line below should contain 40 characters in double width.");
1704   holdit();
1705   cup(15, 1); decswl();
1706   cup(11, 1);
1707   println("Now the line below should contain 80 characters in single width.");
1708   holdit();
1709
1710   /* ...and in 132 column mode  */
1711
1712   sm("?3");
1713   ed(2);
1714   cup(15, 1);
1715   printf("This-is-a-long-line-This-is-a-long-line-");
1716   printf("This-is-a-long-line-This-is-a-long-line-");
1717   printf("This-is-a-long-line-This-is-a-long-line-");
1718   printf("ending-here-");
1719
1720   cup(1, 1);
1721   printf("This is the same test in 132 column mode.");
1722
1723   cup(5, 1);
1724   println("Now the line below should contain 132 characters in single width.");
1725   holdit();
1726   cup(15, 1); decdwl();
1727   cup(8, 1);
1728   println("Now the line below should contain 66 characters in double width.");
1729   holdit();
1730   cup(15, 1); decswl();
1731   cup(11, 1);
1732   println("Now the line below should contain 132 characters in single width.");
1733   holdit();
1734   rm("?3");
1735 }
1736
1737 bug_s() {
1738   int i;
1739   decstbm(20,10);       /* 20-10=-10, < 2, so no scroll region. */
1740   cup(1,1);
1741   for (i=1; i<=20; i++)
1742     printf("This is 20 lines of text (line %d), no scroll region.\n", i);
1743   holdit();
1744   ed(2);
1745   decstbm(0,1);         /* Should be interpreted as decstbm(1,1) = none */
1746   cup(1,1);
1747   for (i=1; i<=20; i++)
1748     printf("This is 20 lines of text (line %d), no scroll region.\n", i);
1749   holdit();
1750   decstbm(0,0);         /* No scroll region (just in case...)   */
1751 }
1752
1753 tst_rst() {
1754
1755   /*
1756    * Test of
1757    *    - RIS    (Reset to Initial State)
1758    *    - DECTST (invoke terminal test)
1759    */
1760
1761   cup(10,1);
1762   printf ("The terminal will now be RESET. ");
1763   holdit();
1764   ris();
1765   fflush(stdout);
1766   zleep(5000);          /* Wait 5.0 seconds */
1767   cup(10,1);
1768   println("The terminal is now RESET. Next, the built-in confidence test");
1769   printf("%s", "will be invoked. ");
1770   holdit();
1771   ed(2);
1772   dectst(1);
1773   fflush(stdout);
1774   zleep(5000);          /* Wait 5.0 seconds */
1775   cup(10,1);
1776   println("If the built-in confidence test found any errors, a code");
1777   printf("%s", "is visible above. ");
1778   holdit();
1779 }
1780
1781 initterminal(pn) int pn; {
1782
1783   if (pn==0) {
1784     fflush(stdout);
1785     gtty(0,&sgttyOrg);
1786     gtty(0,&sgttyNew);
1787     sgttyNew.sg_flags |= CBREAK;
1788     }
1789   else  {
1790     fflush(stdout);
1791     inflush();
1792     sleep(2);
1793     sgttyNew.sg_flags = sgttyOrg.sg_flags | CBREAK;
1794     }
1795   stty(0,&sgttyNew);
1796   /* Set up my personal prejudices      */
1797
1798   esc("<");     /* Enter ANSI mode (if in VT52 mode)    */
1799   rm("?1");     /* cursor keys normal   */
1800   rm("?3");     /* 80 col mode          */
1801   rm("?4");     /* Jump scroll          */
1802   rm("?5");     /* Normal screen        */
1803   rm("?6");     /* Absolute origin mode */
1804   sm("?7");     /* Wrap around on       */
1805   rm("?8");     /* Auto repeat off      */
1806   decstbm(0,0); /* No scroll region     */
1807   sgr("0");     /* Normal character attributes  */
1808
1809 }
1810
1811 bye () {
1812   /* Force my personal prejudices upon the poor luser   */
1813
1814   esc("<");     /* Enter ANSI mode (if in VT52 mode)    */
1815   rm("?1");     /* cursor keys normal   */
1816   rm("?3");     /* 80 col mode          */
1817   rm("?5");     /* Normal screen        */
1818   rm("?6");     /* Absolute origin mode */
1819   sm("?7");     /* Wrap around on       */
1820   sm("?8");     /* Auto repeat on       */
1821   decstbm(0,0); /* No scroll region     */
1822   sgr("0");     /* Normal character attributes  */
1823
1824   /* Say goodbye */
1825
1826   ed(2);
1827   cup(12,30);
1828   printf("That's all, folks!\n");
1829   printf("\n\n\n");
1830   inflush();
1831   stty(0,&sgttyOrg);
1832   exit(0);
1833 }
1834
1835 void
1836 onbrk(int no) {
1837   signal(SIGINT, onbrk);
1838   if (reading)
1839     brkrd = 1;
1840   else
1841     longjmp(intrenv, 1);
1842 }
1843
1844 void
1845 onterm(int no) {
1846   signal(SIGTERM, onterm);
1847   longjmp(intrenv, 1);
1848 }
1849
1850 holdit() {
1851   inflush();
1852   printf("Push <RETURN>");
1853   readnl();
1854 }
1855
1856 readnl() {
1857   char ch;
1858   fflush(stdout);
1859   brkrd = 0;
1860   reading = 1;
1861   do { read(0,&ch,1); } while(ch != '\n' && !brkrd);
1862   if (brkrd)
1863     kill(getpid(), SIGTERM);
1864   reading = 0;
1865 }
1866
1867 scanto(str, pos, toc) char *str; int *pos; char toc; {
1868   char c;
1869   int result = 0;
1870
1871   while (toc != (c = str[(*pos)++])) {
1872     if (isdigit(c)) result = result * 10 + c - '0';
1873     else break;
1874   }
1875   if (c == toc) return(result);
1876   else          return(0);
1877 }
1878
1879 char *lookup(t, k) struct table t[]; int k; {
1880
1881   int i;
1882   for (i = 0; t[i].key != -1; i++) {
1883     if (t[i].key == k) return(t[i].msg);
1884   }
1885   return("BAD VALUE");
1886 }
1887
1888 menu(table) char *table[]; {
1889
1890   int i, tablesize, choice;
1891   char c;
1892   char storage[80];
1893   char *s = storage;
1894   println("");
1895   tablesize = 0;
1896   for (i = 0; *table[i] != '\0'; i++) {
1897     printf("          %d. %s\n", i, table[i]);
1898     tablesize++;
1899   }
1900   tablesize--;
1901
1902   printf("\n          Enter choice number (0 - %d): ", tablesize);
1903   for(;;) {
1904     inputline(s);
1905     choice = 0;
1906     while (c = *s++) choice = 10 * choice + c - '0';
1907     if (choice >= 0 && choice <= tablesize) {
1908       ed(2);
1909       return (choice);
1910     }
1911     printf("          Bad choice, try again: ");
1912   }
1913 }
1914
1915 chrprint (s) char *s; {
1916
1917   int i;
1918
1919   printf("  ");
1920   sgr("7");
1921   printf(" ");
1922   for (i = 0; s[i] != '\0'; i++) {
1923     if (s[i] <= ' ' || s[i] == '\177')
1924     printf("<%d> ", s[i]);
1925     else printf("%c ", s[i]);
1926   }
1927   sgr("");
1928 }