source: trunk/minix/commands/elvis/system.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 8.5 KB
RevLine 
[9]1/* system.c -- UNIX version */
2
3/* Author:
4 * Steve Kirkendall
5 * 14407 SW Teal Blvd. #C
6 * Beaverton, OR 97005
7 * kirkenda@cs.pdx.edu
8 */
9
10
11/* This file contains a new version of the system() function and related stuff.
12 *
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
17 *
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.
21 */
22
23#include "config.h"
24#include "vi.h"
25extern char **environ;
26
27#if ANY_UNIX
28
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.
31 */
32int system(cmd)
33 char *cmd; /* a command to run */
34{
35 int pid; /* process ID of child */
36 int died;
37 int status; /* exit status of the command */
38
39
40 signal(SIGINT, SIG_IGN);
41 pid = fork();
42 switch (pid)
43 {
44 case -1: /* error */
45 msg("fork() failed");
46 status = -1;
47 break;
48
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++)
52 {
53 }
54
55 signal(SIGINT, SIG_DFL);
56 if (cmd == o_shell)
57 {
58 execle(o_shell, o_shell, (char *)0, environ);
59 }
60 else
61 {
62 execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
63 }
64 msg("execle(\"%s\", ...) failed", o_shell);
65 exit(1); /* if we get here, the exec failed */
66
67 default: /* parent */
68 do
69 {
70 died = wait(&status);
71 } while (died >= 0 && died != pid);
72 if (died < 0)
73 {
74 status = -1;
75 }
76#if __GNUC__ || _ANSI
77 signal(SIGINT, (void (*)()) trapint);
78#else
79 signal(SIGINT, trapint);
80#endif
81 }
82
83 return status;
84}
85
86/* This private function opens a pipe from a filter. It is similar to the
87 * system() function above, and to popen(cmd, "r").
88 */
89int rpipe(cmd, in)
90 char *cmd; /* the filter command to use */
91 int in; /* the fd to use for stdin */
92{
93 int r0w1[2];/* the pipe fd's */
94
95 /* make the pipe */
96 if (pipe(r0w1) < 0)
97 {
98 return -1; /* pipe failed */
99 }
100
101 /* The parent process (elvis) ignores signals while the filter runs.
102 * The child (the filter program) will reset this, so that it can
103 * catch the signal.
104 */
105 signal(SIGINT, SIG_IGN);
106
107 switch (fork())
108 {
109 case -1: /* error */
110 return -1;
111
112 case 0: /* child */
113 /* close the "read" end of the pipe */
114 close(r0w1[0]);
115
116 /* redirect stdout to go to the "write" end of the pipe */
117 close(1);
118 dup(r0w1[1]);
119 close(2);
120 dup(r0w1[1]);
121 close(r0w1[1]);
122
123 /* redirect stdin */
124 if (in != 0)
125 {
126 close(0);
127 dup(in);
128 close(in);
129 }
130
131 /* the filter should accept SIGINT signals */
132 signal(SIGINT, SIG_DFL);
133
134 /* exec the shell to run the command */
135 execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
136 exit(1); /* if we get here, exec failed */
137
138 default: /* parent */
139 /* close the "write" end of the pipe */
140 close(r0w1[1]);
141
142 return r0w1[0];
143 }
144}
145
146#endif /* non-DOS */
147
148#if OSK
149
150/* This private function opens a pipe from a filter. It is similar to the
151 * system() function above, and to popen(cmd, "r").
152 */
153int rpipe(cmd, in)
154 char *cmd; /* the filter command to use */
155 int in; /* the fd to use for stdin */
156{
157 return osk_popen(cmd, "r", in, 0);
158}
159#endif
160
161#if ANY_UNIX || OSK
162
163/* This function closes the pipe opened by rpipe(), and returns 0 for success */
164int rpclose(fd)
165 int fd;
166{
167 int status;
168
169 close(fd);
170 wait(&status);
171#if __GNUC__ || _ANSI
172 signal(SIGINT, (void (*)()) trapint);
173#else
174 signal(SIGINT, trapint);
175#endif
176 return status;
177}
178
179#endif /* non-DOS */
180
181/* This function expands wildcards in a filename or filenames. It does this
182 * by running the "echo" command on the filenames via the shell; it is assumed
183 * that the shell will expand the names for you. If for any reason it can't
184 * run echo, then it returns the names unmodified.
185 */
186
187#if MSDOS || TOS
188#define PROG "wildcard "
189#define PROGLEN 9
190#include <string.h>
191#else
192#define PROG "echo "
193#define PROGLEN 5
194#endif
195
196#if !AMIGA
197char *wildcard(names)
198 char *names;
199{
200
201# if VMS
202/*
203 We could use expand() [vmswild.c], but what's the point on VMS?
204 Anyway, echo is the wrong thing to do, it takes too long to build
205 a subprocess on VMS and any "echo" program would have to be supplied
206 by elvis. More importantly, many VMS utilities expand names
207 themselves (the shell doesn't do any expansion) so the concept is
208 non-native. jdc
209*/
210 return names;
211# else
212
213 int i, j, fd;
214 REG char *s, *d;
215
216
217 /* build the echo command */
218 if (names != tmpblk.c)
219 {
220 /* the names aren't in tmpblk.c, so we can do it the easy way */
221 strcpy(tmpblk.c, PROG);
222 strcat(tmpblk.c, names);
223 }
224 else
225 {
226 /* the names are already in tmpblk.c, so shift them to make
227 * room for the word "echo "
228 */
229 for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; )
230 {
231 *--d = *--s;
232 }
233 strncpy(names, PROG, PROGLEN);
234 }
235
236 /* run the command & read the resulting names */
237 fd = rpipe(tmpblk.c, 0);
238 if (fd < 0) return names;
239 i = 0;
240 do
241 {
242 j = tread(fd, tmpblk.c + i, BLKSIZE - i);
243 i += j;
244 } while (j > 0);
245
246 /* successful? */
247 if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0)
248 {
249 tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */
250 return tmpblk.c;
251 }
252 else
253 {
254 return names;
255 }
256# endif
257}
258#endif
259
260/* This function runs a range of lines through a filter program, and replaces
261 * the original text with the filtered version. As a special case, if "to"
262 * is MARK_UNSET, then it runs the filter program with stdin coming from
263 * /dev/null, and inserts any output lines.
264 */
265int filter(from, to, cmd, back)
266 MARK from, to; /* the range of lines to filter */
267 char *cmd; /* the filter command */
268 int back; /* boolean: will we read lines back? */
269{
270 int scratch; /* fd of the scratch file */
271 int fd; /* fd of the pipe from the filter */
272 char scrout[50]; /* name of the scratch out file */
273 MARK new; /* place where new text should go */
274 long sent, rcvd; /* number of lines sent/received */
275 int i, j;
276
277 /* write the lines (if specified) to a temp file */
278 if (to)
279 {
280 /* we have lines */
281#if MSDOS || TOS
282 strcpy(scrout, o_directory);
283 if ((i=strlen(scrout)) && !strchr("\\/:", scrout[i-1]))
284 scrout[i++]=SLASH;
285 strcpy(scrout+i, SCRATCHOUT+3);
286#else
287 sprintf(scrout, SCRATCHOUT, o_directory);
288#endif
289 mktemp(scrout);
290 cmd_write(from, to, CMD_BANG, FALSE, scrout);
291 sent = markline(to) - markline(from) + 1L;
292
293 /* use those lines as stdin */
294 scratch = open(scrout, O_RDONLY);
295 if (scratch < 0)
296 {
297 unlink(scrout);
298 return -1;
299 }
300 }
301 else
302 {
303 scratch = 0;
304 sent = 0L;
305 }
306
307 /* start the filter program */
308#if VMS
309 /*
310 VMS doesn't know a thing about file descriptor 0. The rpipe
311 concept is non-portable. Hence we need a file name argument.
312 */
313 fd = rpipe(cmd, scratch, scrout);
314#else
315 fd = rpipe(cmd, scratch);
316#endif
317 if (fd < 0)
318 {
319 if (to)
320 {
321 close(scratch);
322 unlink(scrout);
323 }
324 return -1;
325 }
326
327 if (back)
328 {
329 ChangeText
330 {
331 /* adjust MARKs for whole lines, and set "new" */
332 from &= ~(BLKSIZE - 1);
333 if (to)
334 {
335 to &= ~(BLKSIZE - 1);
336 to += BLKSIZE;
337 new = to;
338 }
339 else
340 {
341 new = from + BLKSIZE;
342 }
343
344#if VMS
345/* Reading from a VMS mailbox (pipe) is record oriented... */
346# define tread vms_pread
347#endif
348
349 /* repeatedly read in new text and add it */
350 rcvd = 0L;
351 while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
352 {
353 tmpblk.c[i] = '\0';
354 add(new, tmpblk.c);
355#if VMS
356 /* What! An advantage to record oriented reads? */
357 new += (i - 1);
358 new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
359 rcvd++;
360#else
361 for (i = 0; tmpblk.c[i]; i++)
362 {
363 if (tmpblk.c[i] == '\n')
364 {
365 new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
366 rcvd++;
367 }
368 else
369 {
370 new++;
371 }
372 }
373#endif
374 }
375 }
376
377 /* delete old text, if any */
378 if (to)
379 {
380 cut(from, to);
381 delete(from, to);
382 }
383 }
384 else
385 {
386 /* read the command's output, and copy it to the screen */
387 while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
388 {
389 for (j = 0; j < i; j++)
390 {
391 addch(tmpblk.c[j]);
392 }
393 }
394 rcvd = 0;
395 }
396
397 /* Reporting... */
398 if (sent >= *o_report || rcvd >= *o_report)
399 {
400 if (sent > 0L && rcvd > 0L)
401 {
402 msg("%ld lines out, %ld lines back", sent, rcvd);
403 }
404 else if (sent > 0)
405 {
406 msg("%ld lines written to filter", sent);
407 }
408 else
409 {
410 msg("%ld lines read from filter", rcvd);
411 }
412 }
413 rptlines = 0L;
414
415 /* cleanup */
416 rpclose(fd);
417 if (to)
418 {
419 close(scratch);
420 unlink(scrout);
421 }
422 return 0;
423}
Note: See TracBrowser for help on using the repository browser.