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