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