153 lines
4.3 KiB
C
153 lines
4.3 KiB
C
|
/* vms-code.c -- additional VMS-specific support code for flex
|
|||
|
*/
|
|||
|
|
|||
|
#include "flexdef.h"
|
|||
|
|
|||
|
static const char *original_arg0;
|
|||
|
static const char default_arg0[] = "flex.exe";
|
|||
|
|
|||
|
#define IN_FD 0
|
|||
|
#define OUT_FD 1
|
|||
|
#define ERR_FD 2
|
|||
|
|
|||
|
static char *fix_arg0 PROTO((const char *));
|
|||
|
|
|||
|
/* Command line arguments fixup -- simplify argv[0], and handle `>'
|
|||
|
output redirection request; called first thing from main(). */
|
|||
|
|
|||
|
void argv_fixup( iargc, iargv )
|
|||
|
int *iargc;
|
|||
|
char ***iargv;
|
|||
|
{
|
|||
|
const char *mode[3], *rfm[3], *name[3];
|
|||
|
char *p;
|
|||
|
int i, oargc, punct, which, append, alt_rfm;
|
|||
|
|
|||
|
/*
|
|||
|
* Get original argv[0] supplied by run-time library startup code,
|
|||
|
* then replace it with a stripped down one.
|
|||
|
*/
|
|||
|
original_arg0 = (*iargv)[0];
|
|||
|
(*iargv)[0] = fix_arg0(original_arg0);
|
|||
|
|
|||
|
/*
|
|||
|
* Check command line arguments for redirection request(s).
|
|||
|
* For simplicity, if multiple attempts are made, the last one wins.
|
|||
|
*/
|
|||
|
name[0] = name[1] = name[2] = 0;
|
|||
|
oargc = 1; /* number of args caller will see; count includes argv[0] */
|
|||
|
for (i = 1; i < *iargc; i++) {
|
|||
|
p = (*iargv)[i];
|
|||
|
switch (*p) {
|
|||
|
case '<':
|
|||
|
/* might be "<dir>file"; then again, perhaps "<<dir>file" */
|
|||
|
punct = (strchr(p, '>') != 0);
|
|||
|
if (p[1] == '<') {
|
|||
|
if (!punct || p[2] == '<')
|
|||
|
flexerror("<<'sentinel' input not supported.");
|
|||
|
punct = 0;
|
|||
|
}
|
|||
|
if (punct) /* the '<' seems to be directory punctuation */
|
|||
|
goto arg; /*GOTO*/
|
|||
|
mode[IN_FD] = "r";
|
|||
|
rfm[IN_FD] = 0;
|
|||
|
name[IN_FD] = ++p;
|
|||
|
if (!*p && (i + 1) < *iargc)
|
|||
|
name[IN_FD] = (*iargv)[++i];
|
|||
|
break;
|
|||
|
case '>':
|
|||
|
append = (p[1] == '>');
|
|||
|
if (append) ++p;
|
|||
|
alt_rfm = (p[1] == '$');
|
|||
|
if (alt_rfm) ++p;
|
|||
|
which = (p[1] == '&' ? ERR_FD : OUT_FD);
|
|||
|
if (which == ERR_FD) ++p;
|
|||
|
mode[which] = append ? "a" : "w";
|
|||
|
rfm[which] = alt_rfm ? "rfm=var" : "rfm=stmlf";
|
|||
|
name[which] = ++p;
|
|||
|
if (!*p && (i + 1) < *iargc)
|
|||
|
name[which] = (*iargv)[++i];
|
|||
|
break;
|
|||
|
case '|':
|
|||
|
flexerror("pipe output not supported.");
|
|||
|
/*NOTREACHED*/
|
|||
|
break;
|
|||
|
default:
|
|||
|
arg: /* ordinary option or argument */
|
|||
|
(*iargv)[oargc++] = p;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
/* perform any requested redirection; don't bother with SYS$xxx logicals */
|
|||
|
if (name[IN_FD])
|
|||
|
if (!freopen(name[IN_FD], mode[IN_FD], stdin))
|
|||
|
lerrsf("failed to redirect `stdin' from \"%s\"", name[IN_FD]);
|
|||
|
if (name[OUT_FD])
|
|||
|
if (!freopen(name[OUT_FD], mode[OUT_FD], stdout,
|
|||
|
rfm[OUT_FD], "rat=cr", "mbc=32", "shr=nil"))
|
|||
|
lerrsf("failed to redirect `stdout' to \"%s\"", name[OUT_FD]);
|
|||
|
if (name[ERR_FD]) /* likely won't see message if this fails; oh well... */
|
|||
|
if (!freopen(name[ERR_FD], mode[ERR_FD], stderr,
|
|||
|
rfm[ERR_FD], "rat=cr"))
|
|||
|
lerrsf("failed to redirect `stderr' to \"%s\"", name[ERR_FD]);
|
|||
|
/* remove any excess arguments (used up from redirection) */
|
|||
|
while (*iargc > oargc)
|
|||
|
(*iargv)[--*iargc] = 0;
|
|||
|
/* all done */
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/* Pick out the basename of a full filename, and return a pointer
|
|||
|
to a modifiable copy of it. */
|
|||
|
|
|||
|
static char *fix_arg0( arg0 )
|
|||
|
const char *arg0;
|
|||
|
{
|
|||
|
char *p, *new_arg0;
|
|||
|
|
|||
|
if (arg0) {
|
|||
|
/* strip off the path */
|
|||
|
if ((p = strrchr(arg0, ':')) != 0) /* device punctuation */
|
|||
|
arg0 = p + 1;
|
|||
|
if ((p = strrchr(arg0, ']')) != 0) /* directory punctuation */
|
|||
|
arg0 = p + 1;
|
|||
|
if ((p = strrchr(arg0, '>')) != 0) /* alternate dir punct */
|
|||
|
arg0 = p + 1;
|
|||
|
}
|
|||
|
if (!arg0 || !*arg0)
|
|||
|
arg0 = default_arg0;
|
|||
|
/* should now have "something.exe;#"; make a modifiable copy */
|
|||
|
new_arg0 = copy_string(arg0);
|
|||
|
|
|||
|
/* strip off ".exe" and/or ";#" (version number),
|
|||
|
unless it ended up as the whole name */
|
|||
|
if ((p = strchr(new_arg0, '.')) != 0 && (p > new_arg0)
|
|||
|
&& (p[1] == 'e' || p[1] == 'E')
|
|||
|
&& (p[2] == 'x' || p[2] == 'X')
|
|||
|
&& (p[3] == 'e' || p[3] == 'E')
|
|||
|
&& (p[4] == ';' || p[4] == '.' || p[4] == '\0'))
|
|||
|
*p = '\0';
|
|||
|
else if ((p = strchr(new_arg0, ';')) != 0 && (p > new_arg0))
|
|||
|
*p = '\0';
|
|||
|
|
|||
|
return new_arg0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#include <ssdef.h>
|
|||
|
#include <stsdef.h>
|
|||
|
|
|||
|
#ifdef exit
|
|||
|
#undef exit
|
|||
|
extern void exit PROTO((int)); /* <stdlib.h> ended up prototyping vms_exit */
|
|||
|
#endif
|
|||
|
|
|||
|
/* Convert zero to VMS success and non-zero to VMS failure. The latter
|
|||
|
does not bother trying to distinguish between various failure reasons. */
|
|||
|
|
|||
|
void vms_exit( status )
|
|||
|
int status;
|
|||
|
{
|
|||
|
exit( status == 0 ? SS$_NORMAL : (SS$_ABORT | STS$M_INHIB_MSG) );
|
|||
|
}
|