1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1992-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * * 20 ***********************************************************************/ 21 #pragma prototyped 22 /* 23 * stty.c 24 * Written by David Korn 25 * Tue Apr 4 10:46:00 EDT 1995 26 */ 27 28 static const char usage[] = 29 "[-?@(#)$Id: stty (AT&T Research) 2006-10-31 $\n]" 30 USAGE_LICENSE 31 "[+NAME?stty - set or get terminal modes]" 32 "[+DESCRIPTION?\bstty\b sets certain terminal I/O modes for the device " 33 "that is the current standard input; without arguments, it writes " 34 "the settings of certain modes to standard output.]" 35 36 "[a:all?Writes to standard output all of the mode settings.]" 37 "[g:save?Writes the current settings to standard output in a form that can " 38 "be used as an argument to another \bstty\b command. The \brows\b " 39 "and \bcolumns\b values are not included.]" 40 "\n" 41 "\n[mode ...]\n" 42 "\n" 43 "[+EXTENDED DESCRIPTION?Modes are specified either as a single name or " 44 "as a name followed by a value. As indicated below, many of the " 45 "mode names can be preceded by a \b-\b to negate its meaning. " 46 "Modes are listed by group corresponding to field in the " 47 "\btermios\b structure defined in \b<termios.h>\b. Modes " 48 "in the last group are implemented using options in the previous " 49 "groups. Note that many combinations of modes make no sense, but " 50 "no sanity checking is performed. The modes are selected from the " 51 "following:]{\fabc\f}" 52 53 "[+EXIT STATUS?]{" 54 "[+0?All modes reported or set successfully.]" 55 "[+>0?Standard input not a terminaol or one or more modes failed.]" 56 "}" 57 "[+SEE ALSO?\btegetattr\b(2), \btcsetattr\b(2), \bioctl\b(2)]" 58 ; 59 60 61 #include <cmd.h> 62 #include <ccode.h> 63 #include <ctype.h> 64 #include <ast_tty.h> 65 #if _sys_ioctl 66 #include <sys/ioctl.h> 67 #endif 68 69 #define C(x) ERROR_catalog(x) 70 71 #ifndef _POSIX_VDISABLE 72 # define _POSIX_VDISABLE 0 73 #endif 74 75 #ifndef NCCS 76 # ifdef NCC 77 # define NCCS NCC 78 # else 79 # define NCCS elementsof(((struct termio*)0)->c_cc) 80 # endif 81 #endif 82 83 /* command options */ 84 #define A_FLAG 1 85 #define G_FLAG 2 86 87 /* termios fields */ 88 #define C_FLAG 1 89 #define C_LINE 2 90 #define C_SPEED 3 91 #define I_FLAG 4 92 #define O_FLAG 5 93 #define L_FLAG 6 94 #define T_CHAR 7 95 #define W_SIZE 8 96 97 #define BIT 1 98 #define BITS 2 99 #define NUM 3 100 #define CHAR 4 101 #define SPEED 5 102 #define SIZE 6 103 #define MIXED 7 104 #define SANE 8 105 #define COOKED 9 106 #define CASE 10 107 #define TABS 11 108 #define WIND 12 109 110 #undef SS /* who co-opted this namespace? */ 111 112 #define IG 0x0001 /* ignore display */ 113 #define NL 0x0002 /* entry ends line of display */ 114 #define SS 0x0004 /* set in sane mode */ 115 #define US 0x0010 /* unset in sane mode */ 116 117 typedef struct tty_s 118 { 119 const char name[8]; 120 unsigned char type; 121 unsigned char field; 122 short flags; 123 unsigned long mask; 124 unsigned long val; 125 const char description[76]; 126 } Tty_t; 127 128 static const Tty_t Ttable[] = 129 { 130 #ifdef CBAUD 131 { "ispeed", NUM, C_SPEED,0, CBAUD, 0, C("\an\a is the input baud rate") }, 132 { "ospeed", NUM, C_SPEED,0, CBAUD, 0, C("\an\a is the output baud rate") }, 133 { "speed", NUM, C_SPEED,IG, CBAUD }, 134 #endif 135 { "0", SPEED, C_FLAG, 0, B0 }, 136 { "50", SPEED, C_FLAG, 0, B50 }, 137 { "75", SPEED, C_FLAG, 0, B75 }, 138 { "110", SPEED, C_FLAG, 0, B110 }, 139 { "134", SPEED, C_FLAG, 0, B134 }, 140 { "150", SPEED, C_FLAG, 0, B150 }, 141 { "200", SPEED, C_FLAG, 0, B200 }, 142 { "300", SPEED, C_FLAG, 0, B300 }, 143 { "600", SPEED, C_FLAG, 0, B600 }, 144 { "1200", SPEED, C_FLAG, 0, B1200 }, 145 { "1800", SPEED, C_FLAG, 0, B1800 }, 146 { "2400", SPEED, C_FLAG, 0, B2400 }, 147 { "4800", SPEED, C_FLAG, 0, B4800 }, 148 { "9600", SPEED, C_FLAG, 0, B9600 }, 149 { "19200", SPEED, C_FLAG, 0, B19200 }, 150 { "38400", SPEED, C_FLAG, 0, B38400 }, 151 152 #ifdef TIOCSWINSZ 153 { "rows", WIND, W_SIZE, IG, 0, 24, C("\an\a is the number of lines for display") }, 154 { "cols", WIND, W_SIZE, IG, 1, 80, C("\an\a is the number of columns for display") }, 155 { "columns", WIND, W_SIZE, IG, 1, 80, C("Same as \bcols\b") }, 156 #endif 157 { "intr", CHAR, T_CHAR, SS, VINTR, 'C', C("Send an interrupt signal") }, 158 { "quit", CHAR, T_CHAR, SS, VQUIT, '|', C("Send a quit signal") }, 159 { "erase", CHAR, T_CHAR, SS, VERASE, 'H', C("Erase the last character entered") }, 160 { "kill", CHAR, T_CHAR, NL|SS, VKILL, 'U', C("Erase the current line") }, 161 { "eof", CHAR, T_CHAR, SS, VEOF, 'D', C("Send an end of file") }, 162 #ifdef VEOL2 163 { "eol2", CHAR, T_CHAR, US, VEOL2, _POSIX_VDISABLE, C("Alternate character to end the line") }, 164 #endif /* VEOL2 */ 165 #ifdef VSWTCH 166 { "swtch", CHAR, T_CHAR, US, VSWTCH, _POSIX_VDISABLE, C("Switch to a different shell layer") }, 167 #endif /* VSWTCH */ 168 { "eol", CHAR, T_CHAR, NL|US, VEOL, _POSIX_VDISABLE, C("End the line") }, 169 #ifdef VSTART 170 { "start", CHAR, T_CHAR, SS, VSTART, 'Q', C("Restart the output after stopping it") }, 171 #endif /* VSTART */ 172 #ifdef VSTOP 173 { "stop", CHAR, T_CHAR, SS, VSTOP, 'S', C("Stop the output") }, 174 #endif /* VSTOP */ 175 #ifdef VDSUSP 176 { "dsusp", CHAR, T_CHAR, SS, VDSUSP, 'Y', C("Send a terminal stop signal after flushing the input") }, 177 #endif /* VDSUSP */ 178 #ifdef VSUSP 179 { "susp", CHAR, T_CHAR, NL|SS, VSUSP, 'Z', C("Send a terminal stop signal") }, 180 #endif /* VSUSP */ 181 #ifdef VREPRINT 182 { "rprnt", CHAR, T_CHAR, SS, VREPRINT, 'R', C("Redraw the current line") }, 183 #endif /* VREPRINT */ 184 #ifdef VDISCARD 185 { "flush", CHAR, T_CHAR, SS, VDISCARD, 'O', C("Discard output") }, 186 #endif /* VDISCARD */ 187 #ifdef VWERASE 188 { "werase", CHAR, T_CHAR, SS, VWERASE, 'W', C("Erase the last word entered") }, 189 #endif /* VWERASE */ 190 #ifdef VLNEXT 191 { "lnext", CHAR, T_CHAR, NL|SS, VLNEXT, 'V', C("Enter the next input character literally") }, 192 #endif /* VLNEXT */ 193 194 #if _mem_c_line_termios 195 { "line", NUM, C_LINE, 0, 0, 0, C("Line discipline number") }, 196 #endif 197 { "min", NUM, T_CHAR, 0, VMIN, 0, C("Mininmum number of characters to read in raw mode") }, 198 { "time", NUM, T_CHAR, 0, VTIME, 0, C("Number of .1 second intervals with raw mode") }, 199 200 { "parenb", BIT, C_FLAG, 0, PARENB, PARENB, C("Enable (disable) parity generation and detection") }, 201 { "parodd", BIT, C_FLAG, 0, PARODD, PARODD, C("Use odd (even) parity") }, 202 #ifdef PAREXT 203 { "parext", BIT, C_FLAG, 0, PAREXT, PAREXT }, 204 #endif /* PAREXT */ 205 #ifdef CREAD 206 { "cread", BIT, C_FLAG, SS, CREAD, CREAD, C("Enable (disable) input") }, 207 #endif /* CREAD */ 208 { "cs5", SIZE, C_FLAG, 0, CSIZE, CS5 , C("Char size 5") }, 209 { "cs6", SIZE, C_FLAG, 0, CSIZE, CS6 , C("Char size 6") }, 210 { "cs7", SIZE, C_FLAG, 0, CSIZE, CS7 , C("Char size 7") }, 211 { "cs8", SIZE, C_FLAG, 0, CSIZE, CS8 , C("Char size 8") }, 212 { "hupcl", BIT, C_FLAG, 0, HUPCL, HUPCL, C("Hangup (do not hangup) connection on last close") }, 213 { "hup", BIT, C_FLAG, IG, HUPCL, HUPCL, C("Same as \bhupcl\b") }, 214 { "cstopb", BIT, C_FLAG, 0, CSTOPB, CSTOPB, C("Use two (one) stop bits") }, 215 #ifdef CRTSCTS 216 { "crtscts", BIT, C_FLAG, 0, CRTSCTS, CRTSCTS, C("Enable (disable) RTS/CTS handshaking") }, 217 #endif /* CRTSCTS */ 218 { "clocal", BIT, C_FLAG, NL, CLOCAL, CLOCAL, C("Disable (enable) modem control signals") }, 219 220 { "ignbrk", BIT, I_FLAG, US, IGNBRK, IGNBRK, C("Ignore (do not ignore) break characters") }, 221 { "brkint", BIT, I_FLAG, SS, BRKINT, BRKINT, C("Generate (do not generate) INTR signal on break") }, 222 { "ignpar", BIT, I_FLAG, 0, IGNPAR, IGNPAR, C("Ignore (do not ignore) characters with parity errors") }, 223 { "parmrk", BIT, I_FLAG, 0, PARMRK, PARMRK, C("Mark (do not mark) parity errors") }, 224 { "inpck", BIT, I_FLAG, 0, INPCK, INPCK, C("Enable (disable) input parity checking") }, 225 { "istrip", BIT, I_FLAG, 0, ISTRIP, ISTRIP, C("Clear (do not clear) high bit of input characters") }, 226 { "inlcr", BIT, I_FLAG, US, INLCR, INLCR, C("Translate (do not translate) carriage return to newline") }, 227 { "igncr", BIT, I_FLAG, US, IGNCR, IGNCR, C("Ignore (do not ignore) carriage return") }, 228 #ifdef IUCLC 229 { "iuclc", BIT, I_FLAG, US, IUCLC, IUCLC, C("Map (do not map) upper-case to lower case") }, 230 #endif /* IUCLC */ 231 { "ixon", BIT, I_FLAG, 0, IXON, IXON, C("Enable (disable) XON/XOFF flow control. \bstop\b character stops output") }, 232 #ifdef IXANY 233 { "ixany", BIT, I_FLAG, US, IXANY, IXANY, C("Any character (only start character) can restart output.") }, 234 { "decctlq", BIT, I_FLAG, IG, IXANY, 0, C("Same as \b-ixany\b") }, 235 #endif /* IXANY */ 236 { "ixoff", BIT, I_FLAG, US, IXOFF, IXOFF, C("Disable (enable) XON/XOFF flow control") }, 237 #ifdef IMAXBEL 238 { "imaxbel", BIT, I_FLAG, SS, IMAXBEL, IMAXBEL, C("Beep (do not beep) if a character arrives with full input buffer") }, 239 #endif /* IMAXBEL */ 240 { "icrnl", BIT, I_FLAG, NL|SS, ICRNL, ICRNL, C("Translate (do not translate) carriage return to newline") }, 241 242 { "isig", BIT, L_FLAG, SS, ISIG, ISIG, C("Enable (disable) \bintr\b, \bquit\b, and \bsusp\b special characters") }, 243 { "icanon", BIT, L_FLAG, SS, ICANON, ICANON, C("Enable (disable) \berase\b, \bkill\b, \bwerase\b, and \brprnt\b special characters") }, 244 { "icannon", BIT, L_FLAG, SS, ICANON, ICANON }, 245 #ifdef IEXTEN 246 { "iexten", BIT, L_FLAG, SS, IEXTEN, IEXTEN, C("Enable (disable) non-POSIX special characters") }, 247 #endif /* IEXTEN */ 248 { "echo", BIT, L_FLAG, SS, ECHO|ECHONL, ECHO|ECHONL, C("Echo (do not echo) input characters") }, 249 { "echoe", BIT, L_FLAG, SS, ECHOE, ECHOE, C("Echo (do not echo) erase characters as backspace-space-backspace") }, 250 { "echok", BIT, L_FLAG, SS, ECHOK, ECHOK, C("Echo (do not echo) a newline after a kill character") }, 251 #ifdef ECHOKE 252 { "echoke", BIT, L_FLAG, SS, ECHOKE, ECHOKE, C("Echo (do not echo) a newline after a kill character") }, 253 #endif 254 { "lfkc", BIT, L_FLAG, IG, ECHOK, ECHOK, C("Same as \bechok\b (\b-echok\b); obsolete") }, 255 { "echonl", BIT, L_FLAG, SS, ECHONL, ECHONL,"Echo (do not echo) newline even if not echoing other character" }, 256 #ifdef ECHOCTL 257 { "echoctl", BIT, L_FLAG, SS, ECHOCTL, ECHOCTL, C("Echo (do not echo) control characters as \b^\b\ac\a") }, 258 #else 259 #define ECHOCTL 0 260 #endif /* ECHOCTL */ 261 #ifdef ECHOPRT 262 { "echoprt", BIT, L_FLAG, US, ECHOPRT, ECHOPRT, C("Echo (do not echo) erased characters backward, between '\\' and '/'") }, 263 #else 264 #define ECHOPRT 0 265 #endif /* ECHOPRT */ 266 #ifdef XCASE 267 { "xcase", BIT, L_FLAG, US, XCASE, XCASE, C("Enable (disable) \bicanon\b uppercase as lowercase with '\\' prefix") }, 268 #endif /* XCASE */ 269 #ifdef DEFECHO 270 { "defecho", BIT, L_FLAG, 0, DEFECHO, DEFECHO }, 271 #endif /* DEFECHO */ 272 #ifdef FLUSHO 273 { "flusho", BIT, L_FLAG, 0, FLUSHO, FLUSHO, C("Discard (do not discard) written data. Cleared by subsequent input") }, 274 #endif /* FLUSHO */ 275 #ifdef PENDIN 276 { "pendin", BIT, L_FLAG, 0, PENDIN, PENDIN, C("Redisplay pending input at next read and then automatically clear \bpendin\b") }, 277 #endif /* PENDIN */ 278 { "noflsh", BIT, L_FLAG, US, NOFLSH, NOFLSH, C("Disable (enable) flushing after \bintr\b and \bquit\b special characters") }, 279 #ifdef TOSTOP 280 { "tostop", BIT, L_FLAG, NL|US, TOSTOP, TOSTOP, C("Stop (do not stop) background jobs that try to write to the terminal") }, 281 #endif /* TOSTOP */ 282 #ifdef OLCUC 283 { "olcuc", BIT, O_FLAG, US, OLCUC, OLCUC, C("Translate (do not translate) lowercase characters to uppercase") }, 284 #endif /* OLCUC */ 285 #ifdef ONLCR 286 { "onlcr", BIT, O_FLAG, SS, ONLCR, ONLCR, C("Translate (do not translate) newline to carriage return-newline") }, 287 #endif /* ONLCR */ 288 #ifdef ONLRET 289 { "onlret", BIT, O_FLAG, US, ONLRET, ONLRET, C("Newline performs (does not perform) a carriage return") }, 290 #endif /* ONLRET */ 291 #ifdef OCRNL 292 { "ocrnl", BIT, O_FLAG, US, OCRNL, OCRNL, C("Translate (do not translate) carriage return to newline") }, 293 #endif /* OCRNL */ 294 #ifdef ONOCR 295 { "onocr", BIT, O_FLAG, US, ONOCR, ONOCR, C("Do not (do) print carriage returns in the first column") }, 296 #endif /* ONOCR */ 297 #ifdef OFILL 298 { "ofill", BIT, O_FLAG, US, OFILL, OFILL, C("Use fill characters (use timing) for delays") }, 299 #endif /* OFILL */ 300 #ifdef OFDEL 301 { "ofdel", BIT, O_FLAG, US, OFDEL, OFDEL, C("Use DEL (NUL) as fill characters for delays") }, 302 #endif /* OFDEL */ 303 { "opost", BIT, O_FLAG, SS, OPOST, OPOST, C(" Postprocess (do not postprocess) output") }, 304 #ifdef CRDLY 305 { "cr0", BITS, O_FLAG, IG|SS, CRDLY, CR0 }, 306 { "cr1", BITS, O_FLAG, US, CRDLY, CR1 }, 307 { "cr2", BITS, O_FLAG, US, CRDLY, CR2 }, 308 { "cr3", BITS, O_FLAG, US, CRDLY, CR3 }, 309 #endif 310 #ifdef NLDLY 311 { "nl0", BITS, O_FLAG, IG|US, NLDLY, NL0 }, 312 { "nl1", BITS, O_FLAG, US, NLDLY, NL1 }, 313 #endif 314 #ifdef TABDLY 315 { "tabs", TABS, O_FLAG, IG, TABDLY, TAB3, C("Preserve (expand to spaces) tabs") }, 316 { "tab0", BITS, O_FLAG, IG|SS, TABDLY, TAB0 }, 317 { "tab1", BITS, O_FLAG, US, TABDLY, TAB1 }, 318 { "tab2", BITS, O_FLAG, US, TABDLY, TAB2 }, 319 { "tab3", BITS, O_FLAG, US, TABDLY, TAB3 }, 320 #endif 321 #ifdef BSDLY 322 { "bs0", BITS, O_FLAG, IG|SS, BSDLY, BS0 }, 323 { "bs1", BITS, O_FLAG, US, BSDLY, BS1 }, 324 #endif 325 #ifdef VTDLY 326 { "vt0", BITS, O_FLAG, IG|SS, VTDLY, VT0 }, 327 { "vt1", BITS, O_FLAG, US, VTDLY, VT1 }, 328 #endif 329 #ifdef FFDLY 330 { "ff0", BITS, O_FLAG, IG|SS, FFDLY, FF0 }, 331 { "ff1", BITS, O_FLAG, US, FFDLY, FF1 }, 332 #endif 333 { "", MIXED, O_FLAG, NL|IG }, 334 335 { "evenp", MIXED, C_FLAG, IG, PARENB, 0, C("Same as \bparenb -parodd cs7\b") }, 336 { "oddp", MIXED, C_FLAG, IG, PARODD, 0, C("Same as \bparenb parodd cs7\b") }, 337 { "parity", MIXED, C_FLAG, IG, 0, 0, C("Same as parenb \b-parodd cs7\b") }, 338 { "ek", MIXED, C_FLAG, IG, 0, 0, C("Reset the \berase\b and \bkill\b special characters to their default values") }, 339 { "sane", SANE, C_FLAG, IG, 0, 0, C("Reset all modes to some reasonable values") }, 340 { "cooked", COOKED, C_FLAG, IG, 0, 0, C("Disable raw input and output") }, 341 { "raw", COOKED, C_FLAG, IG, 0, 0, C("Enable raw input and output") }, 342 { "lcase", CASE, C_FLAG, IG, 0 , 0, C("Set \bxcase\b, \biuclc\b, and \bolcuc\b") }, 343 { "LCASE", CASE, C_FLAG, IG, 0 , 0, C("Same as \blcase\b") } 344 }; 345 346 #if CC_NATIVE == CC_ASCII 347 #define cntl(x) (((x)=='?')?0177:((x)&037)) 348 #else 349 #define cntl(x) (((x)=='?')?ccmapc(0177,CC_ASCII,CC_NATIVE):ccmapc(ccmapc(x,CC_NATIVE,CC_ASCII)&037,CC_ASCII,CC_NATIVE)) 350 #endif 351 352 static void sane(register struct termios *sp) 353 { 354 register const Tty_t* tp; 355 356 for (tp = Ttable; tp < &Ttable[elementsof(Ttable)]; tp++) 357 if (tp->flags & (SS|US)) 358 switch (tp->type) 359 { 360 case BIT: 361 case BITS: 362 switch (tp->field) 363 { 364 case C_FLAG: 365 if (tp->flags & SS) 366 sp->c_cflag |= tp->mask; 367 else 368 sp->c_cflag &= ~tp->mask; 369 break; 370 case I_FLAG: 371 if (tp->flags & SS) 372 sp->c_iflag |= tp->mask; 373 else 374 sp->c_iflag &= ~tp->mask; 375 break; 376 case O_FLAG: 377 if (tp->flags & SS) 378 sp->c_oflag |= tp->mask; 379 else 380 sp->c_oflag &= ~tp->mask; 381 break; 382 case L_FLAG: 383 if (tp->flags & SS) 384 sp->c_lflag |= tp->mask; 385 else 386 sp->c_lflag &= ~tp->mask; 387 break; 388 } 389 break; 390 case CHAR: 391 sp->c_cc[tp->mask] = cntl(tp->val); 392 break; 393 } 394 } 395 396 static int gin(char *arg,struct termios *sp) 397 { 398 register int i; 399 if(*arg++ != ':') 400 return(0); 401 sp->c_iflag = strtol(arg,&arg,16); 402 if(*arg++ != ':') 403 return(0); 404 sp->c_oflag = strtol(arg,&arg,16); 405 if(*arg++ != ':') 406 return(0); 407 sp->c_cflag = strtol(arg,&arg,16); 408 if(*arg++ != ':') 409 return(0); 410 sp->c_lflag = strtol(arg,&arg,16); 411 if(*arg++ != ':') 412 return(0); 413 for(i=0;i< NCCS; i++) 414 { 415 sp->c_cc[i] = strtol(arg,&arg,16); 416 if(*arg++ != ':') 417 return(0); 418 } 419 #if _mem_c_line_termios 420 sp->c_line = 421 #endif 422 strtol(arg,&arg,16); 423 if(*arg++ != ':') 424 return(0); 425 i = strtol(arg,&arg,16); 426 if(*arg++ != ':') 427 return(0); 428 cfsetispeed(sp, i); 429 i = strtol(arg,&arg,16); 430 if(*arg++ != ':') 431 return(0); 432 cfsetospeed(sp, i); 433 if(*arg) 434 return(0); 435 return(1); 436 } 437 438 static void gout(struct termios *sp) 439 { 440 register int i; 441 sfprintf(sfstdout,":%x",sp->c_iflag); 442 sfprintf(sfstdout,":%x",sp->c_oflag); 443 sfprintf(sfstdout,":%x",sp->c_cflag); 444 sfprintf(sfstdout,":%x",sp->c_lflag); 445 for(i=0;i< NCCS; i++) 446 sfprintf(sfstdout,":%x",sp->c_cc[i]); 447 #if _mem_c_line_termios 448 sfprintf(sfstdout,":%x", sp->c_line); 449 #else 450 sfprintf(sfstdout,":%x", 0); 451 #endif 452 sfprintf(sfstdout,":%x",cfgetispeed(sp)); 453 sfprintf(sfstdout,":%x",cfgetospeed(sp)); 454 sfprintf(sfstdout,":\n"); 455 } 456 457 static void output(struct termios *sp, int flags) 458 { 459 const Tty_t *tp; 460 struct termios tty; 461 register int delim = ' '; 462 register int i,off,off2; 463 char schar[2]; 464 unsigned int ispeed = cfgetispeed(sp); 465 unsigned int ospeed = cfgetospeed(sp); 466 if(flags&G_FLAG) 467 { 468 gout(sp); 469 return; 470 } 471 tty = *sp; 472 sane(&tty); 473 for(i=0; i < elementsof(Ttable); i++) 474 { 475 tp= &Ttable[i]; 476 if(tp->flags&IG) 477 { 478 if(tp->flags&NL) 479 sfputc(sfstdout,'\n'); 480 continue; 481 } 482 switch(tp->type) 483 { 484 case BIT: 485 case BITS: 486 off = 1; 487 switch(tp->field) 488 { 489 case C_FLAG: 490 if(sp->c_cflag&tp->mask) 491 off = 0; 492 if(tty.c_cflag&tp->mask) 493 off2 = 0; 494 break; 495 case I_FLAG: 496 if(sp->c_iflag&tp->mask) 497 off = 0; 498 if(tty.c_iflag&tp->mask) 499 off2 = 0; 500 break; 501 case O_FLAG: 502 if((sp->c_oflag&tp->mask)==tp->val) 503 off = 0; 504 if(tty.c_oflag&tp->mask) 505 off2 = 0; 506 break; 507 case L_FLAG: 508 if(sp->c_lflag&tp->mask) 509 off = 0; 510 if(tty.c_lflag&tp->mask) 511 off2 = 0; 512 } 513 if(tp->flags&NL) 514 delim = '\n'; 515 if(!flags && off==off2) 516 continue; 517 if(!off) 518 sfprintf(sfstdout,"%s%c",tp->name,delim); 519 else if(tp->type==BIT) 520 sfprintf(sfstdout,"-%s%c",tp->name,delim); 521 delim = ' '; 522 break; 523 524 case CHAR: 525 off = sp->c_cc[tp->mask]; 526 if(tp->flags&NL) 527 delim = '\n'; 528 if(!flags && off==(unsigned char)tty.c_cc[tp->mask]) 529 continue; 530 if(off==_POSIX_VDISABLE) 531 sfprintf(sfstdout,"%s = <undef>;%c",tp->name,delim); 532 else if(isprint(off&0xff)) 533 sfprintf(sfstdout,"%s = %c;%c",tp->name,off,delim); 534 else 535 #if CC_NATIVE == CC_ASCII 536 sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':(off^0100),delim); 537 #else 538 { 539 off = ccmapc(off, CC_NATIVE, CC_ASCII); 540 sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':ccmapc(off^0100,CC_ASCII,CC_NATIVE),delim); 541 } 542 #endif 543 delim = ' '; 544 break; 545 case SIZE: 546 if((sp->c_cflag&CSIZE)!=tp->mask) 547 continue; 548 if(flags || (sp->c_cflag&CSIZE) != (tty.c_cflag&CSIZE)) 549 sfprintf(sfstdout,"%s ",tp->name); 550 break; 551 case SPEED: 552 if(tp->mask==ispeed) 553 { 554 if(ispeed!=ospeed) 555 schar[0]='i'; 556 else 557 schar[0]=0; 558 } 559 else if(tp->mask==ospeed) 560 schar[0]='o'; 561 else 562 continue; 563 schar[1] = 0; 564 #ifdef TIOCSWINSZ 565 { 566 struct winsize win; 567 off = ioctl(0,TIOCGWINSZ,&win); 568 if(off>=0) 569 sfprintf(sfstdout,"%sspeed %s baud; rows %d; columns %d;\n",schar,tp->name,win.ws_row,win.ws_col); 570 } 571 if(off<0) 572 #endif 573 sfprintf(sfstdout,"%sspeed %s baud;\n",schar,tp->name); 574 } 575 } 576 if(delim=='\n') 577 sfputc(sfstdout,'\n'); 578 } 579 580 static const Tty_t *lookup(const char *name) 581 { 582 register int i; 583 for(i=0; i < elementsof(Ttable); i++) 584 { 585 if(strcmp(Ttable[i].name,name)==0) 586 return(&Ttable[i]); 587 } 588 return(0); 589 590 } 591 592 static const Tty_t *getspeed(unsigned long val) 593 { 594 register int i; 595 for(i=0; i < elementsof(Ttable); i++) 596 { 597 if(Ttable[i].type==SPEED && Ttable[i].mask==val) 598 return(&Ttable[i]); 599 } 600 return(0); 601 } 602 603 static int gettchar(register const char *cp) 604 { 605 if(*cp==0) 606 return(-1); 607 if(cp[1]==0) 608 return((unsigned)cp[0]); 609 if(*cp=='^' && cp[1] && cp[2]==0) 610 { 611 switch(cp[1]) 612 { 613 case '-': 614 return(-1); 615 default: 616 return(cntl(cp[1])); 617 } 618 } 619 if(streq(cp,"undef") || streq(cp,"<undef>")) 620 return(-1); 621 return(*((unsigned char*)cp)); 622 } 623 624 static void set(char *argv[], struct termios *sp) 625 { 626 const Tty_t *tp; 627 register int c,off; 628 char *cp; 629 char *ep; 630 while(cp = *argv++) 631 { 632 off = 0; 633 if(*cp=='-') 634 { 635 cp++; 636 off=1; 637 } 638 if(!(tp=lookup(cp)) || (off && (tp->type!=BIT) && (tp->type!=TABS))) 639 error(ERROR_exit(1),"%s: unknown mode",cp); 640 switch(tp->type) 641 { 642 case CHAR: 643 if(off) 644 error(ERROR_exit(1),"%s: unknown mode",cp); 645 if(!*argv) 646 error(ERROR_exit(1),"missing argument to %s",cp); 647 c = gettchar(*argv++); 648 if(c>=0) 649 sp->c_cc[tp->mask] = c; 650 else 651 sp->c_cc[tp->mask] = _POSIX_VDISABLE; 652 break; 653 case BIT: case BITS: 654 switch(tp->field) 655 { 656 case C_FLAG: 657 if(off) 658 sp->c_cflag &= ~tp->mask; 659 else 660 sp->c_cflag |= tp->mask; 661 break; 662 case I_FLAG: 663 if(off) 664 sp->c_iflag &= ~tp->mask; 665 else 666 sp->c_iflag |= tp->mask; 667 break; 668 case O_FLAG: 669 sp->c_oflag &= ~tp->mask; 670 sp->c_oflag |= tp->val; 671 break; 672 case L_FLAG: 673 if(off) 674 sp->c_lflag &= ~tp->mask; 675 else 676 sp->c_lflag |= tp->mask; 677 break; 678 } 679 break; 680 case TABS: 681 sp->c_oflag &= ~tp->mask; 682 if(off) 683 sp->c_oflag |= tp->val; 684 break; 685 #ifdef TIOCSWINSZ 686 case WIND: 687 { 688 struct winsize win; 689 int n; 690 if(ioctl(0,TIOCGWINSZ,&win)<0) 691 error(ERROR_system(1),"cannot set %s",tp->name); 692 if(!(cp= *argv)) 693 { 694 sfprintf(sfstdout,"%d\n",tp->mask?win.ws_col:win.ws_row); 695 break; 696 } 697 argv++; 698 n=strtol(cp,&cp,10); 699 if(*cp) 700 error(ERROR_system(1),"%d: invalid number of %s",argv[-1],tp->name); 701 if(tp->mask) 702 win.ws_col = n; 703 else 704 win.ws_row = n; 705 if(ioctl(0,TIOCSWINSZ,&win)<0) 706 error(ERROR_system(1),"cannot set %s",tp->name); 707 break; 708 } 709 #endif 710 case NUM: 711 cp = *argv; 712 if (!cp) 713 { 714 if (tp->field == C_SPEED) 715 { 716 if (tp = getspeed(*tp->name == 'i' ? cfgetispeed(sp) : cfgetospeed(sp))) 717 sfprintf(sfstdout, "%s\n", tp->name); 718 break; 719 } 720 error(ERROR_exit(1), "%s: missing numeric argument", tp->name); 721 } 722 argv++; 723 c = (int)strtol(cp, &ep, 10); 724 if (*ep) 725 error(ERROR_exit(1), "%s: %s: numeric argument expected", tp->name, cp); 726 switch (tp->field) 727 { 728 #if _mem_c_line_termios 729 case C_LINE: 730 sp->c_line = c; 731 break; 732 #endif 733 case C_SPEED: 734 if(getspeed(c)) 735 { 736 if (*tp->name != 'o') 737 cfsetispeed(sp, c); 738 if (*tp->name != 'i') 739 cfsetospeed(sp, c); 740 } 741 else 742 error(ERROR_exit(1), "%s: %s: invalid speed", tp->name, cp); 743 break; 744 case T_CHAR: 745 sp->c_cc[tp->mask] = c; 746 break; 747 } 748 break; 749 case SPEED: 750 cfsetospeed(sp, tp->mask); 751 cfsetispeed(sp, tp->mask); 752 break; 753 case SIZE: 754 sp->c_cflag &= ~CSIZE; 755 sp->c_cflag |= tp->mask; 756 break; 757 case SANE: 758 sane(sp); 759 break; 760 #if defined(OLCUC) && defined(IUCLC) 761 case CASE: 762 if(off) 763 { 764 sp->c_iflag |= IUCLC; 765 sp->c_oflag |= OLCUC; 766 } 767 else 768 { 769 sp->c_iflag &= ~IUCLC; 770 sp->c_oflag &= ~OLCUC; 771 } 772 break; 773 #endif /* OLCUC && IUCLC */ 774 } 775 } 776 } 777 778 779 static void listchars(Sfio_t *sp,int type) 780 { 781 int i,c; 782 c = (type==CHAR?'c':'n'); 783 for(i=0; i < elementsof(Ttable); i++) 784 { 785 if(Ttable[i].type==type && *Ttable[i].description) 786 sfprintf(sp,"[+%s \a%c\a?%s.]",Ttable[i].name,c,Ttable[i].description); 787 } 788 } 789 790 static void listgroup(Sfio_t *sp,int type, const char *description) 791 { 792 int i; 793 sfprintf(sp,"[+"); 794 for(i=0; i < elementsof(Ttable); i++) 795 { 796 if(Ttable[i].type==type) 797 sfprintf(sp,"%s ",Ttable[i].name); 798 } 799 sfprintf(sp,"?%s.]",description); 800 } 801 802 static void listmask(Sfio_t *sp,unsigned int mask,const char *description) 803 { 804 int i; 805 sfprintf(sp,"[+"); 806 for(i=0; i < elementsof(Ttable); i++) 807 { 808 if(Ttable[i].mask==mask && Ttable[i].type==BITS) 809 sfprintf(sp,"%s ",Ttable[i].name); 810 } 811 sfprintf(sp,"?%s.]",description); 812 } 813 814 static void listfields(Sfio_t *sp,int field) 815 { 816 int i; 817 for(i=0; i < elementsof(Ttable); i++) 818 { 819 if(Ttable[i].field==field && Ttable[i].type==BIT && *Ttable[i].description) 820 sfprintf(sp,"[+%s (-%s)?%s.]",Ttable[i].name,Ttable[i].name,Ttable[i].description); 821 } 822 } 823 824 static void listmode(Sfio_t *sp,const char *name) 825 { 826 sfprintf(sp,"[+%s?%s.]",name,lookup(name)->description); 827 } 828 829 static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) 830 { 831 NoP(op); 832 NoP(s); 833 NoP(dp); 834 sfprintf(sp,"[+Control Modes.]{"); 835 listfields(sp,C_FLAG); 836 listgroup(sp,SPEED,"Attempt to set input and output baud rate to number given. A value of \b0\b causes immediate hangup"); 837 listchars(sp,NUM); 838 listgroup(sp,SIZE,"Number of bits in a character"); 839 sfprintf(sp,"}[+Input Modes.]{"); 840 listfields(sp,I_FLAG); 841 sfprintf(sp,"}[+Output Modes.]{"); 842 listfields(sp,O_FLAG); 843 #ifdef CRDLY 844 listmask(sp,CRDLY,"Carriage return delay style"); 845 #endif 846 #ifdef NLDLY 847 listmask(sp,NLDLY,"Newline delay style"); 848 #endif 849 #ifdef TABDLY 850 listmask(sp,TABDLY,"Horizontal tab delay style"); 851 #endif 852 #ifdef BSDLY 853 listmask(sp,BSDLY,"Backspace delay style"); 854 #endif 855 #ifdef FFDLY 856 listmask(sp,FFDLY,"Form feed delay style"); 857 #endif 858 #ifdef VTDLY 859 listmask(sp,VTDLY,"Vertical tab delay style"); 860 #endif 861 sfprintf(sp,"}[+Local Modes.]{"); 862 listfields(sp,L_FLAG); 863 sfprintf(sp,"}[+Control Assignments.?If \ac\a is \bundef\b or an empty " 864 "string then the control assignment is disabled.]{"); 865 listchars(sp,WIND); 866 listchars(sp,CHAR); 867 sfprintf(sp,"}[+Combination Modes.]{"); 868 listmode(sp,"ek"); 869 listmode(sp,"evenp"); 870 listmode(sp,"lcase"); 871 listmode(sp,"oddp"); 872 listmode(sp,"parity"); 873 listmode(sp,"sane"); 874 listmode(sp,"tabs"); 875 listmode(sp,"LCASE"); 876 sfputc(sp,'}'); 877 return(1); 878 } 879 880 int 881 b_stty(int argc, char** argv, void* context) 882 { 883 struct termios tty; 884 register int n; 885 register int flags = 0; 886 const Tty_t* tp; 887 Optdisc_t disc; 888 889 cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_INTERACTIVE); 890 if (tcgetattr(0, &tty) < 0) 891 error(ERROR_system(1),"not a tty"); 892 memset(&disc, 0, sizeof(disc)); 893 disc.version = OPT_VERSION; 894 disc.infof = infof; 895 opt_info.disc = &disc; 896 for (;;) 897 { 898 switch (n = optget(argv, usage)) 899 { 900 case 'a': 901 case 'g': 902 if (!opt_info.offset || !argv[opt_info.index][opt_info.offset]) 903 { 904 switch (n) 905 { 906 case 'a': 907 flags |= A_FLAG; 908 break; 909 case 'g': 910 flags |= G_FLAG; 911 break; 912 } 913 continue; 914 } 915 /*FALLTHROUGH*/ 916 case ':': 917 if (!opt_info.offset) 918 error(2, "%s", opt_info.arg); 919 else if (!(tp = lookup(argv[opt_info.index]+1)) || (tp->type != BIT && tp->type != TABS)) 920 error(ERROR_exit(1), "%s: unknown mode", argv[opt_info.index]); 921 break; 922 case '?': 923 error(ERROR_usage(2), "%s", opt_info.arg); 924 break; 925 } 926 break; 927 } 928 argv += opt_info.index; 929 if (error_info.errors || (flags && *argv)) 930 error(ERROR_usage(2), "%s", optusage(NiL)); 931 if (*argv) 932 { 933 if (!argv[1] && **argv == ':') 934 gin(*argv, &tty); 935 else 936 set(argv, &tty); 937 if (tcsetattr(0, TCSANOW, &tty) < 0) 938 error(ERROR_system(1), "cannot set tty"); 939 } 940 else 941 output(&tty, flags); 942 return error_info.errors; 943 } 944