release.sh: restore -jJAILDIR option
[minix.git] / commands / elvis / system.c
blobe73bc5a922f3664d77982c3564ea4e8078eea4d7
1 /* system.c -- UNIX version */
3 /* Author:
4 * Steve Kirkendall
5 * 14407 SW Teal Blvd. #C
6 * Beaverton, OR 97005
7 * kirkenda@cs.pdx.edu
8 */
11 /* This file contains a new version of the system() function and related stuff.
13 * Entry points are:
14 * system(cmd) - run a single shell command
15 * wildcard(names) - expand wildcard characters in filanames
16 * filter(m,n,cmd,back) - run text lines through a filter program
18 * This is probably the single least portable file in the program. The code
19 * shown here should work correctly if it links at all; it will work on UNIX
20 * and any O.S./Compiler combination which adheres to UNIX forking conventions.
23 #include "config.h"
24 #include "vi.h"
25 extern char **environ;
27 #if ANY_UNIX
29 /* This is a new version of the system() function. The only difference
30 * between this one and the library one is: this one uses the o_shell option.
32 int system(cmd)
33 char *cmd; /* a command to run */
35 int pid; /* process ID of child */
36 int died;
37 int status; /* exit status of the command */
40 signal(SIGINT, SIG_IGN);
41 pid = fork();
42 switch (pid)
44 case -1: /* error */
45 msg("fork() failed");
46 status = -1;
47 break;
49 case 0: /* child */
50 /* for the child, close all files except stdin/out/err */
51 for (status = 3; status < 60 && (close(status), errno != EINVAL); status++)
55 signal(SIGINT, SIG_DFL);
56 if (cmd == o_shell)
58 execle(o_shell, o_shell, (char *)0, environ);
60 else
62 execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
64 msg("execle(\"%s\", ...) failed", o_shell);
65 exit(1); /* if we get here, the exec failed */
67 default: /* parent */
70 died = wait(&status);
71 } while (died >= 0 && died != pid);
72 if (died < 0)
74 status = -1;
76 signal(SIGINT, (void (*)()) trapint);
79 return status;
82 /* This private function opens a pipe from a filter. It is similar to the
83 * system() function above, and to popen(cmd, "r").
85 int rpipe(cmd, in)
86 char *cmd; /* the filter command to use */
87 int in; /* the fd to use for stdin */
89 int r0w1[2];/* the pipe fd's */
91 /* make the pipe */
92 if (pipe(r0w1) < 0)
94 return -1; /* pipe failed */
97 /* The parent process (elvis) ignores signals while the filter runs.
98 * The child (the filter program) will reset this, so that it can
99 * catch the signal.
101 signal(SIGINT, SIG_IGN);
103 switch (fork())
105 case -1: /* error */
106 return -1;
108 case 0: /* child */
109 /* close the "read" end of the pipe */
110 close(r0w1[0]);
112 /* redirect stdout to go to the "write" end of the pipe */
113 close(1);
114 dup(r0w1[1]);
115 close(2);
116 dup(r0w1[1]);
117 close(r0w1[1]);
119 /* redirect stdin */
120 if (in != 0)
122 close(0);
123 dup(in);
124 close(in);
127 /* the filter should accept SIGINT signals */
128 signal(SIGINT, SIG_DFL);
130 /* exec the shell to run the command */
131 execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
132 exit(1); /* if we get here, exec failed */
134 default: /* parent */
135 /* close the "write" end of the pipe */
136 close(r0w1[1]);
138 return r0w1[0];
142 #endif /* non-DOS */
144 #if OSK
146 /* This private function opens a pipe from a filter. It is similar to the
147 * system() function above, and to popen(cmd, "r").
149 int rpipe(cmd, in)
150 char *cmd; /* the filter command to use */
151 int in; /* the fd to use for stdin */
153 return osk_popen(cmd, "r", in, 0);
155 #endif
157 #if ANY_UNIX || OSK
159 /* This function closes the pipe opened by rpipe(), and returns 0 for success */
160 int rpclose(fd)
161 int fd;
163 int status;
165 close(fd);
166 wait(&status);
167 signal(SIGINT, (void (*)()) trapint);
168 return status;
171 #endif /* non-DOS */
173 /* This function expands wildcards in a filename or filenames. It does this
174 * by running the "echo" command on the filenames via the shell; it is assumed
175 * that the shell will expand the names for you. If for any reason it can't
176 * run echo, then it returns the names unmodified.
179 #if MSDOS || TOS
180 #define PROG "wildcard "
181 #define PROGLEN 9
182 #include <string.h>
183 #else
184 #define PROG "echo "
185 #define PROGLEN 5
186 #endif
188 #if !AMIGA
189 char *wildcard(names)
190 char *names;
193 # if VMS
195 We could use expand() [vmswild.c], but what's the point on VMS?
196 Anyway, echo is the wrong thing to do, it takes too long to build
197 a subprocess on VMS and any "echo" program would have to be supplied
198 by elvis. More importantly, many VMS utilities expand names
199 themselves (the shell doesn't do any expansion) so the concept is
200 non-native. jdc
202 return names;
203 # else
205 int i, j, fd;
206 REG char *s, *d;
209 /* build the echo command */
210 if (names != tmpblk.c)
212 /* the names aren't in tmpblk.c, so we can do it the easy way */
213 strcpy(tmpblk.c, PROG);
214 strcat(tmpblk.c, names);
216 else
218 /* the names are already in tmpblk.c, so shift them to make
219 * room for the word "echo "
221 for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; )
223 *--d = *--s;
225 strncpy(names, PROG, PROGLEN);
228 /* run the command & read the resulting names */
229 fd = rpipe(tmpblk.c, 0);
230 if (fd < 0) return names;
231 i = 0;
234 j = tread(fd, tmpblk.c + i, BLKSIZE - i);
235 i += j;
236 } while (j > 0);
238 /* successful? */
239 if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0)
241 tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */
242 return tmpblk.c;
244 else
246 return names;
248 # endif
250 #endif
252 /* This function runs a range of lines through a filter program, and replaces
253 * the original text with the filtered version. As a special case, if "to"
254 * is MARK_UNSET, then it runs the filter program with stdin coming from
255 * /dev/null, and inserts any output lines.
257 int filter(from, to, cmd, back)
258 MARK from, to; /* the range of lines to filter */
259 char *cmd; /* the filter command */
260 int back; /* boolean: will we read lines back? */
262 int scratch; /* fd of the scratch file */
263 int fd; /* fd of the pipe from the filter */
264 char scrout[50]; /* name of the scratch out file */
265 MARK new; /* place where new text should go */
266 long sent, rcvd; /* number of lines sent/received */
267 int i, j;
269 /* write the lines (if specified) to a temp file */
270 if (to)
272 /* we have lines */
273 #if MSDOS || TOS
274 strcpy(scrout, o_directory);
275 if ((i=strlen(scrout)) && !strchr("\\/:", scrout[i-1]))
276 scrout[i++]=SLASH;
277 strcpy(scrout+i, SCRATCHOUT+3);
278 #else
279 sprintf(scrout, SCRATCHOUT, o_directory);
280 #endif
281 mktemp(scrout);
282 cmd_write(from, to, CMD_BANG, FALSE, scrout);
283 sent = markline(to) - markline(from) + 1L;
285 /* use those lines as stdin */
286 scratch = open(scrout, O_RDONLY);
287 if (scratch < 0)
289 unlink(scrout);
290 return -1;
293 else
295 scratch = 0;
296 sent = 0L;
299 /* start the filter program */
300 #if VMS
302 VMS doesn't know a thing about file descriptor 0. The rpipe
303 concept is non-portable. Hence we need a file name argument.
305 fd = rpipe(cmd, scratch, scrout);
306 #else
307 fd = rpipe(cmd, scratch);
308 #endif
309 if (fd < 0)
311 if (to)
313 close(scratch);
314 unlink(scrout);
316 return -1;
319 if (back)
321 ChangeText
323 /* adjust MARKs for whole lines, and set "new" */
324 from &= ~(BLKSIZE - 1);
325 if (to)
327 to &= ~(BLKSIZE - 1);
328 to += BLKSIZE;
329 new = to;
331 else
333 new = from + BLKSIZE;
336 #if VMS
337 /* Reading from a VMS mailbox (pipe) is record oriented... */
338 # define tread vms_pread
339 #endif
341 /* repeatedly read in new text and add it */
342 rcvd = 0L;
343 while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
345 tmpblk.c[i] = '\0';
346 add(new, tmpblk.c);
347 #if VMS
348 /* What! An advantage to record oriented reads? */
349 new += (i - 1);
350 new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
351 rcvd++;
352 #else
353 for (i = 0; tmpblk.c[i]; i++)
355 if (tmpblk.c[i] == '\n')
357 new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
358 rcvd++;
360 else
362 new++;
365 #endif
369 /* delete old text, if any */
370 if (to)
372 cut(from, to);
373 delete(from, to);
376 else
378 /* read the command's output, and copy it to the screen */
379 while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
381 for (j = 0; j < i; j++)
383 addch(tmpblk.c[j]);
386 rcvd = 0;
389 /* Reporting... */
390 if (sent >= *o_report || rcvd >= *o_report)
392 if (sent > 0L && rcvd > 0L)
394 msg("%ld lines out, %ld lines back", sent, rcvd);
396 else if (sent > 0)
398 msg("%ld lines written to filter", sent);
400 else
402 msg("%ld lines read from filter", rcvd);
405 rptlines = 0L;
407 /* cleanup */
408 rpclose(fd);
409 if (to)
411 close(scratch);
412 unlink(scrout);
414 return 0;