1 /* system.c -- UNIX version */
5 * 14407 SW Teal Blvd. #C
11 /* This file contains a new version of the system() function and related stuff.
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.
25 extern char **environ
;
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.
33 char *cmd
; /* a command to run */
35 int pid
; /* process ID of child */
37 int status
; /* exit status of the command */
40 signal(SIGINT
, SIG_IGN
);
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
);
58 execle(o_shell
, o_shell
, (char *)0, environ
);
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 */
71 } while (died
>= 0 && died
!= pid
);
76 signal(SIGINT
, (void (*)()) trapint
);
82 /* This private function opens a pipe from a filter. It is similar to the
83 * system() function above, and to popen(cmd, "r").
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 */
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
101 signal(SIGINT
, SIG_IGN
);
109 /* close the "read" end of the pipe */
112 /* redirect stdout to go to the "write" end of the pipe */
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 */
146 /* This private function opens a pipe from a filter. It is similar to the
147 * system() function above, and to popen(cmd, "r").
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);
159 /* This function closes the pipe opened by rpipe(), and returns 0 for success */
167 signal(SIGINT
, (void (*)()) trapint
);
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.
180 #define PROG "wildcard "
189 char *wildcard(names
)
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
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
);
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
; )
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
;
234 j
= tread(fd
, tmpblk
.c
+ i
, BLKSIZE
- i
);
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 */
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 */
269 /* write the lines (if specified) to a temp file */
274 strcpy(scrout
, o_directory
);
275 if ((i
=strlen(scrout
)) && !strchr("\\/:", scrout
[i
-1]))
277 strcpy(scrout
+i
, SCRATCHOUT
+3);
279 sprintf(scrout
, SCRATCHOUT
, o_directory
);
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
);
299 /* start the filter program */
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
);
307 fd
= rpipe(cmd
, scratch
);
323 /* adjust MARKs for whole lines, and set "new" */
324 from
&= ~(BLKSIZE
- 1);
327 to
&= ~(BLKSIZE
- 1);
333 new = from
+ BLKSIZE
;
337 /* Reading from a VMS mailbox (pipe) is record oriented... */
338 # define tread vms_pread
341 /* repeatedly read in new text and add it */
343 while ((i
= tread(fd
, tmpblk
.c
, BLKSIZE
- 1)) > 0)
348 /* What! An advantage to record oriented reads? */
350 new = (new & ~(BLKSIZE
- 1)) + BLKSIZE
;
353 for (i
= 0; tmpblk
.c
[i
]; i
++)
355 if (tmpblk
.c
[i
] == '\n')
357 new = (new & ~(BLKSIZE
- 1)) + BLKSIZE
;
369 /* delete old text, if any */
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
++)
390 if (sent
>= *o_report
|| rcvd
>= *o_report
)
392 if (sent
> 0L && rcvd
> 0L)
394 msg("%ld lines out, %ld lines back", sent
, rcvd
);
398 msg("%ld lines written to filter", sent
);
402 msg("%ld lines read from filter", rcvd
);