|
|
1.1 root 1: /* system.c -- UNIX version */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 16820 SW Tallac Way
6: * Beaverton, OR 97006
7: * [email protected], or ...uunet!tektronix!psueea!jove!kirkenda
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) - 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"
25: #include <signal.h>
26: extern char **environ;
27:
28: #if ANY_UNIX
29:
30: /* This is a new version of the system() function. The only difference
31: * between this one and the library one is: this one uses the o_shell option.
32: */
33: int system(cmd)
34: char *cmd; /* a command to run */
35: {
36: int status; /* exit status of the command */
37:
38: /* warn the user if the file hasn't been saved yet */
39: if (*o_warn && tstflag(file, MODIFIED))
40: {
41: if (mode == MODE_VI)
42: {
43: mode = MODE_COLON;
44: }
45: msg("Warning: \"%s\" has been modified but not yet saved", origname);
46: }
47:
48: signal(SIGINT, SIG_IGN);
49: switch (fork())
50: {
51: case -1: /* error */
52: msg("fork() failed");
53: status = -1;
54: break;
55:
56: case 0: /* child */
57: /* for the child, close all files except stdin/out/err */
58: for (status = 3; status < 60 && (close(status), errno != EINVAL); status++)
59: {
60: }
61:
62: signal(SIGINT, SIG_DFL);
63: if (cmd == o_shell)
64: {
65: execle(o_shell, o_shell, (char *)0, environ);
66: }
67: else
68: {
69: execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
70: }
71: msg("execle(\"%s\", ...) failed", o_shell);
72: exit(1); /* if we get here, the exec failed */
73:
74: default: /* parent */
75: wait(&status);
76: signal(SIGINT, trapint);
77: }
78:
79: return status;
80: }
81:
82: /* This private function opens a pipe from a filter. It is similar to the
83: * system() function above, and to popen(cmd, "r").
84: */
85: static int rpipe(cmd, in)
86: char *cmd; /* the filter command to use */
87: int in; /* the fd to use for stdin */
88: {
89: int r0w1[2];/* the pipe fd's */
90:
91: /* make the pipe */
92: if (pipe(r0w1) < 0)
93: {
94: return -1; /* pipe failed */
95: }
96:
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.
100: */
101: signal(SIGINT, SIG_IGN);
102:
103: switch (fork())
104: {
105: case -1: /* error */
106: return -1;
107:
108: case 0: /* child */
109: /* close the "read" end of the pipe */
110: close(r0w1[0]);
111:
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]);
118:
119: /* redirect stdin */
120: if (in != 0)
121: {
122: close(0);
123: dup(in);
124: close(in);
125: }
126:
127: /* the filter should accept SIGINT signals */
128: signal(SIGINT, SIG_DFL);
129:
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 */
133:
134: default: /* parent */
135: /* close the "write" end of the pipe */
136: close(r0w1[1]);
137:
138: return r0w1[0];
139: }
140: }
141:
142: #endif /* non-DOS */
143:
144: #if OSK
145:
146: /* This private function opens a pipe from a filter. It is similar to the
147: * system() function above, and to popen(cmd, "r").
148: */
149: static int rpipe(cmd, in)
150: char *cmd; /* the filter command to use */
151: int in; /* the fd to use for stdin */
152: {
153:
154: char **argblk;
155: char *p, *buffer, *command;
156: int stdinp, stdoutp;
157: unsigned addstack = 0;
158: int words, len, loop = 1;
159: int fp, pipe_pid;
160: extern int os9forkc();
161: extern char *index();
162:
163: command = cmd;
164: words = 0;
165: if ((buffer = (char*) malloc(strlen(cmd))) == (char*) 0)
166: return 0;
167:
168: do {
169: if (!(p = index(command, ' '))) {
170: loop--;
171: len = strlen(command);
172: }
173: else
174: len = p - command;
175: words++;
176: while (command[len] && command[len] == ' ')
177: len++;
178: if (!command[len])
179: break;
180: command = command + len;
181: }
182: while (loop);
183: if ((argblk = (char **)malloc((words+1) * sizeof(char*))) == (char **)0)
184: return 0;
185: command = cmd;
186: words = 0;
187: do {
188: if (!(p = index(command, ' '))) {
189: loop--;
190: len = strlen(command);
191: }
192: else
193: len = p - command;
194: strncpy(buffer, command, len);
195: argblk[words++] = buffer;
196: buffer += len;
197: *buffer++ = '\0';
198: while (command[len] && command[len] == ' ')
199: len++;
200: if (!command[len])
201: break;
202: command = command + len;
203: } while (loop);
204: if (argblk[words - 1][0] == '#')
205: addstack = 1024 * atoi(&argblk[--words][1]);
206: argblk[words] = 0;
207:
208: stdoutp = dup(1);
209: close(1); /* close stdout */
210: if ((fp = open("/pipe",S_IREAD)) < 0) {
211: dup(stdoutp);
212: close(stdoutp);
213: return 0;
214: }
215: if (in != 0) {
216: stdinp = dup(0);
217: close(0);
218: dup(in);
219: close(in);
220: }
221: pipe_pid = os9exec(os9forkc,argblk[0],argblk,environ,addstack,0,3);
222: if (pipe_pid == -1) {
223: fclose(fp);
224: dup(stdoutp);
225: close(stdoutp);
226: if (in != 0) {
227: close(0);
228: dup(stdinp);
229: }
230: return 0;
231: }
232: fp = (short)dup(1); /* save pipe */
233: close(1); /* get rid of the pipe */
234: dup(stdoutp); /* restore old stdout */
235: close(stdoutp); /* close path to stdout copy */
236: if (in != 0) {
237: close(0);
238: dup(stdinp);
239: }
240: return fp;
241: }
242: #endif
243:
244: #if ANY_UNIX || OSK
245:
246: /* This function closes the pipe opened by rpipe(), and returns 0 for success */
247: static int rpclose(fd)
248: int fd;
249: {
250: int status;
251:
252: close(fd);
253: wait(&status);
254: signal(SIGINT, trapint);
255: return status;
256: }
257:
258: #endif /* non-DOS */
259:
260: /* This function expands wildcards in a filename or filenames. It does this
261: * by running the "echo" command on the filenames via the shell; it is assumed
262: * that the shell will expand the names for you. If for any reason it can't
263: * run echo, then it returns the names unmodified.
264: */
265:
266: #if MSDOS || TOS
267: #define PROG "wildcard "
268: #define PROGLEN 9
269: #include <string.h>
270: #else
271: #define PROG "echo "
272: #define PROGLEN 5
273: #endif
274:
275: char *wildcard(names)
276: char *names;
277: {
278: int i, j, fd;
279: REG char *s, *d;
280:
281:
282: /* build the echo command */
283: if (names != tmpblk.c)
284: {
285: /* the names aren't in tmpblk.c, so we can do it the easy way */
286: strcpy(tmpblk.c, PROG);
287: strcat(tmpblk.c, names);
288: }
289: else
290: {
291: /* the names are already in tmpblk.c, so shift them to make
292: * room for the word "echo "
293: */
294: for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; )
295: {
296: *--d = *--s;
297: }
298: strncpy(names, PROG, PROGLEN);
299: }
300:
301: /* run the command & read the resulting names */
302: fd = rpipe(tmpblk.c, 0);
303: if (fd < 0) return names;
304: i = 0;
305: do
306: {
307: j = tread(fd, tmpblk.c + i, BLKSIZE - i);
308: i += j;
309: } while (j > 0);
310:
311: /* successful? */
312: if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0)
313: {
314: tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */
315: return tmpblk.c;
316: }
317: else
318: {
319: return names;
320: }
321: }
322:
323: /* This function runs a range of lines through a filter program, and replaces
324: * the original text with the filtered version. As a special case, if "to"
325: * is MARK_UNSET, then it runs the filter program with stdin coming from
326: * /dev/null, and inserts any output lines.
327: */
328: int filter(from, to, cmd)
329: MARK from, to; /* the range of lines to filter */
330: char *cmd; /* the filter command */
331: {
332: int scratch; /* fd of the scratch file */
333: int fd; /* fd of the pipe from the filter */
334: char scrout[50]; /* name of the scratch out file */
335: MARK new; /* place where new text should go */
336: int i;
337:
338: /* write the lines (if specified) to a temp file */
339: if (to)
340: {
341: /* we have lines */
342: #if MSDOS || TOS
343: strcpy(scrout, o_directory);
344: if ((i=strlen(scrout)) && strchr("\\/:", scrout[i-1]))
345: scrout[i++]=SLASH;
346: strcpy(scrout+i, SCRATCHOUT+3);
347: #else
348: sprintf(scrout, SCRATCHOUT, o_directory);
349: #endif
350: mktemp(scrout);
351: cmd_write(from, to, CMD_BANG, 0, scrout);
352:
353: /* use those lines as stdin */
354: scratch = open(scrout, O_RDONLY);
355: if (scratch < 0)
356: {
357: unlink(scrout);
358: return -1;
359: }
360: }
361: else
362: {
363: scratch = 0;
364: }
365:
366: /* start the filter program */
367: fd = rpipe(cmd, scratch);
368: if (fd < 0)
369: {
370: if (to)
371: {
372: close(scratch);
373: unlink(scrout);
374: }
375: return -1;
376: }
377:
378: ChangeText
379: {
380: /* adjust MARKs for whole lines, and set "new" */
381: from &= ~(BLKSIZE - 1);
382: if (to)
383: {
384: to &= ~(BLKSIZE - 1);
385: to += BLKSIZE;
386: new = to;
387: }
388: else
389: {
390: new = from + BLKSIZE;
391: }
392:
393: /* repeatedly read in new text and add it */
394: while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
395: {
396: tmpblk.c[i] = '\0';
397: add(new, tmpblk.c);
398: for (i = 0; tmpblk.c[i]; i++)
399: {
400: if (tmpblk.c[i] == '\n')
401: {
402: new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
403: }
404: else
405: {
406: new++;
407: }
408: }
409: }
410: }
411:
412: /* delete old text, if any */
413: if (to)
414: {
415: delete(from, to);
416: }
417:
418: /* Reporting... */
419: rptlabel = "more";
420: if (rptlines < 0)
421: {
422: rptlines = -rptlines;
423: rptlabel = "less";
424: }
425:
426: /* cleanup */
427: rpclose(fd);
428: if (to)
429: {
430: close(scratch);
431: unlink(scrout);
432: }
433: return 0;
434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.