home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / sh-utils-1.12-src.tgz / tar.out / fsf / sh-utils / src / stty.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  44KB  |  1,710 lines

  1. /* stty -- change and print terminal line settings
  2.    Copyright (C) 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Usage: stty [-ag] [--all] [--save] [setting...]
  19.  
  20.    Options:
  21.    -a, --all    Write all current settings to stdout in human-readable form.
  22.    -g, --save   Write all current settings to stdout in stty-readable form.
  23.  
  24.    If no args are given, write to stdout the baud rate and settings that
  25.    have been changed from their defaults.  Mode reading and changes
  26.    are done on stdin.
  27.  
  28.    David MacKenzie <djm@gnu.ai.mit.edu> */
  29.  
  30. #include <config.h>
  31. #include <stdio.h>
  32. #include <sys/types.h>
  33. #include <termios.h>
  34. #ifdef GWINSZ_IN_SYS_IOCTL
  35. #include <sys/ioctl.h>
  36. #endif
  37. #ifdef WINSIZE_IN_PTEM
  38. #include <sys/stream.h>
  39. #include <sys/ptem.h>
  40. #endif
  41. #include <getopt.h>
  42. #ifdef __STDC__
  43. #include <stdarg.h>
  44. #define VA_START(args, lastarg) va_start(args, lastarg)
  45. #else
  46. #include <varargs.h>
  47. #define VA_START(args, lastarg) va_start(args)
  48. #endif
  49.  
  50. #include "system.h"
  51. #include "version.h"
  52. #include "long-options.h"
  53.  
  54. #if defined(GWINSZ_BROKEN)    /* Such as for SCO UNIX 3.2.2. */
  55. #undef TIOCGWINSZ
  56. #endif
  57.  
  58. #ifndef _POSIX_VDISABLE
  59. #define _POSIX_VDISABLE ((unsigned char) 0)
  60. #endif
  61.  
  62. #define Control(c) ((c) & 0x1f)
  63. /* Canonical values for control characters. */
  64. #ifndef CINTR
  65. #define CINTR Control ('c')
  66. #endif
  67. #ifndef CQUIT
  68. #define CQUIT 28
  69. #endif
  70. #ifndef CERASE
  71. #define CERASE 127
  72. #endif
  73. #ifndef CKILL
  74. #define CKILL Control ('u')
  75. #endif
  76. #ifndef CEOF
  77. #define CEOF Control ('d')
  78. #endif
  79. #ifndef CEOL
  80. #define CEOL _POSIX_VDISABLE
  81. #endif
  82. #ifndef CSTART
  83. #define CSTART Control ('q')
  84. #endif
  85. #ifndef CSTOP
  86. #define CSTOP Control ('s')
  87. #endif
  88. #ifndef CSUSP
  89. #define CSUSP Control ('z')
  90. #endif
  91. #if defined(VEOL2) && !defined(CEOL2)
  92. #define CEOL2 _POSIX_VDISABLE
  93. #endif
  94. #if defined(VSWTCH) && !defined(CSWTCH)
  95. #define CSWTCH _POSIX_VDISABLE
  96. #endif
  97.  
  98. /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
  99.    So the default is to disable `swtch.'  */
  100. #if defined (__sparc__) && defined (__svr4__)
  101. #undef CSWTCH
  102. #define CSWTCH _POSIX_VDISABLE
  103. #endif
  104.  
  105. #if defined(VWERSE) && !defined (VWERASE)    /* AIX-3.2.5 */
  106. #define VWERASE VWERSE
  107. #endif
  108. #if defined(VDSUSP) && !defined (CDSUSP)
  109. #define CDSUSP Control ('y')
  110. #endif
  111. #if !defined(VREPRINT) && defined(VRPRNT)    /* Irix 4.0.5 */
  112. #define VREPRINT VRPRNT
  113. #endif
  114. #if defined(VREPRINT) && !defined(CRPRNT)
  115. #define CRPRNT Control ('r')
  116. #endif
  117. #if defined(VWERASE) && !defined(CWERASE)
  118. #define CWERASE Control ('w')
  119. #endif
  120. #if defined(VLNEXT) && !defined(CLNEXT)
  121. #define CLNEXT Control ('v')
  122. #endif
  123. #if defined(VDISCARD) && !defined(VFLUSHO)
  124. #define VFLUSHO VDISCARD
  125. #endif
  126. #if defined(VFLUSH) && !defined(VFLUSHO)    /* Ultrix 4.2 */
  127. #define VFLUSHO VFLUSH
  128. #endif
  129. #if defined(VFLUSHO) && !defined(CFLUSHO)
  130. #define CFLUSHO Control ('o')
  131. #endif
  132. #if defined(VSTATUS) && !defined(CSTATUS)
  133. #define CSTATUS Control ('t')
  134. #endif
  135.  
  136. static const char *visible ();
  137. static unsigned long baud_to_value ();
  138. static int recover_mode ();
  139. static int screen_columns ();
  140. static int set_mode ();
  141. static long integer_arg ();
  142. static speed_t string_to_baud ();
  143. static tcflag_t *mode_type_flag ();
  144. static void display_all ();
  145. static void display_changed ();
  146. static void display_recoverable ();
  147. static void display_settings ();
  148. static void display_speed ();
  149. static void display_window_size ();
  150. static void sane_mode ();
  151. static void set_control_char ();
  152. static void set_speed ();
  153. static void set_window_size ();
  154.  
  155. void error ();
  156.  
  157. /* Which speeds to set.  */
  158. enum speed_setting
  159.   {
  160.     input_speed, output_speed, both_speeds
  161.   };
  162.  
  163. /* What to output and how.  */
  164. enum output_type
  165.   {
  166.     changed, all, recoverable    /* Default, -a, -g.  */
  167.   };
  168.  
  169. /* Which member(s) of `struct termios' a mode uses.  */
  170. enum mode_type
  171.   {
  172.     control, input, output, local, combination
  173.   };
  174.  
  175. /* Flags for `struct mode_info'. */
  176. #define SANE_SET 1        /* Set in `sane' mode. */
  177. #define SANE_UNSET 2        /* Unset in `sane' mode. */
  178. #define REV 4            /* Can be turned off by prepending `-'. */
  179. #define OMIT 8            /* Don't display value. */
  180.  
  181. /* Each mode.  */
  182. struct mode_info
  183.   {
  184.     const char *name;        /* Name given on command line.  */
  185.     enum mode_type type;    /* Which structure element to change. */
  186.     char flags;            /* Setting and display options.  */
  187.     unsigned long bits;        /* Bits to set for this mode.  */
  188.     unsigned long mask;        /* Other bits to turn off for this mode.  */
  189.   };
  190.  
  191. static struct mode_info mode_info[] =
  192. {
  193.   {"parenb", control, REV, PARENB, 0},
  194.   {"parodd", control, REV, PARODD, 0},
  195.   {"cs5", control, 0, CS5, CSIZE},
  196.   {"cs6", control, 0, CS6, CSIZE},
  197.   {"cs7", control, 0, CS7, CSIZE},
  198.   {"cs8", control, 0, CS8, CSIZE},
  199.   {"hupcl", control, REV, HUPCL, 0},
  200.   {"hup", control, REV | OMIT, HUPCL, 0},
  201.   {"cstopb", control, REV, CSTOPB, 0},
  202.   {"cread", control, SANE_SET | REV, CREAD, 0},
  203.   {"clocal", control, REV, CLOCAL, 0},
  204. #ifdef CRTSCTS
  205.   {"crtscts", control, REV, CRTSCTS, 0},
  206. #endif
  207.  
  208.   {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
  209.   {"brkint", input, SANE_SET | REV, BRKINT, 0},
  210.   {"ignpar", input, REV, IGNPAR, 0},
  211.   {"parmrk", input, REV, PARMRK, 0},
  212.   {"inpck", input, REV, INPCK, 0},
  213.   {"istrip", input, REV, ISTRIP, 0},
  214.   {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
  215.   {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
  216.   {"icrnl", input, SANE_SET | REV, ICRNL, 0},
  217.   {"ixon", input, REV, IXON, 0},
  218.   {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
  219.   {"tandem", input, REV | OMIT, IXOFF, 0},
  220. #ifdef IUCLC
  221.   {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
  222. #endif
  223. #ifdef IXANY
  224.   {"ixany", input, SANE_UNSET | REV, IXANY, 0},
  225. #endif
  226. #ifdef IMAXBEL
  227.   {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
  228. #endif
  229.  
  230.   {"opost", output, SANE_SET | REV, OPOST, 0},
  231. #ifdef OLCUC
  232.   {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
  233. #endif
  234. #ifdef OCRNL
  235.   {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
  236. #endif
  237. #ifdef ONLCR
  238.   {"onlcr", output, SANE_SET | REV, ONLCR, 0},
  239. #endif
  240. #ifdef ONOCR
  241.   {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
  242. #endif
  243. #ifdef ONLRET
  244.   {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
  245. #endif
  246. #ifdef OFILL
  247.   {"ofill", output, SANE_UNSET | REV, OFILL, 0},
  248. #endif
  249. #ifdef OFDEL
  250.   {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
  251. #endif
  252. #ifdef NLDLY
  253.   {"nl1", output, SANE_UNSET, NL1, NLDLY},
  254.   {"nl0", output, SANE_SET, NL0, NLDLY},
  255. #endif
  256. #ifdef CRDLY
  257.   {"cr3", output, SANE_UNSET, CR3, CRDLY},
  258.   {"cr2", output, SANE_UNSET, CR2, CRDLY},
  259.   {"cr1", output, SANE_UNSET, CR1, CRDLY},
  260.   {"cr0", output, SANE_SET, CR0, CRDLY},
  261. #endif
  262. #ifdef TABDLY
  263.   {"tab3", output, SANE_UNSET, TAB3, TABDLY},
  264.   {"tab2", output, SANE_UNSET, TAB2, TABDLY},
  265.   {"tab1", output, SANE_UNSET, TAB1, TABDLY},
  266.   {"tab0", output, SANE_SET, TAB0, TABDLY},
  267. #else
  268. #ifdef OXTABS
  269.   {"tab3", output, SANE_UNSET, OXTABS, 0},
  270. #endif
  271. #endif
  272. #ifdef BSDLY
  273.   {"bs1", output, SANE_UNSET, BS1, BSDLY},
  274.   {"bs0", output, SANE_SET, BS0, BSDLY},
  275. #endif
  276. #ifdef VTDLY
  277.   {"vt1", output, SANE_UNSET, VT1, VTDLY},
  278.   {"vt0", output, SANE_SET, VT0, VTDLY},
  279. #endif
  280. #ifdef FFDLY
  281.   {"ff1", output, SANE_UNSET, FF1, FFDLY},
  282.   {"ff0", output, SANE_SET, FF0, FFDLY},
  283. #endif
  284.  
  285.   {"isig", local, SANE_SET | REV, ISIG, 0},
  286.   {"icanon", local, SANE_SET | REV, ICANON, 0},
  287. #ifdef IEXTEN
  288.   {"iexten", local, SANE_SET | REV, IEXTEN, 0},
  289. #endif
  290.   {"echo", local, SANE_SET | REV, ECHO, 0},
  291.   {"echoe", local, SANE_SET | REV, ECHOE, 0},
  292.   {"crterase", local, REV | OMIT, ECHOE, 0},
  293.   {"echok", local, SANE_SET | REV, ECHOK, 0},
  294.   {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
  295.   {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
  296. #ifdef XCASE
  297.   {"xcase", local, SANE_UNSET | REV, XCASE, 0},
  298. #endif
  299. #ifdef TOSTOP
  300.   {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
  301. #endif
  302. #ifdef ECHOPRT
  303.   {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
  304.   {"prterase", local, REV | OMIT, ECHOPRT, 0},
  305. #endif
  306. #ifdef ECHOCTL
  307.   {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
  308.   {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
  309. #endif
  310. #ifdef ECHOKE
  311.   {"echoke", local, SANE_SET | REV, ECHOKE, 0},
  312.   {"crtkill", local, REV | OMIT, ECHOKE, 0},
  313. #endif
  314.  
  315.   {"evenp", combination, REV | OMIT, 0, 0},
  316.   {"parity", combination, REV | OMIT, 0, 0},
  317.   {"oddp", combination, REV | OMIT, 0, 0},
  318.   {"nl", combination, REV | OMIT, 0, 0},
  319.   {"ek", combination, OMIT, 0, 0},
  320.   {"sane", combination, OMIT, 0, 0},
  321.   {"cooked", combination, REV | OMIT, 0, 0},
  322.   {"raw", combination, REV | OMIT, 0, 0},
  323.   {"pass8", combination, REV | OMIT, 0, 0},
  324.   {"litout", combination, REV | OMIT, 0, 0},
  325.   {"cbreak", combination, REV | OMIT, 0, 0},
  326. #ifdef IXANY
  327.   {"decctlq", combination, REV | OMIT, 0, 0},
  328. #endif
  329. #if defined (TABDLY) || defined (OXTABS)
  330.   {"tabs", combination, REV | OMIT, 0, 0},
  331. #endif
  332. #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
  333.   {"lcase", combination, REV | OMIT, 0, 0},
  334.   {"LCASE", combination, REV | OMIT, 0, 0},
  335. #endif
  336.   {"crt", combination, OMIT, 0, 0},
  337.   {"dec", combination, OMIT, 0, 0},
  338.  
  339.   {NULL, control, 0, 0, 0}
  340. };
  341.  
  342. /* Control character settings.  */
  343. struct control_info
  344.   {
  345.     const char *name;        /* Name given on command line.  */
  346.     unsigned char saneval;    /* Value to set for `stty sane'.  */
  347.     int offset;            /* Offset in c_cc.  */
  348.   };
  349.  
  350. /* Control characters. */
  351.  
  352. static struct control_info control_info[] =
  353. {
  354.   {"intr", CINTR, VINTR},
  355.   {"quit", CQUIT, VQUIT},
  356.   {"erase", CERASE, VERASE},
  357.   {"kill", CKILL, VKILL},
  358.   {"eof", CEOF, VEOF},
  359.   {"eol", CEOL, VEOL},
  360. #ifdef VEOL2
  361.   {"eol2", CEOL2, VEOL2},
  362. #endif
  363. #ifdef VSWTCH
  364.   {"swtch", CSWTCH, VSWTCH},
  365. #endif
  366.   {"start", CSTART, VSTART},
  367.   {"stop", CSTOP, VSTOP},
  368.   {"susp", CSUSP, VSUSP},
  369. #ifdef VDSUSP
  370.   {"dsusp", CDSUSP, VDSUSP},
  371. #endif
  372. #ifdef VREPRINT
  373.   {"rprnt", CRPRNT, VREPRINT},
  374. #endif
  375. #ifdef VWERASE
  376.   {"werase", CWERASE, VWERASE},
  377. #endif
  378. #ifdef VLNEXT
  379.   {"lnext", CLNEXT, VLNEXT},
  380. #endif
  381. #ifdef VFLUSHO
  382.   {"flush", CFLUSHO, VFLUSHO},
  383. #endif
  384. #ifdef VSTATUS
  385.   {"status", CSTATUS, VSTATUS},
  386. #endif
  387.  
  388.   /* These must be last because of the display routines. */
  389.   {"min", 1, VMIN},
  390.   {"time", 0, VTIME},
  391.   {NULL, 0, 0}
  392. };
  393.  
  394. /* The width of the screen, for output wrapping. */
  395. static int max_col;
  396.  
  397. /* Current position, to know when to wrap. */
  398. static int current_col;
  399.  
  400. static struct option longopts[] =
  401. {
  402.   {"all", no_argument, NULL, 'a'},
  403.   {"save", no_argument, NULL, 'g'},
  404.   {NULL, 0, NULL, 0}
  405. };
  406.  
  407. /* The name this program was run with. */
  408. char *program_name;
  409.  
  410. /* Print format string MESSAGE and optional args.
  411.    Wrap to next line first if it won't fit.
  412.    Print a space first unless MESSAGE will start a new line. */
  413.  
  414. /* VARARGS */
  415. static void
  416. #ifdef __STDC__
  417. wrapf (const char *message,...)
  418. #else
  419. wrapf (message, va_alist)
  420.      const char *message;
  421.      va_dcl
  422. #endif
  423. {
  424.   va_list args;
  425.   char buf[1024];        /* Plenty long for our needs. */
  426.   int buflen;
  427.  
  428.   VA_START (args, message);
  429.   vsprintf (buf, message, args);
  430.   va_end (args);
  431.   buflen = strlen (buf);
  432.   if (current_col + (current_col > 0) + buflen >= max_col)
  433.     {
  434.       putchar ('\n');
  435.       current_col = 0;
  436.     }
  437.   if (current_col > 0)
  438.     {
  439.       putchar (' ');
  440.       current_col++;
  441.     }
  442.   fputs (buf, stdout);
  443.   current_col += buflen;
  444. }
  445.  
  446. static void
  447. usage (status)
  448.      int status;
  449. {
  450.   if (status != 0)
  451.     fprintf (stderr, "Try `%s --help' for more information.\n",
  452.          program_name);
  453.   else
  454.     {
  455.       printf ("\
  456. Usage: %s [SETTING]...\n\
  457.   or:  %s OPTION\n\
  458. ",
  459.           program_name, program_name);
  460.       printf ("\
  461. \n\
  462.   -a, --all       print all current settings in human-readable form\n\
  463.   -g, --save      print all current settings in a stty-readable form\n\
  464.       --help      display this help and exit\n\
  465.       --version   output version information and exit\n\
  466. \n\
  467. Optional - before SETTING indicates negation.  An * marks non-POSIX\n\
  468. settings.  The underlying system defines which settings are available.\n\
  469. ");
  470.       printf ("\
  471. \n\
  472. Special characters:\n\
  473. * dsusp CHAR    CHAR will send a terminal stop signal once input flushed\n\
  474.   eof CHAR      CHAR will send an end of file (terminate the input)\n\
  475.   eol CHAR      CHAR will end the line\n\
  476. * eol2 CHAR     alternate CHAR for ending the line\n\
  477.   erase CHAR    CHAR will erase the last character typed\n\
  478.   intr CHAR     CHAR will send an interrupt signal\n\
  479.   kill CHAR     CHAR will erase the current line\n\
  480. * lnext CHAR    CHAR will enter the next character quoted\n\
  481.   quit CHAR     CHAR will send a quit signal\n\
  482. * rprnt CHAR    CHAR will redraw the current line\n\
  483.   start CHAR    CHAR will restart the output after stopping it\n\
  484.   stop CHAR     CHAR will stop the output\n\
  485.   susp CHAR     CHAR will send a terminal stop signal\n\
  486. * swtch CHAR    CHAR will switch to a different shell layer\n\
  487. * werase CHAR   CHAR will erase the last word typed\n\
  488. ");
  489.       printf ("\
  490. \n\
  491. Special settings:\n\
  492.   N             set the input and output speeds to N bauds\n\
  493. * cols N        tell the kernel that the terminal has N columns\n\
  494. * columns N     same as cols N\n\
  495.   ispeed N      set the input speed to N\n\
  496. * line N        use line discipline N\n\
  497.   min N         with -icanon, set N characters minimum for a completed read\n\
  498.   ospeed N      set the output speed to N\n\
  499. * rows N        tell the kernel that the terminal has N rows\n\
  500. * size          print the number of rows and columns according to the kernel\n\
  501.   speed         print the terminal speed\n\
  502.   time N        with -icanon, set read timeout of N tenths of a second\n\
  503. ");
  504.       printf ("\
  505. \n\
  506. Control settings:\n\
  507.   [-]clocal     disable modem control signals\n\
  508.   [-]cread      allow input to be received\n\
  509. * [-]crtscts    enable RTS/CTS handshaking\n\
  510.   csN           set character size to N bits, N in [5..8]\n\
  511.   [-]cstopb     use two stop bits per character (one with `-')\n\
  512.   [-]hup        send a hangup signal when the last process closes the tty\n\
  513.   [-]hupcl      same as [-]hup\n\
  514.   [-]parenb     generate parity bit in output and expect parity bit in input\n\
  515.   [-]parodd     set odd parity (even with `-')\n\
  516. ");
  517.       printf ("\
  518. \n\
  519. Input settings:\n\
  520.   [-]brkint     breaks cause an interrupt signal\n\
  521.   [-]icrnl      translate carriage return to newline\n\
  522.   [-]ignbrk     ignore breaks\n\
  523.   [-]igncr      ignore carriage return\n\
  524.   [-]ignpar     ignore parity errors\n\
  525. * [-]imaxbel    beep and do not flush a full input buffer on a character\n\
  526.   [-]inlcr      translate newline to carriage return\n\
  527.   [-]inpck      enable input parity checking\n\
  528.   [-]istrip     clear high (8th) bit of input characters\n\
  529. * [-]iuclc      translate uppercase characters to lowercase\n\
  530. * [-]ixany      let any character restart output, not only start character\n\
  531.   [-]ixoff      enable sending of start/stop characters\n\
  532.   [-]ixon       enable XON/XOFF flow control\n\
  533.   [-]parmrk     mark parity errors (with a 255-0-character sequence)\n\
  534.   [-]tandem     same as [-]ixoff\n\
  535. ");
  536.       printf ("\
  537. \n\
  538. Output settings:\n\
  539. * bsN           backspace delay style, N in [0..1]\n\
  540. * crN           carriage return delay style, N in [0..3]\n\
  541. * ffN           form feed delay style, N in [0..1]\n\
  542. * nlN           newline delay style, N in [0..1]\n\
  543. * [-]ocrnl      translate carriage return to newline\n\
  544. * [-]ofdel      use delete characters for fill instead of null characters\n\
  545. * [-]ofill      use fill (padding) characters instead of timing for delays\n\
  546. * [-]olcuc      translate lowercase characters to uppercase\n\
  547. * [-]onlcr      translate newline to carriage return-newline\n\
  548. * [-]onlret     newline performs a carriage return\n\
  549. * [-]onocr      do not print carriage returns in the first column\n\
  550.   [-]opost      postprocess output\n\
  551. * tabN          horizontal tab delay style, N in [0..3]\n\
  552. * tabs          same as tab0\n\
  553. * -tabs         same as tab3\n\
  554. * vtN           vertical tab delay style, N in [0..1]\n\
  555. ");
  556.       printf ("\
  557. \n\
  558. Local settings:\n\
  559.   [-]crterase   echo erase characters as backspace-space-backspace\n\
  560. * crtkill       kill all line by obeying the echoprt and echoe settings\n\
  561. * -crtkill      kill all line by obeying the echoctl and echok settings\n\
  562. * [-]ctlecho    echo control characters in hat notation (`^c')\n\
  563.   [-]echo       echo input characters\n\
  564. * [-]echoctl    same as [-]ctlecho\n\
  565.   [-]echoe      same as [-]crterase\n\
  566.   [-]echok      echo a newline after a kill character\n\
  567. * [-]echoke     same as [-]crtkill\n\
  568.   [-]echonl     echo newline even if not echoing other characters\n\
  569. * [-]echoprt    echo erased characters backward, between `\\' and '/'\n\
  570.   [-]icanon     enable erase, kill, werase, and rprnt special characters\n\
  571.   [-]iexten     enable non-POSIX special characters\n\
  572.   [-]isig       enable interrupt, quit, and suspend special characters\n\
  573.   [-]noflsh     disable flushing after interrupt and quit special characters\n\
  574. * [-]prterase   same as [-]echoprt\n\
  575. * [-]tostop     stop background jobs that try to write to the terminal\n\
  576. * [-]xcase      with icanon, escape with `\\' for uppercase characters\n\
  577. ");
  578.       printf ("\
  579. \n\
  580. Combination settings:\n\
  581. * [-]LCASE      same as [-]lcase\n\
  582.   cbreak        same as -icanon\n\
  583.   -cbreak       same as icanon\n\
  584.   cooked        same as brkint ignpar istrip icrnl ixon opost isig\n\
  585.                 icanon, eof and eol characters to their default values\n\
  586.   -cooked       same as raw\n\
  587.   crt           same as echoe echoctl echoke\n\
  588.   dec           same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
  589.                 kill ^u\n\
  590. * [-]decctlq    same as [-]ixany\n\
  591.   ek            erase and kill characters to their default values\n\
  592.   evenp         same as parenb -parodd cs7\n\
  593.   -evenp        same as -parenb cs8\n\
  594. * [-]lcase      same as xcase iuclc olcuc\n\
  595.   litout        same as -parenb -istrip -opost cs8\n\
  596.   -litout       same as parenb istrip opost cs7\n\
  597.   nl            same as -icrnl -onlcr\n\
  598.   -nl           same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
  599.   oddp          same as parenb parodd cs7\n\
  600.   -oddp         same as -parenb cs8\n\
  601.   [-]parity     same as [-]evenp\n\
  602.   pass8         same as -parenb -istrip cs8\n\
  603.   -pass8        same as parenb istrip cs7\n\
  604.   raw           same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
  605.                 -inlcr -igncr -icrnl  -ixon  -ixoff  -iuclc  -ixany\n\
  606.                 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
  607.   -raw          same as cooked\n\
  608.   sane          same as cread -ignbrk brkint -inlcr -igncr icrnl\n\
  609.                 -ixoff -iucl -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
  610.                 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
  611.                 isig icanon iexten echo echoe echok -echonl -noflsh\n\
  612.                 -xcase -tostop -echoprt echoctl echoke, all special\n\
  613.                 characters to their default values.\n\
  614. ");
  615.       printf ("\
  616. \n\
  617. Handle the tty line connected to standard input.  Without arguments,\n\
  618. prints baud rate, line discipline, and deviations from stty sane.  In\n\
  619. settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
  620. 127; special values ^- or undef used to disable special characters.\n\
  621. ");
  622.     }
  623.   exit (status);
  624. }
  625.  
  626. main (argc, argv)
  627.      int argc;
  628.      char **argv;
  629. {
  630.   struct termios mode;
  631.   enum output_type output_type;
  632.   int optc;
  633.   int require_set_attr;
  634.   int speed_was_set;
  635.   int verbose_output;
  636.   int recoverable_output;
  637.   int k;
  638.  
  639.   program_name = argv[0];
  640.  
  641.   parse_long_options (argc, argv, "stty", version_string, usage);
  642.  
  643.   output_type = changed;
  644.   verbose_output = 0;
  645.   recoverable_output = 0;
  646.  
  647.   /* Recognize the long options only.  */
  648.   opterr = 0;
  649.   while ((optc = getopt_long_only (argc, argv, "ag", longopts, (int *) 0))
  650.      != EOF)
  651.     {
  652.       switch (optc)
  653.     {
  654.     case 'a':
  655.       verbose_output = 1;
  656.       output_type = all;
  657.       break;
  658.  
  659.     case 'g':
  660.       recoverable_output = 1;
  661.       output_type = recoverable;
  662.       break;
  663.  
  664.     default:
  665.       break;
  666.     }
  667.     }
  668.  
  669.   /* Recognize short options and combinations: -a, -g, -ag, and -ga.
  670.      They need not precede non-options.  We cannot use GNU getopt because
  671.      it would treat -tabs and -ixany as uses of the -a option.  */
  672.   for (k = optind; k < argc; k++)
  673.     {
  674.       if (argv[k][0] == '-')
  675.     {
  676.       if (argv[k][1] == 'a'
  677.           && argv[k][2] == '\0')
  678.         {
  679.           ++optind;
  680.           verbose_output = 1;
  681.         }
  682.       else if (argv[k][1] == 'g'
  683.            && argv[k][2] == '\0')
  684.         {
  685.           ++optind;
  686.           recoverable_output = 1;
  687.         }
  688.       else if ((argv[k][1] == 'g'
  689.             && argv[k][2] == 'a'
  690.             && argv[k][3] == '\0')
  691.            || (argv[k][1] == 'a'
  692.                && argv[k][2] == 'g'
  693.                && argv[k][3] == '\0'))
  694.         {
  695.           ++optind;
  696.           verbose_output = 1;
  697.           recoverable_output = 1;
  698.         }
  699.     }
  700.     }
  701.  
  702.   /* Specifying both -a and -g gets an error.  */
  703.   if (verbose_output && recoverable_output)
  704.     error (2, 0,
  705.        "the options for verbose and stty-readable output styles are\n\
  706. \tmutually exclusive");
  707.  
  708.   /* Specifying any other arguments with -a or -g gets an error.  */
  709.   if (argc - optind > 0 && (verbose_output || recoverable_output))
  710.     error (2, 0, "when specifying an output style, modes may not be set");
  711.  
  712.   /* Initialize to all zeroes so there is no risk memcmp will report a
  713.      spurious difference in an uninitialized portion of the structure.  */
  714.   bzero (&mode, sizeof (mode));
  715.   if (tcgetattr (0, &mode))
  716.     error (1, errno, "standard input");
  717.  
  718.   if (verbose_output || recoverable_output || argc == 1)
  719.     {
  720.       max_col = screen_columns ();
  721.       current_col = 0;
  722.       display_settings (output_type, &mode);
  723.       exit (0);
  724.     }
  725.  
  726.   speed_was_set = 0;
  727.   require_set_attr = 0;
  728.   k = 1;
  729.   while (k < argc)
  730.     {
  731.       int match_found = 0;
  732.       int reversed = 0;
  733.       int i;
  734.  
  735.       if (argv[k][0] == '-')
  736.     {
  737.       ++argv[k];
  738.       reversed = 1;
  739.     }
  740.       for (i = 0; mode_info[i].name != NULL; ++i)
  741.     {
  742.       if (!strcmp (argv[k], mode_info[i].name))
  743.         {
  744.           match_found = set_mode (&mode_info[i], reversed, &mode);
  745.           require_set_attr = 1;
  746.           break;
  747.         }
  748.     }
  749.       if (match_found == 0 && reversed)
  750.     {
  751.       error (0, 0, "invalid argument `%s'", --argv[k]);
  752.       usage (1);
  753.     }
  754.       if (match_found == 0)
  755.     {
  756.       for (i = 0; control_info[i].name != NULL; ++i)
  757.         {
  758.           if (!strcmp (argv[k], control_info[i].name))
  759.         {
  760.           if (k == argc - 1)
  761.             {
  762.               error (0, 0, "missing argument to `%s'", argv[k]);
  763.               usage (1);
  764.             }
  765.           match_found = 1;
  766.           ++k;
  767.           set_control_char (&control_info[i], argv[k], &mode);
  768.           require_set_attr = 1;
  769.           break;
  770.         }
  771.         }
  772.     }
  773.       if (match_found == 0)
  774.     {
  775.       if (!strcmp (argv[k], "ispeed"))
  776.         {
  777.           if (k == argc - 1)
  778.         {
  779.           error (0, 0, "missing argument to `%s'", argv[k]);
  780.           usage (1);
  781.         }
  782.           ++k;
  783.           set_speed (input_speed, argv[k], &mode);
  784.           speed_was_set = 1;
  785.           require_set_attr = 1;
  786.         }
  787.       else if (!strcmp (argv[k], "ospeed"))
  788.         {
  789.           if (k == argc - 1)
  790.         {
  791.           error (0, 0, "missing argument to `%s'", argv[k]);
  792.           usage (1);
  793.         }
  794.           ++k;
  795.           set_speed (output_speed, argv[k], &mode);
  796.           speed_was_set = 1;
  797.           require_set_attr = 1;
  798.         }
  799. #ifdef TIOCGWINSZ
  800.       else if (!strcmp (argv[k], "rows"))
  801.         {
  802.           if (k == argc - 1)
  803.         {
  804.           error (0, 0, "missing argument to `%s'", argv[k]);
  805.           usage (1);
  806.         }
  807.           ++k;
  808.           set_window_size ((int) integer_arg (argv[k]), -1);
  809.         }
  810.       else if (!strcmp (argv[k], "cols")
  811.            || !strcmp (argv[k], "columns"))
  812.         {
  813.           if (k == argc - 1)
  814.         {
  815.           error (0, 0, "missing argument to `%s'", argv[k]);
  816.           usage (1);
  817.         }
  818.           ++k;
  819.           set_window_size (-1, (int) integer_arg (argv[k]));
  820.         }
  821.       else if (!strcmp (argv[k], "size"))
  822.         {
  823.           max_col = screen_columns ();
  824.           current_col = 0;
  825.           display_window_size (0);
  826.         }
  827. #endif
  828. #ifdef HAVE_C_LINE
  829.       else if (!strcmp (argv[k], "line"))
  830.         {
  831.           if (k == argc - 1)
  832.         {
  833.           error (0, 0, "missing argument to `%s'", argv[k]);
  834.           usage (1);
  835.         }
  836.           ++k;
  837.           mode.c_line = integer_arg (argv[k]);
  838.           require_set_attr = 1;
  839.         }
  840. #endif
  841.       else if (!strcmp (argv[k], "speed"))
  842.         {
  843.           max_col = screen_columns ();
  844.           display_speed (&mode, 0);
  845.         }
  846.       else if (string_to_baud (argv[k]) != (speed_t) -1)
  847.         {
  848.           set_speed (both_speeds, argv[k], &mode);
  849.           speed_was_set = 1;
  850.           require_set_attr = 1;
  851.         }
  852.       else
  853.         {
  854.           if (recover_mode (argv[k], &mode) == 0)
  855.         {
  856.           error (0, 0, "invalid argument `%s'", argv[k]);
  857.           usage (1);
  858.         }
  859.           require_set_attr = 1;
  860.         }
  861.     }
  862.       k++;
  863.     }
  864.  
  865.   if (require_set_attr)
  866.     {
  867.       struct termios new_mode;
  868.  
  869.       if (tcsetattr (0, TCSADRAIN, &mode))
  870.     error (1, errno, "standard input");
  871.  
  872.       /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
  873.      it performs *any* of the requested operations.  This means it
  874.      can report `success' when it has actually failed to perform
  875.      some proper subset of the requested operations.  To detect
  876.      this partial failure, get the current terminal attributes and
  877.      compare them to the requested ones.  */
  878.  
  879.       /* Initialize to all zeroes so there is no risk memcmp will report a
  880.      spurious difference in an uninitialized portion of the structure.  */
  881.       bzero (&new_mode, sizeof (new_mode));
  882.       if (tcgetattr (0, &new_mode))
  883.     error (1, errno, "standard input");
  884.  
  885.       /* Normally, one shouldn't use memcmp to compare structures that
  886.      may have `holes' containing uninitialized data, but we have been
  887.      careful to initialize the storage of these two variables to all
  888.      zeroes.  One might think it more efficient simply to compare the
  889.      modified fields, but that would require enumerating those fields --
  890.      and not all systems have the same fields in this structure.  */
  891.  
  892.       if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
  893.     {
  894. #ifdef CIBAUD
  895.       /* SunOS 4.1.3 (at least) has the problem that after this sequence,
  896.          tcgetattr(&m1); tcsetattr(&m1); tcgetattr(&m2);
  897.          sometimes (m1 != m2).  The only difference is in the four bits
  898.          of the c_cflag field corresponding to the baud rate.  To save
  899.          Sun users a little confusion, don't report an error if this
  900.          happens.  But suppress the error only if we haven't tried to
  901.          set the baud rate explicitly -- otherwise we'd never give an
  902.          error for a true failure to set the baud rate.  */
  903.  
  904.       new_mode.c_cflag &= (~CIBAUD);
  905.       if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
  906. #endif
  907.         error (1, 0,
  908.           "standard input: unable to perform all requested operations");
  909.     }
  910.     }
  911.  
  912.   exit (0);
  913. }
  914.  
  915. /* Return 0 if not applied because not reversible; otherwise return 1. */
  916.  
  917. static int
  918. set_mode (info, reversed, mode)
  919.      struct mode_info *info;
  920.      int reversed;
  921.      struct termios *mode;
  922. {
  923.   tcflag_t *bitsp;
  924.  
  925.   if (reversed && (info->flags & REV) == 0)
  926.     return 0;
  927.  
  928.   bitsp = mode_type_flag (info->type, mode);
  929.  
  930.   if (bitsp == NULL)
  931.     {
  932.       /* Combination mode. */
  933.       if (!strcmp (info->name, "evenp") || !strcmp (info->name, "parity"))
  934.     {
  935.       if (reversed)
  936.         mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  937.       else
  938.         mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
  939.     }
  940.       else if (!strcmp (info->name, "oddp"))
  941.     {
  942.       if (reversed)
  943.         mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  944.       else
  945.         mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
  946.     }
  947.       else if (!strcmp (info->name, "nl"))
  948.     {
  949.       if (reversed)
  950.         {
  951.           mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
  952.           mode->c_oflag = (mode->c_oflag
  953. #ifdef ONLCR
  954.                    | ONLCR
  955. #endif
  956.         )
  957. #ifdef OCRNL
  958.         & ~OCRNL
  959. #endif
  960. #ifdef ONLRET
  961.         & ~ONLRET
  962. #endif
  963.         ;
  964.         }
  965.       else
  966.         {
  967.           mode->c_iflag = mode->c_iflag & ~ICRNL;
  968. #ifdef ONLCR
  969.           mode->c_oflag = mode->c_oflag & ~ONLCR;
  970. #endif
  971.         }
  972.     }
  973.       else if (!strcmp (info->name, "ek"))
  974.     {
  975.       mode->c_cc[VERASE] = CERASE;
  976.       mode->c_cc[VKILL] = CKILL;
  977.     }
  978.       else if (!strcmp (info->name, "sane"))
  979.     sane_mode (mode);
  980.       else if (!strcmp (info->name, "cbreak"))
  981.     {
  982.       if (reversed)
  983.         mode->c_lflag |= ICANON;
  984.       else
  985.         mode->c_lflag &= ~ICANON;
  986.     }
  987.       else if (!strcmp (info->name, "pass8"))
  988.     {
  989.       if (reversed)
  990.         {
  991.           mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
  992.           mode->c_iflag |= ISTRIP;
  993.         }
  994.       else
  995.         {
  996.           mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  997.           mode->c_iflag &= ~ISTRIP;
  998.         }
  999.     }
  1000.       else if (!strcmp (info->name, "litout"))
  1001.     {
  1002.       if (reversed)
  1003.         {
  1004.           mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
  1005.           mode->c_iflag |= ISTRIP;
  1006.           mode->c_oflag |= OPOST;
  1007.         }
  1008.       else
  1009.         {
  1010.           mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  1011.           mode->c_iflag &= ~ISTRIP;
  1012.           mode->c_oflag &= ~OPOST;
  1013.         }
  1014.     }
  1015.       else if (!strcmp (info->name, "raw") || !strcmp (info->name, "cooked"))
  1016.     {
  1017.       if ((info->name[0] == 'r' && reversed)
  1018.           || (info->name[0] == 'c' && !reversed))
  1019.         {
  1020.           /* Cooked mode. */
  1021.           mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
  1022.           mode->c_oflag |= OPOST;
  1023.           mode->c_lflag |= ISIG | ICANON;
  1024. #if VMIN == VEOF
  1025.           mode->c_cc[VEOF] = CEOF;
  1026. #endif
  1027. #if VTIME == VEOL
  1028.           mode->c_cc[VEOL] = CEOL;
  1029. #endif
  1030.         }
  1031.       else
  1032.         {
  1033.           /* Raw mode. */
  1034.           mode->c_iflag = 0;
  1035.           mode->c_oflag &= ~OPOST;
  1036.           mode->c_lflag &= ~(ISIG | ICANON
  1037. #ifdef XCASE
  1038.                  | XCASE
  1039. #endif
  1040.         );
  1041.           mode->c_cc[VMIN] = 1;
  1042.           mode->c_cc[VTIME] = 0;
  1043.         }
  1044.     }
  1045. #ifdef IXANY
  1046.       else if (!strcmp (info->name, "decctlq"))
  1047.     {
  1048.       if (reversed)
  1049.         mode->c_iflag |= IXANY;
  1050.       else
  1051.         mode->c_iflag &= ~IXANY;
  1052.     }
  1053. #endif
  1054. #ifdef TABDLY
  1055.       else if (!strcmp (info->name, "tabs"))
  1056.     {
  1057.       if (reversed)
  1058.         mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
  1059.       else
  1060.         mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
  1061.     }
  1062. #else
  1063. #ifdef OXTABS
  1064.       else if (!strcmp (info->name, "tabs"))
  1065.     {
  1066.       if (reversed)
  1067.         mode->c_oflag = mode->c_oflag | OXTABS;
  1068.       else
  1069.         mode->c_oflag = mode->c_oflag & ~OXTABS;
  1070.     }
  1071. #endif
  1072. #endif
  1073. #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
  1074.       else if (!strcmp (info->name, "lcase")
  1075.            || !strcmp (info->name, "LCASE"))
  1076.     {
  1077.       if (reversed)
  1078.         {
  1079.           mode->c_lflag &= ~XCASE;
  1080.           mode->c_iflag &= ~IUCLC;
  1081.           mode->c_oflag &= ~OLCUC;
  1082.         }
  1083.       else
  1084.         {
  1085.           mode->c_lflag |= XCASE;
  1086.           mode->c_iflag |= IUCLC;
  1087.           mode->c_oflag |= OLCUC;
  1088.         }
  1089.     }
  1090. #endif
  1091.       else if (!strcmp (info->name, "crt"))
  1092.     mode->c_lflag |= ECHOE
  1093. #ifdef ECHOCTL
  1094.       | ECHOCTL
  1095. #endif
  1096. #ifdef ECHOKE
  1097.       | ECHOKE
  1098. #endif
  1099.       ;
  1100.       else if (!strcmp (info->name, "dec"))
  1101.     {
  1102.       mode->c_cc[VINTR] = 3;    /* ^C */
  1103.       mode->c_cc[VERASE] = 127;    /* DEL */
  1104.       mode->c_cc[VKILL] = 21;    /* ^U */
  1105.       mode->c_lflag |= ECHOE
  1106. #ifdef ECHOCTL
  1107.         | ECHOCTL
  1108. #endif
  1109. #ifdef ECHOKE
  1110.         | ECHOKE
  1111. #endif
  1112.         ;
  1113. #ifdef IXANY
  1114.       mode->c_iflag &= ~IXANY;
  1115. #endif
  1116.     }
  1117.     }
  1118.   else if (reversed)
  1119.     *bitsp = *bitsp & ~info->mask & ~info->bits;
  1120.   else
  1121.     *bitsp = (*bitsp & ~info->mask) | info->bits;
  1122.  
  1123.   return 1;
  1124. }
  1125.  
  1126. static void
  1127. set_control_char (info, arg, mode)
  1128.      struct control_info *info;
  1129.      char *arg;
  1130.      struct termios *mode;
  1131. {
  1132.   unsigned char value;
  1133.  
  1134.   if (!strcmp (info->name, "min") || !strcmp (info->name, "time"))
  1135.     value = integer_arg (arg);
  1136.   else if (arg[0] == '\0' || arg[1] == '\0')
  1137.     value = arg[0];
  1138.   else if (!strcmp (arg, "^-") || !strcmp (arg, "undef"))
  1139.     value = _POSIX_VDISABLE;
  1140.   else if (arg[0] == '^' && arg[1] != '\0')    /* Ignore any trailing junk. */
  1141.     {
  1142.       if (arg[1] == '?')
  1143.     value = 127;
  1144.       else
  1145.     value = arg[1] & ~0140;    /* Non-letters get weird results. */
  1146.     }
  1147.   else
  1148.     value = integer_arg (arg);
  1149.   mode->c_cc[info->offset] = value;
  1150. }
  1151.  
  1152. static void
  1153. set_speed (type, arg, mode)
  1154.      enum speed_setting type;
  1155.      char *arg;
  1156.      struct termios *mode;
  1157. {
  1158.   speed_t baud;
  1159.  
  1160.   baud = string_to_baud (arg);
  1161.   if (type == input_speed || type == both_speeds)
  1162.     cfsetispeed (mode, baud);
  1163.   if (type == output_speed || type == both_speeds)
  1164.     cfsetospeed (mode, baud);
  1165. }
  1166.  
  1167. #ifdef TIOCGWINSZ
  1168.  
  1169. /* Get window size information.  First try getting the information
  1170.    associated with standard output and if that fails, try standard input.
  1171.    Return zero for success, non-zero if both ioctl's failed.  */
  1172.  
  1173. static int
  1174. get_win_size (win)
  1175.      struct winsize *win;
  1176. {
  1177.   int err;
  1178.  
  1179.   err = ioctl (1, TIOCGWINSZ, (char *) win);
  1180.   if (err != 0)
  1181.     err = ioctl (0, TIOCGWINSZ, (char *) win);
  1182.   return err;
  1183. }
  1184.  
  1185. static void
  1186. set_window_size (rows, cols)
  1187.      int rows, cols;
  1188. {
  1189.   struct winsize win;
  1190.  
  1191.   if (get_win_size (&win))
  1192.     {
  1193.       if (errno != EINVAL)
  1194.     error (1, errno, "standard input");
  1195.       bzero (&win, sizeof (win));
  1196.     }
  1197.  
  1198.   if (rows >= 0)
  1199.     win.ws_row = rows;
  1200.   if (cols >= 0)
  1201.     win.ws_col = cols;
  1202.  
  1203. #ifdef TIOCSSIZE
  1204.   /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
  1205.      The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
  1206.      This comment from sys/ttold.h describes Sun's twisted logic - a better
  1207.      test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
  1208.      At any rate, the problem is gone in Solaris 2.x.
  1209.  
  1210.      Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
  1211.      but they can be disambiguated by checking whether a "struct ttysize"
  1212.      structure's "ts_lines" field is greater than 64K or not.  If so,
  1213.      it's almost certainly a "struct winsize" instead.
  1214.  
  1215.      At any rate, the bug manifests itself when ws_row == 0; the symptom is
  1216.      that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
  1217.      ws_ypixel.  Since GNU stty sets rows and columns separately, this bug
  1218.      caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
  1219.      "stty cols 0 rows 0" would do the right thing.  On a little-endian
  1220.      machine like the sun386i, the problem is the same, but for ws_col == 0.
  1221.  
  1222.      The workaround is to do the ioctl once with row and col = 1 to set the
  1223.      pixel info, and then do it again using a TIOCSSIZE to set rows/cols.  */
  1224.  
  1225.   if (win.ws_row == 0 || win.ws_col == 0)
  1226.     {
  1227.       struct ttysize ttysz;
  1228.  
  1229.       ttysz.ts_lines = win.ws_row;
  1230.       ttysz.ts_cols = win.ws_col;
  1231.  
  1232.       win.ws_row = 1;
  1233.       win.ws_col = 1;
  1234.  
  1235.       if (ioctl (0, TIOCSWINSZ, (char *) &win))
  1236.     error (1, errno, "standard input");
  1237.  
  1238.       if (ioctl (0, TIOCSSIZE, (char *) &ttysz))
  1239.     error (1, errno, "standard input");
  1240.       return;
  1241.     }
  1242. #endif
  1243.  
  1244.   if (ioctl (0, TIOCSWINSZ, (char *) &win))
  1245.     error (1, errno, "standard input");
  1246. }
  1247.  
  1248. static void
  1249. display_window_size (fancy)
  1250.      int fancy;
  1251. {
  1252.   struct winsize win;
  1253.  
  1254.   if (get_win_size (&win))
  1255.     {
  1256.       if (errno != EINVAL)
  1257.     error (1, errno, "standard input");
  1258.     }
  1259.   else
  1260.     {
  1261.       wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
  1262.          win.ws_row, win.ws_col);
  1263.       if (!fancy)
  1264.     current_col = 0;
  1265.     }
  1266. }
  1267. #endif
  1268.  
  1269. static int
  1270. screen_columns ()
  1271. {
  1272. #ifdef TIOCGWINSZ
  1273.   struct winsize win;
  1274.  
  1275.   if (get_win_size (&win))
  1276.     {
  1277.       /* With Solaris 2.[123], this ioctl fails and errno is set to
  1278.      EINVAL for telnet (but not rlogin) sessions.  */
  1279.       if (errno != EINVAL)
  1280.     error (1, errno, "standard input");
  1281.     }
  1282.   else if (win.ws_col > 0)
  1283.     return win.ws_col;
  1284. #endif
  1285.   if (getenv ("COLUMNS"))
  1286.     return atoi (getenv ("COLUMNS"));
  1287.   return 80;
  1288. }
  1289.  
  1290. static tcflag_t *
  1291. mode_type_flag (type, mode)
  1292.      enum mode_type type;
  1293.      struct termios *mode;
  1294. {
  1295.   switch (type)
  1296.     {
  1297.     case control:
  1298.       return &mode->c_cflag;
  1299.  
  1300.     case input:
  1301.       return &mode->c_iflag;
  1302.  
  1303.     case output:
  1304.       return &mode->c_oflag;
  1305.  
  1306.     case local:
  1307.       return &mode->c_lflag;
  1308.  
  1309.     case combination:
  1310.       return NULL;
  1311.  
  1312.     default:
  1313.       abort ();
  1314.     }
  1315. }
  1316.  
  1317. static void
  1318. display_settings (output_type, mode)
  1319.      enum output_type output_type;
  1320.      struct termios *mode;
  1321. {
  1322.   switch (output_type)
  1323.     {
  1324.     case changed:
  1325.       display_changed (mode);
  1326.       break;
  1327.  
  1328.     case all:
  1329.       display_all (mode);
  1330.       break;
  1331.  
  1332.     case recoverable:
  1333.       display_recoverable (mode);
  1334.       break;
  1335.     }
  1336. }
  1337.  
  1338. static void
  1339. display_changed (mode)
  1340.      struct termios *mode;
  1341. {
  1342.   int i;
  1343.   int empty_line;
  1344.   tcflag_t *bitsp;
  1345.   unsigned long mask;
  1346.   enum mode_type prev_type = control;
  1347.  
  1348.   display_speed (mode, 1);
  1349. #ifdef HAVE_C_LINE
  1350.   wrapf ("line = %d;", mode->c_line);
  1351. #endif
  1352.   putchar ('\n');
  1353.   current_col = 0;
  1354.  
  1355.   empty_line = 1;
  1356.   for (i = 0; strcmp (control_info[i].name, "min"); ++i)
  1357.     {
  1358.       if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
  1359.     continue;
  1360.       empty_line = 0;
  1361.       wrapf ("%s = %s;", control_info[i].name,
  1362.          visible (mode->c_cc[control_info[i].offset]));
  1363.     }
  1364.   if ((mode->c_lflag & ICANON) == 0)
  1365.     {
  1366.       wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
  1367.          (int) mode->c_cc[VTIME]);
  1368.     }
  1369.   else if (empty_line == 0)
  1370.     putchar ('\n');
  1371.   current_col = 0;
  1372.  
  1373.   empty_line = 1;
  1374.   for (i = 0; mode_info[i].name != NULL; ++i)
  1375.     {
  1376.       if (mode_info[i].flags & OMIT)
  1377.     continue;
  1378.       if (mode_info[i].type != prev_type)
  1379.     {
  1380.       if (empty_line == 0)
  1381.         {
  1382.           putchar ('\n');
  1383.           current_col = 0;
  1384.           empty_line = 1;
  1385.         }
  1386.       prev_type = mode_info[i].type;
  1387.     }
  1388.  
  1389.       bitsp = mode_type_flag (mode_info[i].type, mode);
  1390.       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
  1391.       if ((*bitsp & mask) == mode_info[i].bits)
  1392.     {
  1393.       if (mode_info[i].flags & SANE_UNSET)
  1394.         {
  1395.           wrapf ("%s", mode_info[i].name);
  1396.           empty_line = 0;
  1397.         }
  1398.     }
  1399.       else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
  1400.     {
  1401.       wrapf ("-%s", mode_info[i].name);
  1402.       empty_line = 0;
  1403.     }
  1404.     }
  1405.   if (empty_line == 0)
  1406.     putchar ('\n');
  1407.   current_col = 0;
  1408. }
  1409.  
  1410. static void
  1411. display_all (mode)
  1412.      struct termios *mode;
  1413. {
  1414.   int i;
  1415.   tcflag_t *bitsp;
  1416.   unsigned long mask;
  1417.   enum mode_type prev_type = control;
  1418.  
  1419.   display_speed (mode, 1);
  1420. #ifdef TIOCGWINSZ
  1421.   display_window_size (1);
  1422. #endif
  1423. #ifdef HAVE_C_LINE
  1424.   wrapf ("line = %d;", mode->c_line);
  1425. #endif
  1426.   putchar ('\n');
  1427.   current_col = 0;
  1428.  
  1429.   for (i = 0; strcmp (control_info[i].name, "min"); ++i)
  1430.     {
  1431.       wrapf ("%s = %s;", control_info[i].name,
  1432.          visible (mode->c_cc[control_info[i].offset]));
  1433.     }
  1434.   wrapf ("min = %d; time = %d;\n", mode->c_cc[VMIN], mode->c_cc[VTIME]);
  1435.   current_col = 0;
  1436.  
  1437.   for (i = 0; mode_info[i].name != NULL; ++i)
  1438.     {
  1439.       if (mode_info[i].flags & OMIT)
  1440.     continue;
  1441.       if (mode_info[i].type != prev_type)
  1442.     {
  1443.       putchar ('\n');
  1444.       current_col = 0;
  1445.       prev_type = mode_info[i].type;
  1446.     }
  1447.  
  1448.       bitsp = mode_type_flag (mode_info[i].type, mode);
  1449.       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
  1450.       if ((*bitsp & mask) == mode_info[i].bits)
  1451.     wrapf ("%s", mode_info[i].name);
  1452.       else if (mode_info[i].flags & REV)
  1453.     wrapf ("-%s", mode_info[i].name);
  1454.     }
  1455.   putchar ('\n');
  1456.   current_col = 0;
  1457. }
  1458.  
  1459. static void
  1460. display_speed (mode, fancy)
  1461.      struct termios *mode;
  1462.      int fancy;
  1463. {
  1464.   if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
  1465.     wrapf (fancy ? "speed %lu baud;" : "%lu\n",
  1466.        baud_to_value (cfgetospeed (mode)));
  1467.   else
  1468.     wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
  1469.        baud_to_value (cfgetispeed (mode)),
  1470.        baud_to_value (cfgetospeed (mode)));
  1471.   if (!fancy)
  1472.     current_col = 0;
  1473. }
  1474.  
  1475. static void
  1476. display_recoverable (mode)
  1477.      struct termios *mode;
  1478. {
  1479.   int i;
  1480.  
  1481.   printf ("%lx:%lx:%lx:%lx",
  1482.       (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
  1483.       (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
  1484.   for (i = 0; i < NCCS; ++i)
  1485.     printf (":%x", (unsigned int) mode->c_cc[i]);
  1486.   putchar ('\n');
  1487. }
  1488.  
  1489. static int
  1490. recover_mode (arg, mode)
  1491.      char *arg;
  1492.      struct termios *mode;
  1493. {
  1494.   int i, n;
  1495.   unsigned int chr;
  1496.   unsigned long iflag, oflag, cflag, lflag;
  1497.  
  1498.   /* Scan into temporaries since it is too much trouble to figure out
  1499.      the right format for `tcflag_t'.  */
  1500.   if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
  1501.           &iflag, &oflag, &cflag, &lflag, &n) != 4)
  1502.     return 0;
  1503.   mode->c_iflag = iflag;
  1504.   mode->c_oflag = oflag;
  1505.   mode->c_cflag = cflag;
  1506.   mode->c_lflag = lflag;
  1507.   arg += n;
  1508.   for (i = 0; i < NCCS; ++i)
  1509.     {
  1510.       if (sscanf (arg, ":%x%n", &chr, &n) != 1)
  1511.     return 0;
  1512.       mode->c_cc[i] = chr;
  1513.       arg += n;
  1514.     }
  1515.   return 1;
  1516. }
  1517.  
  1518. struct speed_map
  1519. {
  1520.   const char *string;        /* ASCII representation. */
  1521.   speed_t speed;        /* Internal form. */
  1522.   unsigned long value;        /* Numeric value. */
  1523. };
  1524.  
  1525. struct speed_map speeds[] =
  1526. {
  1527.   {"0", B0, 0},
  1528.   {"50", B50, 50},
  1529.   {"75", B75, 75},
  1530.   {"110", B110, 110},
  1531.   {"134", B134, 134},
  1532.   {"134.5", B134, 134},
  1533.   {"150", B150, 150},
  1534.   {"200", B200, 200},
  1535.   {"300", B300, 300},
  1536.   {"600", B600, 600},
  1537.   {"1200", B1200, 1200},
  1538.   {"1800", B1800, 1800},
  1539.   {"2400", B2400, 2400},
  1540.   {"4800", B4800, 4800},
  1541.   {"9600", B9600, 9600},
  1542.   {"19200", B19200, 19200},
  1543.   {"38400", B38400, 38400},
  1544.   {"exta", B19200, 19200},
  1545.   {"extb", B38400, 38400},
  1546. #ifdef B57600
  1547.   {"57600", B57600, 57600},
  1548. #endif
  1549. #ifdef B115200
  1550.   {"115200", B115200, 115200},
  1551. #endif
  1552.   {NULL, 0, 0}
  1553. };
  1554.  
  1555. static speed_t
  1556. string_to_baud (arg)
  1557.      char *arg;
  1558. {
  1559.   int i;
  1560.  
  1561.   for (i = 0; speeds[i].string != NULL; ++i)
  1562.     if (!strcmp (arg, speeds[i].string))
  1563.       return speeds[i].speed;
  1564.   return (speed_t) -1;
  1565. }
  1566.  
  1567. static unsigned long
  1568. baud_to_value (speed)
  1569.      speed_t speed;
  1570. {
  1571.   int i;
  1572.  
  1573.   for (i = 0; speeds[i].string != NULL; ++i)
  1574.     if (speed == speeds[i].speed)
  1575.       return speeds[i].value;
  1576.   return 0;
  1577. }
  1578.  
  1579. static void
  1580. sane_mode (mode)
  1581.      struct termios *mode;
  1582. {
  1583.   int i;
  1584.   tcflag_t *bitsp;
  1585.  
  1586.   for (i = 0; control_info[i].name; ++i)
  1587.     {
  1588. #if VMIN == VEOF
  1589.       if (!strcmp (control_info[i].name, "min"))
  1590.     break;
  1591. #endif
  1592.       mode->c_cc[control_info[i].offset] = control_info[i].saneval;
  1593.     }
  1594.  
  1595.   for (i = 0; mode_info[i].name != NULL; ++i)
  1596.     {
  1597.       if (mode_info[i].flags & SANE_SET)
  1598.     {
  1599.       bitsp = mode_type_flag (mode_info[i].type, mode);
  1600.       *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
  1601.     }
  1602.       else if (mode_info[i].flags & SANE_UNSET)
  1603.     {
  1604.       bitsp = mode_type_flag (mode_info[i].type, mode);
  1605.       *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
  1606.     }
  1607.     }
  1608. }
  1609.  
  1610. /* Return a string that is the printable representation of character CH.  */
  1611. /* Adapted from `cat' by Torbjorn Granlund.  */
  1612.  
  1613. static const char *
  1614. visible (ch)
  1615.      unsigned char ch;
  1616. {
  1617.   static char buf[10];
  1618.   char *bpout = buf;
  1619.  
  1620.   if (ch == _POSIX_VDISABLE)
  1621.     return "<undef>";
  1622.  
  1623.   if (ch >= 32)
  1624.     {
  1625.       if (ch < 127)
  1626.     *bpout++ = ch;
  1627.       else if (ch == 127)
  1628.     {
  1629.       *bpout++ = '^';
  1630.       *bpout++ = '?';
  1631.     }
  1632.       else
  1633.     {
  1634.       *bpout++ = 'M',
  1635.         *bpout++ = '-';
  1636.       if (ch >= 128 + 32)
  1637.         {
  1638.           if (ch < 128 + 127)
  1639.         *bpout++ = ch - 128;
  1640.           else
  1641.         {
  1642.           *bpout++ = '^';
  1643.           *bpout++ = '?';
  1644.         }
  1645.         }
  1646.       else
  1647.         {
  1648.           *bpout++ = '^';
  1649.           *bpout++ = ch - 128 + 64;
  1650.         }
  1651.     }
  1652.     }
  1653.   else
  1654.     {
  1655.       *bpout++ = '^';
  1656.       *bpout++ = ch + 64;
  1657.     }
  1658.   *bpout = '\0';
  1659.   return (const char *) buf;
  1660. }
  1661.  
  1662. /* Parse string S as an integer, using decimal radix by default,
  1663.    but allowing octal and hex numbers as in C.  */
  1664. /* From `od' by Richard Stallman.  */
  1665.  
  1666. static long
  1667. integer_arg (s)
  1668.      char *s;
  1669. {
  1670.   long value;
  1671.   int radix = 10;
  1672.   char *p = s;
  1673.   int c;
  1674.  
  1675.   if (*p != '0')
  1676.     radix = 10;
  1677.   else if (*++p == 'x')
  1678.     {
  1679.       radix = 16;
  1680.       p++;
  1681.     }
  1682.   else
  1683.     radix = 8;
  1684.  
  1685.   value = 0;
  1686.   while (((c = *p++) >= '0' && c <= '9')
  1687.      || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
  1688.     {
  1689.       value *= radix;
  1690.       if (c >= '0' && c <= '9')
  1691.     value += c - '0';
  1692.       else
  1693.     value += (c & ~40) - 'A';
  1694.     }
  1695.  
  1696.   if (c == 'b')
  1697.     value *= 512;
  1698.   else if (c == 'B')
  1699.     value *= 1024;
  1700.   else
  1701.     p--;
  1702.  
  1703.   if (*p)
  1704.     {
  1705.       error (0, 0, "invalid integer argument `%s'", s);
  1706.       usage (1);
  1707.     }
  1708.   return value;
  1709. }
  1710.