2 * $Id: argproc.c 443 2006-05-30 04:37:13Z darren $
4 * Copyright (c) 1989, Mark Pizzolato (mark@infopiz.uucp)
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * Provided by Stephen P. Wall <swall@redcom.com>
10 * Extracted from the VMS port of GNU patch-2.1.
12 * This module provides redirection support for the VAX DECC port of
16 * @(#)argproc.c 1.0 89/02/01 Mark Pizzolato (mark@infopiz.uucp)
20 char argproc_version
[] = "@(#)argproc.c VMS uucp Version infopiz-1.0";
28 #include <lib$routines.h>
33 #include <syidef.h> /* System Information Definitions */
35 #define EXIT_OK 1 /* image exit code */
36 #define EXIT_ERR 0x10000000 /* image exit code */
39 * getredirection() is intended to aid in porting C programs
40 * to VMS (Vax-11 C) which does not support '>' and '<'
41 * I/O redirection, along with a command line pipe mechanism
42 * using the '|' AND background command execution '&'.
43 * The piping mechanism will probably work with almost any 'filter' type
44 * of program. With suitable modification, it may useful for other
45 * portability problems as well.
47 * Author: Mark Pizzolato mark@infopiz.UUCP
48 * Mods: Steve Wall Don't return a full path unless the
49 * original filename included a path.
53 struct list_item
*next
;
57 static expand_wild_cards ();
58 static char *pipe_and_fork ();
61 getredirection (ac
, av
)
65 * Process vms redirection arg's. Exit if any error is seen.
66 * If getredirection() processes an argument, it is erased
67 * from the vector. getredirection () returns a new argc and argv value.
68 * In the event that a background command is requested (by a trailing "&"),
69 * this routine creates a background subprocess, and simply exits the program.
71 * Warning: do not try to simplify the code for vms. The code
72 * presupposes that getredirection() is called before any data is
73 * read from stdin or written to stdout.
75 * Normal usage is as follows:
81 * getredirection (&argc, &argv);
85 int argc
= *ac
; /* Argument Count */
86 char **argv
= *av
; /* Argument Vector */
87 char *ap
; /* Argument pointer */
88 int j
; /* argv [] index */
89 extern int errno
; /* Last vms i/o error */
90 int item_count
= 0; /* Count of Items in List */
91 struct list_item
*list_head
= 0; /* First Item in List */
92 struct list_item
*list_tail
; /* Last Item in List */
93 char *in
= NULL
; /* Input File Name */
94 char *out
= NULL
; /* Output File Name */
95 char *outmode
= "w"; /* Mode to Open Output File */
96 int cmargc
= 0; /* Piped Command Arg Count */
97 char **cmargv
= NULL
;/* Piped Command Arg Vector */
100 * First handle the case where the last thing on the line ends with
101 * a '&'. This indicates the desire for the command to be run in a
102 * subprocess, so we satisfy that desire.
105 extern background_process ();
107 if (0 == strcmp ("&", ap
))
108 exit (background_process (--argc
, argv
));
109 if ('&' == ap
[strlen (ap
)-1])
111 ap
[strlen (ap
)-1] = '\0';
112 exit (background_process (argc
, argv
));
116 * Now we handle the general redirection cases that involve '>', '>>',
117 * '<', and pipes '|'.
119 for (j
= 0; j
< argc
; ++j
)
121 if (0 == strcmp ("<", argv
[j
]))
126 perror ("No input file");
132 if ('<' == *(ap
= argv
[j
]))
137 if (0 == strcmp (">", ap
))
142 perror ("No output file");
162 if (0 == strcmp ("|", argv
[j
]))
167 perror ("No command to Pipe to");
170 cmargc
= argc
- (j
+1);
171 cmargv
= &argv
[j
+1];
175 if ('|' == *(ap
= argv
[j
]))
183 expand_wild_cards (ap
, &list_head
, &list_tail
, &item_count
);
186 * Allocate and fill in the new argument vector, Some Unix's terminate
187 * the list with an extra null pointer.
189 argv
= *av
= calloc (item_count
+1, sizeof (char *));
190 for (j
= 0; j
< item_count
; ++j
, list_head
= list_head
->next
)
191 argv
[j
] = list_head
->value
;
200 perror ("Invalid '|' and '>' specified");
203 strcpy (subcmd
, cmargv
[0]);
204 for (j
= 1; j
< cmargc
; ++j
)
206 strcat (subcmd
, " \"");
207 strcat (subcmd
, cmargv
[j
]);
208 strcat (subcmd
, "\"");
210 out
= pipe_and_fork (subcmd
);
212 if ((in
!= NULL
) && (NULL
== freopen (in
, "r", stdin
, "mbc=32", "mbf=2")))
214 perror (in
); /* Can't find file */
215 exit (EXIT_ERR
); /* Is a fatal error */
217 if ((out
!= NULL
) && (NULL
== freopen (out
, outmode
, stdout
, "mbc=32", "mbf=2")))
219 perror (ap
); /* Error, can't write or append */
220 exit (EXIT_ERR
); /* Is a fatal error */
223 fprintf (stderr
, "Arglist:\n");
224 for (j
= 0; j
< *ac
; ++j
)
225 fprintf (stderr
, "argv[%d] = '%s'\n", j
, argv
[j
]);
230 static add_item (head
, tail
, value
, count
)
231 struct list_item
**head
;
232 struct list_item
**tail
;
238 if (NULL
== (*head
= calloc (1, sizeof (**head
))))
247 if (NULL
== ((*tail
)->next
= calloc (1, sizeof (**head
))))
254 *tail
= (*tail
)->next
;
255 (*tail
)->value
= value
;
259 static expand_wild_cards (item
, head
, tail
, count
)
261 struct list_item
**head
;
262 struct list_item
**tail
;
271 $
DESCRIPTOR (filespec
, item
);
272 /*$DESCRIPTOR (defaultspec, "SYS$DISK:[]*.*;");*/
273 $
DESCRIPTOR (defaultspec
, "");
274 $
DESCRIPTOR (resultspec
, "");
276 if (strcspn (item
, "*%") == strlen (item
))
278 add_item (head
, tail
, item
, count
);
281 resultspec
.dsc$b_dtype
= DSC$K_DTYPE_T
;
282 resultspec
.dsc$b_class
= DSC$K_CLASS_D
;
283 resultspec
.dsc$a_pointer
= NULL
;
284 filespec
.dsc$w_length
= strlen (item
);
286 * Only return version specs, if the caller specified a version
288 had_version
= strchr (item
, ';');
290 * Only return full path if the caller specified a path
292 had_path
= (strchr (item
, ']') || strchr (item
, ':'));
293 while (1 == (1&lib$
find_file (&filespec
, &resultspec
, &context
,
294 &defaultspec
, 0, &status_value
, &0)))
299 if (NULL
== (string
= calloc (1, resultspec
.dsc$w_length
+1)))
305 strncpy (string
, resultspec
.dsc$a_pointer
, resultspec
.dsc$w_length
);
306 string
[resultspec
.dsc$w_length
] = '\0';
307 if (NULL
== had_version
)
308 *((char *) strrchr (string
, ';')) = '\0';
310 char *s
= strrchr (string
, ']');
311 if ( s
== NULL
) s
= strrchr (string
, ':');
312 if ( s
!= NULL
) strcpy (string
, s
+1);
315 * Be consistent with what the C RTL has already done to the rest of
316 * the argv items and lowercase all of these names.
318 for (c
= string
; *c
; ++c
)
321 add_item (head
, tail
, string
, count
);
325 add_item (head
, tail
, item
, count
);
326 lib$
sfree1_dd (&resultspec
);
327 lib$
find_file_end (&context
);
330 static int child_st
[2]; /* Event Flag set when child process completes */
332 static short child_chan
;/* I/O Channel for Pipe Mailbox */
334 static exit_handler (status
)
339 if (0 == child_st
[0])
342 fprintf (stderr
, "Waiting for Child Process to Finnish . . .\n");
344 sys$
qiow (0, child_chan
, IO$_WRITEOF
, iosb
, 0, 0, 0, 0, 0, 0, 0, 0);
345 sys$
dassgn (child_chan
);
347 sys$
synch (0, child_st
);
352 static sig_child (chan
)
356 fprintf (stderr
, "Child Completion AST\n");
358 if (child_st
[0] == 0)
362 static struct exit_control_block
364 struct exit_control_block
*flink
;
365 int (*exit_routine
) ();
374 &exit_block
.exit_status
,
378 static char *pipe_and_fork (cmd
)
381 $
DESCRIPTOR (cmddsc
, cmd
);
382 static char mbxname
[64];
383 $
DESCRIPTOR (mbxdsc
, mbxname
);
392 unsigned short *dna_retlen
;
399 &mbxdsc
.dsc$w_length
,
408 unsigned short *mbf_retlen
;
419 cmddsc
.dsc$w_length
= strlen (cmd
);
421 * Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as
422 * the size of the 'pipe' mailbox.
424 if (1 == (1& (vaxc$errno
= sys$
getsyiw (0, 0, 0, &syiitmlst
, iosb
, 0, 0, 0))))
425 vaxc$errno
= iosb
[0];
426 if (0 == (1&vaxc$errno
))
429 perror ("Can't get SYSGEN parameter value for MAXBUF");
434 if (0 == (1& (vaxc$errno
= sys$
crembx (0, &child_chan
, mbxsize
, mbxsize
, 0, 0, 0))))
437 perror ("Can't create pipe mailbox");
440 if (1 == (1& (vaxc$errno
= sys$
getdviw (0, child_chan
, 0, &itmlst
, iosb
,
442 vaxc$errno
= iosb
[0];
443 if (0 == (1&vaxc$errno
))
446 perror ("Can't get pipe mailbox device name");
449 mbxname
[mbxdsc
.dsc$w_length
] = '\0';
451 fprintf (stderr
, "Pipe Mailbox Name = '%s'\n", mbxname
);
453 if (0 == (1& (vaxc$errno
= lib$
spawn (&cmddsc
, &mbxdsc
, 0, &1,
454 0, &pid
, child_st
, &0, sig_child
,
458 perror ("Can't spawn subprocess");
462 fprintf (stderr
, "Subprocess's Pid = %08X\n", pid
);
464 sys$
dclexh (&exit_block
);
468 background_process (argc
, argv
)
472 char command
[2048] = "$";
473 $
DESCRIPTOR (value
, command
);
474 $
DESCRIPTOR (cmd
, "BACKGROUND$COMMAND");
475 $
DESCRIPTOR (null
, "NLA0:");
478 strcat (command
, argv
[0]);
481 strcat (command
, " \"");
482 strcat (command
, *(++argv
));
483 strcat (command
, "\"");
485 value
.dsc$w_length
= strlen (command
);
486 if (0 == (1& (vaxc$errno
= lib$
set_symbol (&cmd
, &value
))))
489 perror ("Can't create symbol for subprocess command");
492 if (0 == (1& (vaxc$errno
= lib$
spawn (&cmd
, &null
, 0, &17, 0, &pid
))))
495 perror ("Can't spawn subprocess");
499 fprintf (stderr
, "%s\n", command
);
501 fprintf (stderr
, "%08X\n", pid
);
505 /* vi:set tabstop=4 shiftwidth=4: */