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