/* chkesc.c -- Check VT terminal's response to report requests. Compile with: No CFLAGS for BSD, SUNOS, etc; -DSYSV to use on AT&T System V; -DNOTTYMOD for system-independent version. Assumes VT102 or higher, 7-bit mode (CSI = "ESC [", ST = "ESC \"). To use, just run it while connected via a VT-102 or higher terminal or emulator. If you're running the system-independent version, you'll have to do something like this: stty raw ; chkesc ; stty -raw The report is generated to stdout. Author: F. da Cruz, Columbia University, Oct 1991. Note: Not yet tested on System V. */ #ifndef NOTTYMOD #ifndef SYSV #define BSD #endif /* SYSV */ #endif /* NOTTYMOD */ #include /* Includes */ #include #include #define SP 040 /* Symbols & macros */ #define DEL 0177 #define ESC 033 #define ctl(ch) (((ch) ^ 64 ) & 0xFF ) #ifdef BSD /* Sys-dependent terminal control */ #include struct sgttyb ttold, ttraw; #endif /* BSD */ #ifdef SYSV /* Sys-dependent terminal control */ #include struct termio ttold, ttraw; #endif /* SYSV */ int fd; /* tty file descriptor */ struct escseq { /* Escape sequence structure */ char * seq; /* Report request escape sequence */ char * fc; /* Final chars of report */ char * txt; /* Descriptive text */ }; /* Escape sequence table */ struct escseq esctab[] = { "\033[c", "c", "DA primary device attributes request", "\033[>c", "c", "DA secondary device attributes request", "\033[5n", "n", "DSR device operating status request", "\033[6n", "R", "DSR device operating status request, cursor position", "\033[?6n", "R", "DECDSR device status request, cursor position", "\033[?15n", "n", "DECDSR printer status request", "\033[?25n", "n", "DECDSR device status request, UDKs", "\033[?26n", "n", "DECDSR device status request, keyboard dialect", "\033[2$p", "y", "KAM ANSI keyboard action", "\033[3$p", "y", "CRM ANSI control representation", "\033[4$p", "y", "IRM ANSI insert/replace mode", "\033[10$p", "y", "HEM ANSI horizontal editing", "\033[12$p", "y", "SRM ANSI send/receive", "\033[20$p", "y", "LNM ANSI newline mode", "\033[?1$p", "y", "DECRQM DEC cursor key mode", "\033[?2$p", "y", "DECRQM DEC mode", "\033[?3$p", "y", "DECRQM DEC 132 column mode", "\033[?4$p", "y", "DECRQM DEC smooth scroll", "\033[?5$p", "y", "DECRQM DEC reverse video", "\033[?6$p", "y", "DECRQM DEC origin mode", "\033[?7$p", "y", "DECRQM DEC autowrap mode", "\033[?8$p", "y", "DECRQM DEC autorepeat keyboard mode", "\033[?18$p","y", "DECRQM DEC print with formfeed mode", "\033[?19$p","y", "DECRQM DEC print extend", "\033[?25$p","y", "DECRQM DEC text cursor enabled", "\033[?42$p","y", "DECRQM DEC NRC set", "\033[?66$p","y", "DECRQM DEC numeric keypad mode", "\033[?67$p","y", "DECRQM DEC backarrow sends BS", "\033[?68$p","y", "DECRQM DEC keyboard usage", "\033[2;2$u","\033\\", "DECRQTSR DEC VT340 palette request", "\033[1$u", "\033\\", "DECRQTSR DEC terminal state request", "\033[&u", "\033\\", "DECRQUPSS DEC UPSS request", "\033[1$w ", "\033\\", "DECRQPSR DEC presentation state request", "\033[2$w ", "\033\\", "DECRQPSR DEC tab stop request" }; nesc = (sizeof(esctab) / sizeof(struct escseq)); /* Number of entries */ jmp_buf jbuf; /* Timeout long jump buffer */ timeout = 0; /* Timeout flag */ timerh() { /* Timeout handler */ timeout = 1; alarm(0); signal(SIGALRM,SIG_DFL); longjmp(jbuf,1); } char * /* Print a character as "text" */ dbchr(c) char c; { static char s[8]; char *cp = s; c &= 0xff; if (c & 0x80) { /* 8th bit on */ sprintf(cp++,"~"); c &= 0x7f; } if (c < SP) { /* Control character */ if (c == ESC) sprintf(cp,"ESC"); else sprintf(cp,"^%c",ctl(c)); } else if (c == DEL) { sprintf(cp,"^?"); } else { /* Printing character */ sprintf(cp,"%c",c); } cp = s; /* Return pointer to it */ return(cp); } echo(tt) char *tt; { /* Read and echo an escape sequence */ char c; /* terminated by string tt. */ int j; signal(SIGALRM,timerh); /* Set timer */ alarm(2); j = 0; /* Pattern match index */ if (setjmp(jbuf)) { /* Timer went off */ timeout = 1; } else { timeout = 0; /* It didn't go off */ while (1) { if (read(fd,&c,1) < 0) { /* Read report */ perror("read error"); break; } c &= 0x7f; /* 7 bits only */ printf("%s ",dbchr(c)); /* Echo it */ if (c == tt[j]) { /* Try to match terminator */ j++; if (tt[j] == '\0') break; } else { j = 0; } } } alarm(0); /* Turn off timer */ signal(SIGALRM,SIG_DFL); } /* Output a report-request escape sequence */ outesc(s,tt,d) char *s; char *tt; char *d; { char *p, c; p = s; printf("\r\n%s:\r\n",d); /* Print descriptive text */ while (*p) { /* Print text-mode esc seq */ printf("%s ",dbchr(*p++)); } printf(" (sent)\r\n"); while (c = *s++) /* Send real escape sequence */ write(fd,&c,1); echo(tt); /* Read back the echo */ if (timeout) /* Print status of echo */ printf(" (timed out)\r\n"); else printf(" (received)\r\n"); } main() { /* Main program */ int i, j; unsigned char c; if ((fd = open("/dev/tty",2)) < 0) { /* Open the tty */ perror("can't open tty"); exit(1); } /* Put tty in raw mode */ #ifdef BSD if (gtty(fd,&ttold) < 0) { perror("can't get modes"); exit(1); } if (gtty(fd,&ttraw) < 0) { perror("can't get modes"); exit(1); } ttraw.sg_flags |= RAW; ttraw.sg_flags &= ~(ECHO|CRMOD); if (stty(fd,&ttraw) < 0) { perror("can't set modes"); exit(1); } #endif /* BSD */ #ifdef SYSV if (ioctl(fd,TCGETA,&ttold) < 0) { perror("Sys V get old modes ioctl"); exit(1); } if (ioctl(fd,TCGETA,&ttraw) < 0) { perror("Sys V get raw modes ioctl"); exit(1); } ttraw.c_lflag &= ~(ISIG|ICANON|ECHO); ttraw.c_iflag |= (BRKINT|IGNPAR); ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF |INPCK|ISTRIP); ttraw.c_oflag &= ~OPOST; ttraw.c_cc[0] = 003; ttraw.c_cc[4] = 1; if (ioctl(0,TCSETAW,&ttraw) < 0) { perror("Sys V ioctl"); exit(1); } printf("Sys V modes OK\r\n"); #endif /* SYSV */ /* Loop for all reports */ for (j = 0; j < nesc; j++) outesc(esctab[j].seq, esctab[j].fc, esctab[j].txt); /* Restore tty */ #ifdef BSD if (stty(fd,&ttold) < 0) { perror("can't reset modes"); exit(1); } #endif /* BSD */ #ifdef SYSV if (ioctl(fd,TCSETAW,&ccold) < 0) { perror("can't reset modes"); exit(1); } #endif /* SYSV */ close(fd); /* Close the tty device. */ exit(0); /* Done. */ }