Use size-dependant no. of words, with OPEN_MAX as default for fd_set size.
[minix3.git] / commands / yap / getcomm.c
blobe6879d42791791b135855421d05cfb4027325e1b
1 /* Copyright (c) 1985 Ceriel J.H. Jacobs */
3 /*
4 * Command reader, also executes shell escapes
5 */
7 # ifndef lint
8 static char rcsid[] = "$Header$";
9 # endif
11 # define _GETCOMM_
13 # include <ctype.h>
14 # include "in_all.h"
15 # include "term.h"
16 # include "process.h"
17 # include "getcomm.h"
18 # include "commands.h"
19 # include "prompt.h"
20 # include "main.h"
21 # include "output.h"
22 # include "getline.h"
23 # include "machine.h"
24 # include "keys.h"
25 # include "display.h"
26 # include "assert.h"
28 #if USG_OPEN
29 #include <fcntl.h>
30 #endif
31 #if POSIX_OPEN
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #endif
36 char *strcpy(),
37 *getenv();
39 STATIC int killchar();
42 * Read a line from the terminal, doing line editing.
43 * The parameter s contains the prompt for the line.
46 char *
47 readline(s) char *s; {
49 static char buf[80];
50 register char *p = buf;
51 register int ch;
52 register int pos;
54 clrbline();
55 putline(s);
56 pos = strlen(s);
57 while ((ch = getch()) != '\n' && ch != '\r') {
58 if (ch == -1) {
60 * Can only occur because of an interrupted read.
62 ch = erasech;
63 interrupt = 0;
65 if (ch == erasech) {
67 * Erase last char
69 if (p == buf) {
71 * There was none, so return
73 return (char *) 0;
75 pos -= killchar(*--p);
76 if (*p != '\\') continue;
78 if (ch == killch) {
80 * Erase the whole line
82 if (!(p > buf && *(p-1) == '\\')) {
83 while (p > buf) {
84 pos -= killchar(*--p);
86 continue;
88 pos -= killchar(*--p);
90 if (p > &buf[78] || pos >= COLS - 2) {
92 * Line does not fit.
93 * Simply refuse to make it any longer
95 pos -= killchar(*--p);
97 *p++ = ch;
98 if (ch < ' ' || ch >= 0177) {
99 fputch('^');
100 pos++;
101 ch ^= 0100;
103 fputch(ch);
104 pos++;
106 fputch('\r');
107 *p++ = '\0';
108 flush();
109 return buf;
113 * Erase a character from the command line.
116 STATIC int
117 killchar(c) {
119 backspace();
120 putch(' ');
121 backspace();
122 if (c < ' ' || c >= 0177) {
123 (VOID) killchar(' ');
124 return 2;
126 return 1;
130 * Do a shell escape, after expanding '%' and '!'.
133 VOID
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 */
140 # ifdef SIGTSTP
141 VOID (*savetstp)();
142 # endif
143 static char previous[256]; /* previous command */
144 char comm[256]; /* space for command */
145 int piped[2];
147 p2 = comm;
148 *p2++ = esc_char;
149 cnt = 253;
150 while (*p) {
152 * expand command
154 switch(*p++) {
155 case '!':
157 * An unescaped ! expands to the previous
158 * command, but disappears if there is none
160 if (lastc != '\\') {
161 if (*previous) {
162 id = strlen(previous);
163 if ((cnt -= id) <= 0) break;
164 (VOID) strcpy(p2,previous);
165 p2 += id;
168 else {
169 *(p2-1) = '!';
171 continue;
172 case '%':
174 * An unescaped % will expand to the current
175 * filename, but disappears is there is none
177 if (lastc != '\\') {
178 if (nopipe) {
179 id = strlen(currentfile);
180 if ((cnt -= id) <= 0) break;
181 (VOID) strcpy(p2,currentfile);
182 p2 += id;
185 else {
186 *(p2-1) = '%';
188 continue;
189 default:
190 lastc = *(p-1);
191 if (cnt-- <= 0) break;
192 *p2++ = lastc;
193 continue;
195 break;
197 clrbline();
198 *p2 = '\0';
199 if (!stupid) {
201 * Display expanded command
203 cputline(comm);
204 putline("\r\n");
206 flush();
207 (VOID) strcpy(previous,comm + 1);
208 resettty();
209 if (esc_char == '|' && pipe(piped) < 0) {
210 error("Cannot create pipe");
211 return;
213 if ((id = fork()) < 0) {
214 error("Cannot fork");
215 return;
217 if (id == 0) {
219 * Close files, as child might need the file descriptors
221 cls_files();
222 if (esc_char == '|') {
223 close(piped[1]);
224 #if USG_OPEN || POSIX_OPEN
225 close(0);
226 fcntl(piped[0], F_DUPFD, 0);
227 #else
228 dup2(piped[0], 0);
229 #endif
230 close(piped[0]);
232 execl("/bin/sh", "sh", "-c", comm + 1, (char *) 0);
233 exit(1);
235 (VOID) signal(SIGINT,SIG_IGN);
236 (VOID) signal(SIGQUIT,SIG_IGN);
237 # ifdef SIGTSTP
238 if ((savetstp = signal(SIGTSTP,SIG_IGN)) != SIG_IGN) {
239 (VOID) signal(SIGTSTP,SIG_DFL);
241 # endif
242 if (esc_char == '|') {
243 (VOID) close(piped[0]);
244 (VOID) signal(SIGPIPE, SIG_IGN);
245 wrt_fd(piped[1]);
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);
255 # ifdef SIGTSTP
256 (VOID) signal(SIGTSTP, savetstp);
257 # endif
258 inittty();
262 * Get all those commands ...
266 getcomm (plong) long *plong; {
267 int c;
268 long count;
269 char *p;
270 int i;
271 int j;
272 char buf[10];
274 for (;;) {
275 count = 0;
276 give_prompt();
277 while (isdigit((c = getch()))) {
278 count = count * 10 + (c - '0');
280 *plong = count;
281 p = buf;
282 for (;;) {
283 if (c == -1) {
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
290 * we end up here.
291 * Right, we will have to read again.
293 if (interrupt) return 1;
294 break;
296 *p++ = c;
297 *p = 0;
298 if ((i = match(buf, &j, currmap->k_mach)) > 0) {
300 * The key sequence matched. We have a command
302 return j;
304 if (i == 0) return 0;
306 * We have a prefix of a command.
308 assert(i == FSM_ISPREFIX);
309 c = getch();
312 /* NOTREACHED */