3
0

stty.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302
  1. /* vi: set sw=4 ts=4: */
  2. /* stty -- change and print terminal line settings
  3. Copyright (C) 1990-1999 Free Software Foundation, Inc.
  4. Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  5. */
  6. /* Usage: stty [-ag] [-F device] [setting...]
  7. Options:
  8. -a Write all current settings to stdout in human-readable form.
  9. -g Write all current settings to stdout in stty-readable form.
  10. -F Open and use the specified device instead of stdin
  11. If no args are given, write to stdout the baud rate and settings that
  12. have been changed from their defaults. Mode reading and changes
  13. are done on the specified device, or stdin if none was specified.
  14. David MacKenzie <djm@gnu.ai.mit.edu>
  15. Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
  16. */
  17. #include "busybox.h"
  18. #ifndef _POSIX_VDISABLE
  19. # define _POSIX_VDISABLE ((unsigned char) 0)
  20. #endif
  21. #define Control(c) ((c) & 0x1f)
  22. /* Canonical values for control characters */
  23. #ifndef CINTR
  24. # define CINTR Control('c')
  25. #endif
  26. #ifndef CQUIT
  27. # define CQUIT 28
  28. #endif
  29. #ifndef CERASE
  30. # define CERASE 127
  31. #endif
  32. #ifndef CKILL
  33. # define CKILL Control('u')
  34. #endif
  35. #ifndef CEOF
  36. # define CEOF Control('d')
  37. #endif
  38. #ifndef CEOL
  39. # define CEOL _POSIX_VDISABLE
  40. #endif
  41. #ifndef CSTART
  42. # define CSTART Control('q')
  43. #endif
  44. #ifndef CSTOP
  45. # define CSTOP Control('s')
  46. #endif
  47. #ifndef CSUSP
  48. # define CSUSP Control('z')
  49. #endif
  50. #if defined(VEOL2) && !defined(CEOL2)
  51. # define CEOL2 _POSIX_VDISABLE
  52. #endif
  53. /* ISC renamed swtch to susp for termios, but we'll accept either name */
  54. #if defined(VSUSP) && !defined(VSWTCH)
  55. # define VSWTCH VSUSP
  56. # define CSWTCH CSUSP
  57. #endif
  58. #if defined(VSWTCH) && !defined(CSWTCH)
  59. # define CSWTCH _POSIX_VDISABLE
  60. #endif
  61. /* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
  62. So the default is to disable 'swtch.' */
  63. #if defined (__sparc__) && defined (__svr4__)
  64. # undef CSWTCH
  65. # define CSWTCH _POSIX_VDISABLE
  66. #endif
  67. #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
  68. # define VWERASE VWERSE
  69. #endif
  70. #if defined(VDSUSP) && !defined (CDSUSP)
  71. # define CDSUSP Control('y')
  72. #endif
  73. #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
  74. # define VREPRINT VRPRNT
  75. #endif
  76. #if defined(VREPRINT) && !defined(CRPRNT)
  77. # define CRPRNT Control('r')
  78. #endif
  79. #if defined(VWERASE) && !defined(CWERASE)
  80. # define CWERASE Control('w')
  81. #endif
  82. #if defined(VLNEXT) && !defined(CLNEXT)
  83. # define CLNEXT Control('v')
  84. #endif
  85. #if defined(VDISCARD) && !defined(VFLUSHO)
  86. # define VFLUSHO VDISCARD
  87. #endif
  88. #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
  89. # define VFLUSHO VFLUSH
  90. #endif
  91. #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
  92. # define ECHOCTL CTLECH
  93. #endif
  94. #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
  95. # define ECHOCTL TCTLECH
  96. #endif
  97. #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
  98. # define ECHOKE CRTKIL
  99. #endif
  100. #if defined(VFLUSHO) && !defined(CFLUSHO)
  101. # define CFLUSHO Control('o')
  102. #endif
  103. #if defined(VSTATUS) && !defined(CSTATUS)
  104. # define CSTATUS Control('t')
  105. #endif
  106. /* Which speeds to set */
  107. enum speed_setting {
  108. input_speed, output_speed, both_speeds
  109. };
  110. /* Which member(s) of 'struct termios' a mode uses */
  111. enum {
  112. /* Do NOT change the order or values, as mode_type_flag()
  113. * depends on them */
  114. control, input, output, local, combination
  115. };
  116. static const char evenp [] = "evenp";
  117. static const char raw [] = "raw";
  118. static const char stty_min [] = "min";
  119. static const char stty_time [] = "time";
  120. static const char stty_swtch[] = "swtch";
  121. static const char stty_eol [] = "eol";
  122. static const char stty_eof [] = "eof";
  123. static const char parity [] = "parity";
  124. static const char stty_oddp [] = "oddp";
  125. static const char stty_nl [] = "nl";
  126. static const char stty_ek [] = "ek";
  127. static const char stty_sane [] = "sane";
  128. static const char cbreak [] = "cbreak";
  129. static const char stty_pass8[] = "pass8";
  130. static const char litout [] = "litout";
  131. static const char cooked [] = "cooked";
  132. static const char decctlq [] = "decctlq";
  133. static const char stty_tabs [] = "tabs";
  134. static const char stty_lcase[] = "lcase";
  135. static const char stty_LCASE[] = "LCASE";
  136. static const char stty_crt [] = "crt";
  137. static const char stty_dec [] = "dec";
  138. /* Flags for 'struct mode_info' */
  139. #define SANE_SET 1 /* Set in 'sane' mode */
  140. #define SANE_UNSET 2 /* Unset in 'sane' mode */
  141. #define REV 4 /* Can be turned off by prepending '-' */
  142. #define OMIT 8 /* Don't display value */
  143. /* Each mode */
  144. struct mode_info {
  145. const char *name; /* Name given on command line */
  146. char type; /* Which structure element to change */
  147. char flags; /* Setting and display options */
  148. unsigned short mask; /* Other bits to turn off for this mode */
  149. unsigned long bits; /* Bits to set for this mode */
  150. };
  151. #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
  152. static const struct mode_info mode_info[] = {
  153. MI_ENTRY("parenb", control, REV, PARENB, 0 ),
  154. MI_ENTRY("parodd", control, REV, PARODD, 0 ),
  155. MI_ENTRY("cs5", control, 0, CS5, CSIZE),
  156. MI_ENTRY("cs6", control, 0, CS6, CSIZE),
  157. MI_ENTRY("cs7", control, 0, CS7, CSIZE),
  158. MI_ENTRY("cs8", control, 0, CS8, CSIZE),
  159. MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
  160. MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
  161. MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
  162. MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
  163. MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
  164. #ifdef CRTSCTS
  165. MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
  166. #endif
  167. MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
  168. MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
  169. MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
  170. MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
  171. MI_ENTRY("inpck", input, REV, INPCK, 0 ),
  172. MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
  173. MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
  174. MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
  175. MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
  176. MI_ENTRY("ixon", input, REV, IXON, 0 ),
  177. MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
  178. MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
  179. #ifdef IUCLC
  180. MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
  181. #endif
  182. #ifdef IXANY
  183. MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
  184. #endif
  185. #ifdef IMAXBEL
  186. MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
  187. #endif
  188. MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
  189. #ifdef OLCUC
  190. MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
  191. #endif
  192. #ifdef OCRNL
  193. MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
  194. #endif
  195. #ifdef ONLCR
  196. MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
  197. #endif
  198. #ifdef ONOCR
  199. MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
  200. #endif
  201. #ifdef ONLRET
  202. MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
  203. #endif
  204. #ifdef OFILL
  205. MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
  206. #endif
  207. #ifdef OFDEL
  208. MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
  209. #endif
  210. #ifdef NLDLY
  211. MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
  212. MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
  213. #endif
  214. #ifdef CRDLY
  215. MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
  216. MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
  217. MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
  218. MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
  219. #endif
  220. #ifdef TABDLY
  221. MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
  222. MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
  223. MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
  224. MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
  225. #else
  226. # ifdef OXTABS
  227. MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
  228. # endif
  229. #endif
  230. #ifdef BSDLY
  231. MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
  232. MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
  233. #endif
  234. #ifdef VTDLY
  235. MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
  236. MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
  237. #endif
  238. #ifdef FFDLY
  239. MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
  240. MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
  241. #endif
  242. MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
  243. MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
  244. #ifdef IEXTEN
  245. MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
  246. #endif
  247. MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
  248. MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
  249. MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
  250. MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
  251. MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
  252. MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
  253. #ifdef XCASE
  254. MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
  255. #endif
  256. #ifdef TOSTOP
  257. MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
  258. #endif
  259. #ifdef ECHOPRT
  260. MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
  261. MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
  262. #endif
  263. #ifdef ECHOCTL
  264. MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
  265. MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
  266. #endif
  267. #ifdef ECHOKE
  268. MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
  269. MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
  270. #endif
  271. MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
  272. MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
  273. MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
  274. MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
  275. MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
  276. MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
  277. MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
  278. MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
  279. MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
  280. MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
  281. MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
  282. #ifdef IXANY
  283. MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
  284. #endif
  285. #if defined(TABDLY) || defined(OXTABS)
  286. MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
  287. #endif
  288. #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
  289. MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
  290. MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
  291. #endif
  292. MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
  293. MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
  294. };
  295. enum {
  296. NUM_mode_info = (sizeof(mode_info) / sizeof(mode_info[0]))
  297. };
  298. /* Control character settings */
  299. struct control_info {
  300. const char *name; /* Name given on command line */
  301. unsigned char saneval; /* Value to set for 'stty sane' */
  302. unsigned char offset; /* Offset in c_cc */
  303. };
  304. /* Control characters */
  305. static const struct control_info control_info[] = {
  306. {"intr", CINTR, VINTR},
  307. {"quit", CQUIT, VQUIT},
  308. {"erase", CERASE, VERASE},
  309. {"kill", CKILL, VKILL},
  310. {stty_eof, CEOF, VEOF},
  311. {stty_eol, CEOL, VEOL},
  312. #ifdef VEOL2
  313. {"eol2", CEOL2, VEOL2},
  314. #endif
  315. #ifdef VSWTCH
  316. {stty_swtch, CSWTCH, VSWTCH},
  317. #endif
  318. {"start", CSTART, VSTART},
  319. {"stop", CSTOP, VSTOP},
  320. {"susp", CSUSP, VSUSP},
  321. #ifdef VDSUSP
  322. {"dsusp", CDSUSP, VDSUSP},
  323. #endif
  324. #ifdef VREPRINT
  325. {"rprnt", CRPRNT, VREPRINT},
  326. #endif
  327. #ifdef VWERASE
  328. {"werase", CWERASE, VWERASE},
  329. #endif
  330. #ifdef VLNEXT
  331. {"lnext", CLNEXT, VLNEXT},
  332. #endif
  333. #ifdef VFLUSHO
  334. {"flush", CFLUSHO, VFLUSHO},
  335. #endif
  336. #ifdef VSTATUS
  337. {"status", CSTATUS, VSTATUS},
  338. #endif
  339. /* These must be last because of the display routines */
  340. {stty_min, 1, VMIN},
  341. {stty_time, 0, VTIME},
  342. };
  343. enum {
  344. NUM_control_info = (sizeof(control_info) / sizeof(control_info[0]))
  345. };
  346. /* The width of the screen, for output wrapping */
  347. static unsigned max_col = 80; /* default */
  348. /* Current position, to know when to wrap */
  349. static unsigned current_col;
  350. static const char *device_name = bb_msg_standard_input;
  351. /* Return a string that is the printable representation of character CH */
  352. /* Adapted from 'cat' by Torbjorn Granlund */
  353. static const char *visible(unsigned int ch)
  354. {
  355. static char buf[10];
  356. char *bpout = buf;
  357. if (ch == _POSIX_VDISABLE)
  358. return "<undef>";
  359. if (ch >= 128) {
  360. ch -= 128;
  361. *bpout++ = 'M';
  362. *bpout++ = '-';
  363. }
  364. if (ch < 32) {
  365. *bpout++ = '^';
  366. *bpout++ = ch + 64;
  367. } else if (ch < 127) {
  368. *bpout++ = ch;
  369. } else {
  370. *bpout++ = '^';
  371. *bpout++ = '?';
  372. }
  373. *bpout = '\0';
  374. return buf;
  375. }
  376. static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
  377. {
  378. static const unsigned char tcflag_offsets[] = {
  379. offsetof(struct termios, c_cflag), /* control */
  380. offsetof(struct termios, c_iflag), /* input */
  381. offsetof(struct termios, c_oflag), /* output */
  382. offsetof(struct termios, c_lflag), /* local */
  383. };
  384. if (type <= local) {
  385. return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
  386. }
  387. return NULL;
  388. }
  389. static speed_t string_to_baud_or_die(const char *arg)
  390. {
  391. return tty_value_to_baud(xatou(arg));
  392. }
  393. static void set_speed_or_die(enum speed_setting type, const char *arg,
  394. struct termios *mode)
  395. {
  396. speed_t baud;
  397. baud = string_to_baud_or_die(arg);
  398. if (type != output_speed) { /* either input or both */
  399. cfsetispeed(mode, baud);
  400. }
  401. if (type != input_speed) { /* either output or both */
  402. cfsetospeed(mode, baud);
  403. }
  404. }
  405. static ATTRIBUTE_NORETURN void perror_on_device_and_die(const char *fmt)
  406. {
  407. bb_perror_msg_and_die(fmt, device_name);
  408. }
  409. static void perror_on_device(const char *fmt)
  410. {
  411. bb_perror_msg(fmt, device_name);
  412. }
  413. /* No, inline won't be as efficient (gcc 3.4.3) */
  414. #define streq(a,b) (!strcmp((a),(b)))
  415. /* Print format string MESSAGE and optional args.
  416. Wrap to next line first if it won't fit.
  417. Print a space first unless MESSAGE will start a new line */
  418. static void wrapf(const char *message, ...)
  419. {
  420. char buf[128];
  421. va_list args;
  422. int buflen;
  423. va_start(args, message);
  424. vsnprintf(buf, sizeof(buf), message, args);
  425. va_end(args);
  426. buflen = strlen(buf);
  427. if (!buflen) return;
  428. if (current_col > 0) {
  429. current_col++;
  430. if (buf[0] != '\n') {
  431. if (current_col + buflen >= max_col) {
  432. putchar('\n');
  433. current_col = 0;
  434. } else
  435. putchar(' ');
  436. }
  437. }
  438. fputs(buf, stdout);
  439. current_col += buflen;
  440. if (buf[buflen-1] == '\n')
  441. current_col = 0;
  442. }
  443. #ifdef TIOCGWINSZ
  444. static int get_win_size(int fd, struct winsize *win)
  445. {
  446. return ioctl(fd, TIOCGWINSZ, (char *) win);
  447. }
  448. static void set_window_size(int rows, int cols)
  449. {
  450. struct winsize win;
  451. if (get_win_size(STDIN_FILENO, &win)) {
  452. if (errno != EINVAL) {
  453. perror_on_device("%s");
  454. return;
  455. }
  456. memset(&win, 0, sizeof(win));
  457. }
  458. if (rows >= 0)
  459. win.ws_row = rows;
  460. if (cols >= 0)
  461. win.ws_col = cols;
  462. # ifdef TIOCSSIZE
  463. /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
  464. The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
  465. This comment from sys/ttold.h describes Sun's twisted logic - a better
  466. test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
  467. At any rate, the problem is gone in Solaris 2.x */
  468. if (win.ws_row == 0 || win.ws_col == 0) {
  469. struct ttysize ttysz;
  470. ttysz.ts_lines = win.ws_row;
  471. ttysz.ts_cols = win.ws_col;
  472. win.ws_row = win.ws_col = 1;
  473. if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
  474. || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
  475. perror_on_device("%s");
  476. }
  477. return;
  478. }
  479. # endif
  480. if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
  481. perror_on_device("%s");
  482. }
  483. static void display_window_size(int fancy)
  484. {
  485. const char *fmt_str = "%s\0%s: no size information for this device";
  486. struct winsize win;
  487. if (get_win_size(STDIN_FILENO, &win)) {
  488. if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
  489. perror_on_device(fmt_str);
  490. }
  491. } else {
  492. wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
  493. win.ws_row, win.ws_col);
  494. }
  495. }
  496. #else /* !TIOCGWINSZ */
  497. static inline void display_window_size(int fancy) {}
  498. #endif /* !TIOCGWINSZ */
  499. static int screen_columns_or_die(void)
  500. {
  501. const char *s;
  502. #ifdef TIOCGWINSZ
  503. struct winsize win;
  504. /* With Solaris 2.[123], this ioctl fails and errno is set to
  505. EINVAL for telnet (but not rlogin) sessions.
  506. On ISC 3.0, it fails for the console and the serial port
  507. (but it works for ptys).
  508. It can also fail on any system when stdout isn't a tty.
  509. In case of any failure, just use the default */
  510. if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
  511. return win.ws_col;
  512. #endif
  513. s = getenv("COLUMNS");
  514. if (s)
  515. return xatoi_u(s);
  516. return 80;
  517. }
  518. static const struct suffix_mult stty_suffixes[] = {
  519. {"b", 512 },
  520. {"k", 1024},
  521. {"B", 1024},
  522. {NULL, 0 }
  523. };
  524. static const struct mode_info *find_mode(const char *name)
  525. {
  526. int i;
  527. for (i = 0; i < NUM_mode_info; ++i)
  528. if (streq(name, mode_info[i].name))
  529. return &mode_info[i];
  530. return 0;
  531. }
  532. static const struct control_info *find_control(const char *name)
  533. {
  534. int i;
  535. for (i = 0; i < NUM_control_info; ++i)
  536. if (streq(name, control_info[i].name))
  537. return &control_info[i];
  538. return 0;
  539. }
  540. enum {
  541. param_need_arg = 0x80,
  542. param_line = 1 | 0x80,
  543. param_rows = 2 | 0x80,
  544. param_cols = 3 | 0x80,
  545. param_size = 4,
  546. param_speed = 5,
  547. param_ispeed = 6 | 0x80,
  548. param_ospeed = 7 | 0x80,
  549. };
  550. static int find_param(const char *name)
  551. {
  552. #ifdef HAVE_C_LINE
  553. if (streq(name, "line")) return param_line;
  554. #endif
  555. #ifdef TIOCGWINSZ
  556. if (streq(name, "rows")) return param_rows;
  557. if (streq(name, "cols")) return param_cols;
  558. if (streq(name, "columns")) return param_cols;
  559. if (streq(name, "size")) return param_size;
  560. #endif
  561. if (streq(name, "speed")) return param_speed;
  562. if (streq(name, "ispeed")) return param_ispeed;
  563. if (streq(name, "ospeed")) return param_ospeed;
  564. return 0;
  565. }
  566. static int recover_mode(const char *arg, struct termios *mode);
  567. static void set_mode(const struct mode_info *info,
  568. int reversed, struct termios *mode);
  569. static void display_all(const struct termios *mode);
  570. static void display_changed(const struct termios *mode);
  571. static void display_recoverable(const struct termios *mode);
  572. static void display_speed(const struct termios *mode, int fancy);
  573. static void sane_mode(struct termios *mode);
  574. static void set_control_char_or_die(const struct control_info *info,
  575. const char *arg, struct termios *mode);
  576. int stty_main(int argc, char **argv)
  577. {
  578. struct termios mode;
  579. void (*output_func)(const struct termios *);
  580. const char *file_name = NULL;
  581. int require_set_attr;
  582. int speed_was_set;
  583. int verbose_output;
  584. int recoverable_output;
  585. int noargs;
  586. int k;
  587. output_func = display_changed;
  588. noargs = 1;
  589. speed_was_set = 0;
  590. require_set_attr = 0;
  591. verbose_output = 0;
  592. recoverable_output = 0;
  593. /* First pass: only parse/verify command line params */
  594. k = 0;
  595. while (argv[++k]) {
  596. const struct mode_info *mp;
  597. const struct control_info *cp;
  598. const char *arg = argv[k];
  599. const char *argnext = argv[k+1];
  600. int param;
  601. if (arg[0] == '-') {
  602. int i;
  603. mp = find_mode(arg+1);
  604. if (mp) {
  605. if (!(mp->flags & REV))
  606. bb_error_msg_and_die("invalid argument '%s'", arg);
  607. noargs = 0;
  608. continue;
  609. }
  610. /* It is an option - parse it */
  611. i = 0;
  612. while (arg[++i]) {
  613. switch (arg[i]) {
  614. case 'a':
  615. verbose_output = 1;
  616. output_func = display_all;
  617. break;
  618. case 'g':
  619. recoverable_output = 1;
  620. output_func = display_recoverable;
  621. break;
  622. case 'F':
  623. if (file_name)
  624. bb_error_msg_and_die("only one device may be specified");
  625. file_name = &arg[i+1]; /* "-Fdevice" ? */
  626. if (!file_name[0]) { /* nope, "-F device" */
  627. int p = k+1; /* argv[p] is argnext */
  628. file_name = argnext;
  629. if (!file_name)
  630. bb_error_msg_and_die(bb_msg_requires_arg, "-F");
  631. /* remove -F param from arg[vc] */
  632. --argc;
  633. while (argv[p]) { argv[p] = argv[p+1]; ++p; }
  634. }
  635. goto end_option;
  636. default:
  637. bb_error_msg_and_die("invalid argument '%s'", arg);
  638. }
  639. }
  640. end_option:
  641. continue;
  642. }
  643. mp = find_mode(arg);
  644. if (mp) {
  645. noargs = 0;
  646. continue;
  647. }
  648. cp = find_control(arg);
  649. if (cp) {
  650. if (!argnext)
  651. bb_error_msg_and_die(bb_msg_requires_arg, arg);
  652. /* called for the side effect of xfunc death only */
  653. set_control_char_or_die(cp, argnext, &mode);
  654. noargs = 0;
  655. ++k;
  656. continue;
  657. }
  658. param = find_param(arg);
  659. if (param & param_need_arg) {
  660. if (!argnext)
  661. bb_error_msg_and_die(bb_msg_requires_arg, arg);
  662. ++k;
  663. }
  664. switch (param) {
  665. #ifdef HAVE_C_LINE
  666. case param_line:
  667. # ifndef TIOCGWINSZ
  668. xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
  669. break;
  670. # endif /* else fall-through */
  671. #endif
  672. #ifdef TIOCGWINSZ
  673. case param_rows:
  674. case param_cols:
  675. xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
  676. break;
  677. case param_size:
  678. #endif
  679. case param_speed:
  680. break;
  681. case param_ispeed:
  682. /* called for the side effect of xfunc death only */
  683. set_speed_or_die(input_speed, argnext, &mode);
  684. break;
  685. case param_ospeed:
  686. /* called for the side effect of xfunc death only */
  687. set_speed_or_die(output_speed, argnext, &mode);
  688. break;
  689. default:
  690. if (recover_mode(arg, &mode) == 1) break;
  691. if (string_to_baud_or_die(arg) != (speed_t) -1) break;
  692. bb_error_msg_and_die("invalid argument '%s'", arg);
  693. }
  694. noargs = 0;
  695. }
  696. /* Specifying both -a and -g is an error */
  697. if (verbose_output && recoverable_output)
  698. bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
  699. /* Specifying -a or -g with non-options is an error */
  700. if (!noargs && (verbose_output || recoverable_output))
  701. bb_error_msg_and_die("modes may not be set when specifying an output style");
  702. /* Now it is safe to start doing things */
  703. if (file_name) {
  704. int fd, fdflags;
  705. device_name = file_name;
  706. fd = xopen(device_name, O_RDONLY | O_NONBLOCK);
  707. if (fd != STDIN_FILENO) {
  708. dup2(fd, STDIN_FILENO);
  709. close(fd);
  710. }
  711. fdflags = fcntl(STDIN_FILENO, F_GETFL);
  712. if (fdflags == -1 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
  713. perror_on_device_and_die("%s: cannot reset non-blocking mode");
  714. }
  715. /* Initialize to all zeroes so there is no risk memcmp will report a
  716. spurious difference in an uninitialized portion of the structure */
  717. memset(&mode, 0, sizeof(mode));
  718. if (tcgetattr(STDIN_FILENO, &mode))
  719. perror_on_device_and_die("%s");
  720. if (verbose_output || recoverable_output || noargs) {
  721. max_col = screen_columns_or_die();
  722. output_func(&mode);
  723. return EXIT_SUCCESS;
  724. }
  725. /* Second pass: perform actions */
  726. k = 0;
  727. while (argv[++k]) {
  728. const struct mode_info *mp;
  729. const struct control_info *cp;
  730. const char *arg = argv[k];
  731. const char *argnext = argv[k+1];
  732. int param;
  733. if (arg[0] == '-') {
  734. mp = find_mode(arg+1);
  735. if (mp) {
  736. set_mode(mp, 1 /* reversed */, &mode);
  737. }
  738. /* It is an option - already parsed. Skip it */
  739. continue;
  740. }
  741. mp = find_mode(arg);
  742. if (mp) {
  743. set_mode(mp, 0 /* non-reversed */, &mode);
  744. continue;
  745. }
  746. cp = find_control(arg);
  747. if (cp) {
  748. ++k;
  749. set_control_char_or_die(cp, argnext, &mode);
  750. continue;
  751. }
  752. param = find_param(arg);
  753. if (param & param_need_arg) {
  754. ++k;
  755. }
  756. switch (param) {
  757. #ifdef HAVE_C_LINE
  758. case param_line:
  759. mode.c_line = xatoul_sfx(argnext, stty_suffixes);
  760. require_set_attr = 1;
  761. break;
  762. #endif
  763. #ifdef TIOCGWINSZ
  764. case param_cols:
  765. set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
  766. break;
  767. case param_size:
  768. display_window_size(0);
  769. break;
  770. case param_rows:
  771. set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
  772. break;
  773. #endif
  774. case param_speed:
  775. display_speed(&mode, 0);
  776. break;
  777. case param_ispeed:
  778. set_speed_or_die(input_speed, argnext, &mode);
  779. speed_was_set = 1;
  780. require_set_attr = 1;
  781. break;
  782. case param_ospeed:
  783. set_speed_or_die(output_speed, argnext, &mode);
  784. speed_was_set = 1;
  785. require_set_attr = 1;
  786. break;
  787. default:
  788. if (recover_mode(arg, &mode) == 1)
  789. require_set_attr = 1;
  790. else /* true: if (string_to_baud_or_die(arg) != (speed_t) -1) */ {
  791. set_speed_or_die(both_speeds, arg, &mode);
  792. speed_was_set = 1;
  793. require_set_attr = 1;
  794. } /* else - impossible (caught in the first pass):
  795. bb_error_msg_and_die("invalid argument '%s'", arg); */
  796. }
  797. }
  798. if (require_set_attr) {
  799. struct termios new_mode;
  800. if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
  801. perror_on_device_and_die("%s");
  802. /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
  803. it performs *any* of the requested operations. This means it
  804. can report 'success' when it has actually failed to perform
  805. some proper subset of the requested operations. To detect
  806. this partial failure, get the current terminal attributes and
  807. compare them to the requested ones */
  808. /* Initialize to all zeroes so there is no risk memcmp will report a
  809. spurious difference in an uninitialized portion of the structure */
  810. memset(&new_mode, 0, sizeof(new_mode));
  811. if (tcgetattr(STDIN_FILENO, &new_mode))
  812. perror_on_device_and_die("%s");
  813. if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
  814. #ifdef CIBAUD
  815. /* SunOS 4.1.3 (at least) has the problem that after this sequence,
  816. tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
  817. sometimes (m1 != m2). The only difference is in the four bits
  818. of the c_cflag field corresponding to the baud rate. To save
  819. Sun users a little confusion, don't report an error if this
  820. happens. But suppress the error only if we haven't tried to
  821. set the baud rate explicitly -- otherwise we'd never give an
  822. error for a true failure to set the baud rate */
  823. new_mode.c_cflag &= (~CIBAUD);
  824. if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
  825. #endif
  826. perror_on_device_and_die("%s: cannot perform all requested operations");
  827. }
  828. }
  829. return EXIT_SUCCESS;
  830. }
  831. /* Save set_mode from #ifdef forest plague */
  832. #ifndef ONLCR
  833. #define ONLCR 0
  834. #endif
  835. #ifndef OCRNL
  836. #define OCRNL 0
  837. #endif
  838. #ifndef ONLRET
  839. #define ONLRET 0
  840. #endif
  841. #ifndef XCASE
  842. #define XCASE 0
  843. #endif
  844. #ifndef IXANY
  845. #define IXANY 0
  846. #endif
  847. #ifndef TABDLY
  848. #define TABDLY 0
  849. #endif
  850. #ifndef OXTABS
  851. #define OXTABS 0
  852. #endif
  853. #ifndef IUCLC
  854. #define IUCLC 0
  855. #endif
  856. #ifndef OLCUC
  857. #define OLCUC 0
  858. #endif
  859. #ifndef ECHOCTL
  860. #define ECHOCTL 0
  861. #endif
  862. #ifndef ECHOKE
  863. #define ECHOKE 0
  864. #endif
  865. static void set_mode(const struct mode_info *info, int reversed,
  866. struct termios *mode)
  867. {
  868. tcflag_t *bitsp;
  869. bitsp = mode_type_flag(info->type, mode);
  870. if (bitsp) {
  871. if (reversed)
  872. *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
  873. else
  874. *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
  875. return;
  876. }
  877. /* Combination mode */
  878. if (info->name == evenp || info->name == parity) {
  879. if (reversed)
  880. mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  881. else
  882. mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
  883. } else if (info->name == stty_oddp) {
  884. if (reversed)
  885. mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  886. else
  887. mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
  888. } else if (info->name == stty_nl) {
  889. if (reversed) {
  890. mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
  891. mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
  892. } else {
  893. mode->c_iflag = mode->c_iflag & ~ICRNL;
  894. if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
  895. }
  896. } else if (info->name == stty_ek) {
  897. mode->c_cc[VERASE] = CERASE;
  898. mode->c_cc[VKILL] = CKILL;
  899. } else if (info->name == stty_sane) {
  900. sane_mode(mode);
  901. }
  902. else if (info->name == cbreak) {
  903. if (reversed)
  904. mode->c_lflag |= ICANON;
  905. else
  906. mode->c_lflag &= ~ICANON;
  907. } else if (info->name == stty_pass8) {
  908. if (reversed) {
  909. mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
  910. mode->c_iflag |= ISTRIP;
  911. } else {
  912. mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  913. mode->c_iflag &= ~ISTRIP;
  914. }
  915. } else if (info->name == litout) {
  916. if (reversed) {
  917. mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
  918. mode->c_iflag |= ISTRIP;
  919. mode->c_oflag |= OPOST;
  920. } else {
  921. mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
  922. mode->c_iflag &= ~ISTRIP;
  923. mode->c_oflag &= ~OPOST;
  924. }
  925. } else if (info->name == raw || info->name == cooked) {
  926. if ((info->name[0] == 'r' && reversed)
  927. || (info->name[0] == 'c' && !reversed)) {
  928. /* Cooked mode */
  929. mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
  930. mode->c_oflag |= OPOST;
  931. mode->c_lflag |= ISIG | ICANON;
  932. #if VMIN == VEOF
  933. mode->c_cc[VEOF] = CEOF;
  934. #endif
  935. #if VTIME == VEOL
  936. mode->c_cc[VEOL] = CEOL;
  937. #endif
  938. } else {
  939. /* Raw mode */
  940. mode->c_iflag = 0;
  941. mode->c_oflag &= ~OPOST;
  942. mode->c_lflag &= ~(ISIG | ICANON | XCASE);
  943. mode->c_cc[VMIN] = 1;
  944. mode->c_cc[VTIME] = 0;
  945. }
  946. }
  947. else if (IXANY && info->name == decctlq) {
  948. if (reversed)
  949. mode->c_iflag |= IXANY;
  950. else
  951. mode->c_iflag &= ~IXANY;
  952. }
  953. else if (TABDLY && info->name == stty_tabs) {
  954. if (reversed)
  955. mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
  956. else
  957. mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
  958. }
  959. else if (OXTABS && info->name == stty_tabs) {
  960. if (reversed)
  961. mode->c_oflag |= OXTABS;
  962. else
  963. mode->c_oflag &= ~OXTABS;
  964. }
  965. else if (XCASE && IUCLC && OLCUC
  966. && (info->name == stty_lcase || info->name == stty_LCASE)) {
  967. if (reversed) {
  968. mode->c_lflag &= ~XCASE;
  969. mode->c_iflag &= ~IUCLC;
  970. mode->c_oflag &= ~OLCUC;
  971. } else {
  972. mode->c_lflag |= XCASE;
  973. mode->c_iflag |= IUCLC;
  974. mode->c_oflag |= OLCUC;
  975. }
  976. }
  977. else if (info->name == stty_crt) {
  978. mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
  979. }
  980. else if (info->name == stty_dec) {
  981. mode->c_cc[VINTR] = 3; /* ^C */
  982. mode->c_cc[VERASE] = 127; /* DEL */
  983. mode->c_cc[VKILL] = 21; /* ^U */
  984. mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
  985. if (IXANY) mode->c_iflag &= ~IXANY;
  986. }
  987. }
  988. static void set_control_char_or_die(const struct control_info *info,
  989. const char *arg, struct termios *mode)
  990. {
  991. unsigned char value;
  992. if (info->name == stty_min || info->name == stty_time)
  993. value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
  994. else if (arg[0] == '\0' || arg[1] == '\0')
  995. value = arg[0];
  996. else if (streq(arg, "^-") || streq(arg, "undef"))
  997. value = _POSIX_VDISABLE;
  998. else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
  999. value = arg[1] & 0x1f; /* Non-letters get weird results */
  1000. if (arg[1] == '?')
  1001. value = 127;
  1002. } else
  1003. value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
  1004. mode->c_cc[info->offset] = value;
  1005. }
  1006. static void display_changed(const struct termios *mode)
  1007. {
  1008. int i;
  1009. tcflag_t *bitsp;
  1010. unsigned long mask;
  1011. int prev_type = control;
  1012. display_speed(mode, 1);
  1013. #ifdef HAVE_C_LINE
  1014. wrapf("line = %d;\n", mode->c_line);
  1015. #else
  1016. wrapf("\n");
  1017. #endif
  1018. for (i = 0; control_info[i].name != stty_min; ++i) {
  1019. if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
  1020. continue;
  1021. /* If swtch is the same as susp, don't print both */
  1022. #if VSWTCH == VSUSP
  1023. if (control_info[i].name == stty_swtch)
  1024. continue;
  1025. #endif
  1026. /* If eof uses the same slot as min, only print whichever applies */
  1027. #if VEOF == VMIN
  1028. if ((mode->c_lflag & ICANON) == 0
  1029. && (control_info[i].name == stty_eof
  1030. || control_info[i].name == stty_eol)) continue;
  1031. #endif
  1032. wrapf("%s = %s;", control_info[i].name,
  1033. visible(mode->c_cc[control_info[i].offset]));
  1034. }
  1035. if ((mode->c_lflag & ICANON) == 0) {
  1036. wrapf("min = %d; time = %d;", (int) mode->c_cc[VMIN],
  1037. (int) mode->c_cc[VTIME]);
  1038. }
  1039. if (current_col) wrapf("\n");
  1040. for (i = 0; i < NUM_mode_info; ++i) {
  1041. if (mode_info[i].flags & OMIT)
  1042. continue;
  1043. if (mode_info[i].type != prev_type) {
  1044. if (current_col) wrapf("\n");
  1045. prev_type = mode_info[i].type;
  1046. }
  1047. bitsp = mode_type_flag(mode_info[i].type, mode);
  1048. mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
  1049. if ((*bitsp & mask) == mode_info[i].bits) {
  1050. if (mode_info[i].flags & SANE_UNSET) {
  1051. wrapf("%s", mode_info[i].name);
  1052. }
  1053. } else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) {
  1054. wrapf("-%s", mode_info[i].name);
  1055. }
  1056. }
  1057. if (current_col) wrapf("\n");
  1058. }
  1059. static void display_all(const struct termios *mode)
  1060. {
  1061. int i;
  1062. tcflag_t *bitsp;
  1063. unsigned long mask;
  1064. int prev_type = control;
  1065. display_speed(mode, 1);
  1066. display_window_size(1);
  1067. #ifdef HAVE_C_LINE
  1068. wrapf("line = %d;\n", mode->c_line);
  1069. #else
  1070. wrapf("\n");
  1071. #endif
  1072. for (i = 0; control_info[i].name != stty_min; ++i) {
  1073. /* If swtch is the same as susp, don't print both */
  1074. #if VSWTCH == VSUSP
  1075. if (control_info[i].name == stty_swtch)
  1076. continue;
  1077. #endif
  1078. /* If eof uses the same slot as min, only print whichever applies */
  1079. #if VEOF == VMIN
  1080. if ((mode->c_lflag & ICANON) == 0
  1081. && (control_info[i].name == stty_eof
  1082. || control_info[i].name == stty_eol)) continue;
  1083. #endif
  1084. wrapf("%s = %s;", control_info[i].name,
  1085. visible(mode->c_cc[control_info[i].offset]));
  1086. }
  1087. #if VEOF == VMIN
  1088. if ((mode->c_lflag & ICANON) == 0)
  1089. #endif
  1090. wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
  1091. if (current_col) wrapf("\n");
  1092. for (i = 0; i < NUM_mode_info; ++i) {
  1093. if (mode_info[i].flags & OMIT)
  1094. continue;
  1095. if (mode_info[i].type != prev_type) {
  1096. wrapf("\n");
  1097. prev_type = mode_info[i].type;
  1098. }
  1099. bitsp = mode_type_flag(mode_info[i].type, mode);
  1100. mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
  1101. if ((*bitsp & mask) == mode_info[i].bits)
  1102. wrapf("%s", mode_info[i].name);
  1103. else if (mode_info[i].flags & REV)
  1104. wrapf("-%s", mode_info[i].name);
  1105. }
  1106. if (current_col) wrapf("\n");
  1107. }
  1108. static void display_speed(const struct termios *mode, int fancy)
  1109. {
  1110. //01234567 8 9
  1111. const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
  1112. unsigned long ispeed, ospeed;
  1113. ospeed = ispeed = cfgetispeed(mode);
  1114. if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
  1115. ispeed = ospeed; /* in case ispeed was 0 */
  1116. //0123 4 5 6 7 8 9
  1117. fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
  1118. }
  1119. if (fancy) fmt_str += 9;
  1120. wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
  1121. }
  1122. static void display_recoverable(const struct termios *mode)
  1123. {
  1124. int i;
  1125. printf("%lx:%lx:%lx:%lx",
  1126. (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
  1127. (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
  1128. for (i = 0; i < NCCS; ++i)
  1129. printf(":%x", (unsigned int) mode->c_cc[i]);
  1130. putchar('\n');
  1131. }
  1132. static int recover_mode(const char *arg, struct termios *mode)
  1133. {
  1134. int i, n;
  1135. unsigned int chr;
  1136. unsigned long iflag, oflag, cflag, lflag;
  1137. /* Scan into temporaries since it is too much trouble to figure out
  1138. the right format for 'tcflag_t' */
  1139. if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
  1140. &iflag, &oflag, &cflag, &lflag, &n) != 4)
  1141. return 0;
  1142. mode->c_iflag = iflag;
  1143. mode->c_oflag = oflag;
  1144. mode->c_cflag = cflag;
  1145. mode->c_lflag = lflag;
  1146. arg += n;
  1147. for (i = 0; i < NCCS; ++i) {
  1148. if (sscanf(arg, ":%x%n", &chr, &n) != 1)
  1149. return 0;
  1150. mode->c_cc[i] = chr;
  1151. arg += n;
  1152. }
  1153. /* Fail if there are too many fields */
  1154. if (*arg != '\0')
  1155. return 0;
  1156. return 1;
  1157. }
  1158. static void sane_mode(struct termios *mode)
  1159. {
  1160. int i;
  1161. tcflag_t *bitsp;
  1162. for (i = 0; i < NUM_control_info; ++i) {
  1163. #if VMIN == VEOF
  1164. if (control_info[i].name == stty_min)
  1165. break;
  1166. #endif
  1167. mode->c_cc[control_info[i].offset] = control_info[i].saneval;
  1168. }
  1169. for (i = 0; i < NUM_mode_info; ++i) {
  1170. if (mode_info[i].flags & SANE_SET) {
  1171. bitsp = mode_type_flag(mode_info[i].type, mode);
  1172. *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
  1173. | mode_info[i].bits;
  1174. } else if (mode_info[i].flags & SANE_UNSET) {
  1175. bitsp = mode_type_flag(mode_info[i].type, mode);
  1176. *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
  1177. & ~mode_info[i].bits;
  1178. }
  1179. }
  1180. }