4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
27 * University Copyright- Copyright (c) 1982, 1986, 1988
28 * The Regents of the University of California
31 * University Acknowledgment- Portions of this document are derived from
32 * software developed by the University of California, Berkeley, and its
36 #pragma ident "%Z%%M% %I% %E% SMI"
39 * mailx -- a modified version of a University of California at Berkeley
42 * Generally useful tty stuff.
50 static char *readtty(char pr
[], char src
[]);
51 static int savetty(void);
52 static void ttycont(int);
54 static int c_erase
; /* Current erase char */
55 static int c_kill
; /* Current kill char */
56 static int c_intr
; /* interrupt char */
57 static int c_quit
; /* quit character */
58 static struct termio savtty
;
59 static char canonb
[LINESIZE
]; /* canonical buffer for input */
63 static void Echo(int cc
);
64 static int countcol(void);
65 static void outstr(register char *s
);
66 static void resetty(void);
67 static void rubout(register char *cp
);
68 static int setty(void);
70 static int c_word
; /* Current word erase char */
71 static int Col
; /* current output column */
72 static int Pcol
; /* end column of prompt string */
73 static int Out
; /* file descriptor of stdout */
74 static int erasing
; /* we are erasing characters */
75 static struct termio ttybuf
;
77 static jmp_buf rewrite
; /* Place to go when continued */
82 typedef int sig_atomic_t;
84 static sig_atomic_t hadcont
; /* Saw continue signal */
105 kill(mypid
, SIGSTOP
);
111 * Read all relevant header fields.
115 grabh(register struct header
*hp
, int gflags
, int subjtop
)
118 void (*savecont
)(int);
120 void (*savestop
)(int);
126 savecont
= sigset(SIGCONT
, ttycont
);
128 savestop
= sigset(SIGTSTP
, ttystop
);
132 hp
->h_to
= addto(NOSTR
, readtty("To: ", hp
->h_to
));
133 if (hp
->h_to
!= NOSTR
)
136 if (gflags
& GSUBJECT
&& subjtop
) {
137 hp
->h_subject
= readtty("Subject: ", hp
->h_subject
);
138 if (hp
->h_subject
!= NOSTR
)
142 hp
->h_cc
= addto(NOSTR
, readtty("Cc: ", hp
->h_cc
));
143 if (hp
->h_cc
!= NOSTR
)
147 hp
->h_bcc
= addto(NOSTR
, readtty("Bcc: ", hp
->h_bcc
));
148 if (hp
->h_bcc
!= NOSTR
)
151 if (gflags
& GSUBJECT
&& !subjtop
) {
152 hp
->h_subject
= readtty("Subject: ", hp
->h_subject
);
153 if (hp
->h_subject
!= NOSTR
)
157 (void) sigset(SIGCONT
, savecont
);
159 (void) sigset(SIGTSTP
, savestop
);
166 * Read up a header from standard input.
167 * The source string has the preliminary contents to
173 readtty(char pr
[], char src
[])
189 if (src
!= NOSTR
&& (int)strlen(src
) > LINESIZE
- 2) {
190 printf(gettext("too long to edit\n"));
196 cp2
= src
==NOSTR
? "" : src
;
197 for (cp
=canonb
; *cp2
; cp
++, cp2
++)
202 cp
= src
== NOSTR
? "" : src
;
206 if (c
== c_erase
|| c
== c_kill
) {
208 ioctl(0, TIOCSTI
, &ch
);
211 ioctl(0, TIOCSTI
, &ch
);
229 if (cp
[-1]=='\\' && !erasing
) {
235 } else if (c
==c_kill
) {
236 if (cp
> canonb
&& cp
[-1]=='\\') {
239 } else while (cp
> canonb
) {
242 } else if (c
==c_word
) {
244 if (cp
[-1]=='\\' && !erasing
) {
248 while (--cp
>= canonb
)
265 if (c
==EOF
|| ferror(stdin
) || c
==c_intr
|| c
==c_quit
) {
270 outstr("(continue)\n");
280 cp
= canonb
[0] != 0 ? canonb
: src
;
282 return(readtty(pr
, cp
));
289 savedead(c
==c_quit
? SIGQUIT
: SIGINT
);
300 return(savestr(canonb
));
315 if (ioctl(fileno(stdout
), TCGETA
, &savtty
) < 0)
319 c_erase
= savtty
.c_cc
[VERASE
];
320 c_kill
= savtty
.c_cc
[VKILL
];
321 c_intr
= savtty
.c_cc
[VINTR
];
322 c_quit
= savtty
.c_cc
[VQUIT
];
324 c_word
= 'W' & 037; /* erase word character */
325 Out
= fileno(stdout
);
328 ttybuf
.c_cflag
&= ~PARENB
; /* disable parity */
329 ttybuf
.c_cflag
|= CS8
; /* character size = 8 */
331 ttybuf
.c_cc
[VTIME
] = 0;
332 ttybuf
.c_cc
[VMIN
] = 1;
333 ttybuf
.c_iflag
&= ~(BRKINT
);
334 ttybuf
.c_lflag
&= ~(ICANON
|ISIG
|ECHO
);
343 if (ioctl(Out
, TCSETAW
, &ttybuf
) < 0) {
353 if (ioctl(Out
, TCSETAW
, &savtty
) < 0)
358 outstr(register char *s
)
365 rubout(register char *cp
)
368 register int c
= *cp
;
377 while (--Col
> oldcol
);
388 fputs("\b \b", stdout
);
400 for (col
=Pcol
, s
=canonb
; *s
; s
++)
436 fputs("\r\n", stdout
);
450 static void signull(int);
453 static int c_erase
; /* Current erase char */
454 static int c_kill
; /* Current kill char */
455 static int hadcont
; /* Saw continue signal */
456 static jmp_buf rewrite
; /* Place to go when continued */
458 static int ttyset
; /* We must now do erase/kill */
462 * Read all relevant header fields.
466 grabh(struct header
*hp
, int gflags
, int subjtop
)
468 struct sgttyb ttybuf
;
469 void (*savecont
)(int);
473 void (*savesigs
[2])(int);
477 savecont
= sigset(SIGCONT
, signull
);
483 if (gtty(fileno(stdin
), &ttybuf
) < 0) {
487 c_erase
= ttybuf
.sg_erase
;
488 c_kill
= ttybuf
.sg_kill
;
492 for (s
= SIGINT
; s
<= SIGQUIT
; s
++)
493 if ((savesigs
[s
-SIGINT
] = sigset(s
, SIG_IGN
)) == SIG_DFL
)
498 if (!ttyset
&& hp
->h_to
!= NOSTR
)
499 ttyset
++, stty(fileno(stdin
), &ttybuf
);
501 hp
->h_to
= addto(NOSTR
, readtty("To: ", hp
->h_to
));
502 if (hp
->h_to
!= NOSTR
)
505 if (gflags
& GSUBJECT
&& subjtop
) {
507 if (!ttyset
&& hp
->h_subject
!= NOSTR
)
508 ttyset
++, stty(fileno(stdin
), &ttybuf
);
510 hp
->h_subject
= readtty("Subject: ", hp
->h_subject
);
511 if (hp
->h_subject
!= NOSTR
)
516 if (!ttyset
&& hp
->h_cc
!= NOSTR
)
517 ttyset
++, stty(fileno(stdin
), &ttybuf
);
519 hp
->h_cc
= addto(NOSTR
, readtty("Cc: ", hp
->h_cc
));
520 if (hp
->h_cc
!= NOSTR
)
525 if (!ttyset
&& hp
->h_bcc
!= NOSTR
)
526 ttyset
++, stty(fileno(stdin
), &ttybuf
);
528 hp
->h_bcc
= addto(NOSTR
, readtty("Bcc: ", hp
->h_bcc
));
529 if (hp
->h_bcc
!= NOSTR
)
532 if (gflags
& GSUBJECT
&& !subjtop
) {
534 if (!ttyset
&& hp
->h_subject
!= NOSTR
)
535 ttyset
++, stty(fileno(stdin
), &ttybuf
);
537 hp
->h_subject
= readtty("Subject: ", hp
->h_subject
);
538 if (hp
->h_subject
!= NOSTR
)
542 sigset(SIGCONT
, savecont
);
545 ttybuf
.sg_erase
= c_erase
;
546 ttybuf
.sg_kill
= c_kill
;
548 stty(fileno(stdin
), &ttybuf
);
549 for (s
= SIGINT
; s
<= SIGQUIT
; s
++)
550 sigset(s
, savesigs
[s
-SIGINT
]);
556 * Read up a header from standard input.
557 * The source string has the preliminary contents to
563 readtty(char pr
[], char src
[])
565 char ch
, canonb
[LINESIZE
];
567 register char *cp
, *cp2
;
571 if (src
!= NOSTR
&& strlen(src
) > LINESIZE
- 2) {
572 printf(gettext("too long to edit\n"));
577 cp
= copy(src
, canonb
);
579 cp
= copy("", canonb
);
580 fputs(canonb
, stdout
);
583 cp
= src
== NOSTR
? "" : src
;
585 if (c
== c_erase
|| c
== c_kill
) {
587 ioctl(0, TIOCSTI
, &ch
);
590 ioctl(0, TIOCSTI
, &ch
);
596 while (cp2
< canonb
+ LINESIZE
)
602 sigset(SIGCONT
, ttycont
);
605 while (cp2
< canonb
+ LINESIZE
) {
607 if (c
== EOF
|| c
== '\n')
613 sigset(SIGCONT
, signull
);
615 if (c
== EOF
&& ferror(stdin
) && hadcont
) {
618 cp
= strlen(canonb
) > 0 ? canonb
: NOSTR
;
620 return(readtty(pr
, cp
));
624 if (cp
== NOSTR
|| *cp
== '\0')
628 return(strlen(canonb
) > 0 ? savestr(canonb
) : NOSTR
);
629 while (*cp
!= '\0') {
634 if (cp2
[-1] == '\\') {
644 if (cp2
[-1] == '\\') {
655 if (equal("", canonb
))
657 return(savestr(canonb
));
662 * Receipt continuation.
674 * Null routine to allow us to hold SIGCONT