1 /* Copyright (c) 1985 Ceriel J.H. Jacobs */
4 * Command reader, also executes shell escapes
8 static char rcsid
[] = "$Header$";
18 # include "commands.h"
32 #include <sys/types.h>
39 STATIC
int killchar();
42 * Read a line from the terminal, doing line editing.
43 * The parameter s contains the prompt for the line.
47 readline(s
) char *s
; {
50 register char *p
= buf
;
57 while ((ch
= getch()) != '\n' && ch
!= '\r') {
60 * Can only occur because of an interrupted read.
71 * There was none, so return
75 pos
-= killchar(*--p
);
76 if (*p
!= '\\') continue;
80 * Erase the whole line
82 if (!(p
> buf
&& *(p
-1) == '\\')) {
84 pos
-= killchar(*--p
);
88 pos
-= killchar(*--p
);
90 if (p
> &buf
[78] || pos
>= COLS
- 2) {
93 * Simply refuse to make it any longer
95 pos
-= killchar(*--p
);
98 if (ch
< ' ' || ch
>= 0177) {
113 * Erase a character from the command line.
122 if (c
< ' ' || c
>= 0177) {
123 (VOID
) killchar(' ');
130 * Do a shell escape, after expanding '%' and '!'.
134 shellescape(p
, esc_char
) register char *p
; {
136 register char *p2
; /* walks through command */
137 register int id
; /* procid of child */
138 register int cnt
; /* prevent array bound errors */
139 register int lastc
= 0; /* will contain the previous char */
143 static char previous
[256]; /* previous command */
144 char comm
[256]; /* space for command */
157 * An unescaped ! expands to the previous
158 * command, but disappears if there is none
162 id
= strlen(previous
);
163 if ((cnt
-= id
) <= 0) break;
164 (VOID
) strcpy(p2
,previous
);
174 * An unescaped % will expand to the current
175 * filename, but disappears is there is none
179 id
= strlen(currentfile
);
180 if ((cnt
-= id
) <= 0) break;
181 (VOID
) strcpy(p2
,currentfile
);
191 if (cnt
-- <= 0) break;
201 * Display expanded command
207 (VOID
) strcpy(previous
,comm
+ 1);
209 if (esc_char
== '|' && pipe(piped
) < 0) {
210 error("Cannot create pipe");
213 if ((id
= fork()) < 0) {
214 error("Cannot fork");
219 * Close files, as child might need the file descriptors
222 if (esc_char
== '|') {
224 #if USG_OPEN || POSIX_OPEN
226 fcntl(piped
[0], F_DUPFD
, 0);
232 execl("/bin/sh", "sh", "-c", comm
+ 1, (char *) 0);
235 (VOID
) signal(SIGINT
,SIG_IGN
);
236 (VOID
) signal(SIGQUIT
,SIG_IGN
);
238 if ((savetstp
= signal(SIGTSTP
,SIG_IGN
)) != SIG_IGN
) {
239 (VOID
) signal(SIGTSTP
,SIG_DFL
);
242 if (esc_char
== '|') {
243 (VOID
) close(piped
[0]);
244 (VOID
) signal(SIGPIPE
, SIG_IGN
);
246 (VOID
) close(piped
[1]);
248 while ((lastc
= wait((int *) 0)) != id
&& lastc
>= 0) {
250 * Wait for child, making sure it is the one we expected ...
253 (VOID
) signal(SIGINT
,catchdel
);
254 (VOID
) signal(SIGQUIT
,quit
);
256 (VOID
) signal(SIGTSTP
, savetstp
);
262 * Get all those commands ...
266 getcomm (plong
) long *plong
; {
277 while (isdigit((c
= getch()))) {
278 count
= count
* 10 + (c
- '0');
285 * This should never happen, but it does,
286 * when the user gives a TSTP signal (^Z) or
287 * an interrupt while the program is trying
288 * to read a character from the terminal.
289 * In this case, the read is interrupted, so
291 * Right, we will have to read again.
293 if (interrupt
) return 1;
298 if ((i
= match(buf
, &j
, currmap
->k_mach
)) > 0) {
300 * The key sequence matched. We have a command
304 if (i
== 0) return 0;
306 * We have a prefix of a command.
308 assert(i
== FSM_ISPREFIX
);