Blame vms/vms_gawk.c

Packit 575503
/* vms_gawk.c -- parse GAWK command line using DCL syntax
Packit 575503
Packit 575503
   Copyright (C) 1991-1993, 1996, 2003, 2005, 2011, 2014
Packit 575503
   the Free Software Foundation, Inc.
Packit 575503
Packit 575503
   This program is free software; you can redistribute it and/or modify
Packit 575503
   it under the terms of the GNU General Public License as published by
Packit 575503
   the Free Software Foundation; either version 2, or (at your option)
Packit 575503
   any later version.
Packit 575503
Packit 575503
   This program is distributed in the hope that it will be useful,
Packit 575503
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 575503
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 575503
   GNU General Public License for more details.
Packit 575503
Packit 575503
   You should have received a copy of the GNU General Public License
Packit 575503
   along with this program; if not, write to the Free Software Foundation,
Packit 575503
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
Packit 575503
Packit 575503
Packit 575503
/*
Packit 575503
 * vms_gawk.c - routines to parse the command line as a native DCL command
Packit 575503
 *	       rather than as a foreign command string.
Packit 575503
 *							Pat Rankin, Nov'89
Packit 575503
 *						[ revised for 2.12, May'91 ]
Packit 575503
 *						[ revised for 4.0.0, Feb'11 ]
Packit 575503
 */
Packit 575503
Packit 575503
#include "awk.h"
Packit 575503
#include "vms.h"
Packit 575503
Packit 575503
#define USAGE_PROG_RQRD 1
Packit 575503
#define USAGE_FILE_RQRD 2
Packit 575503
#define USAGE_BAD_COMBO 3
Packit 575503
#define USAGE_RUN_CMD	4
Packit 575503
#define STS$M_INHIB_MSG 0x10000000
Packit 575503
Packit 575503
#define Present(arg)		vmswork(Cli_Present(arg))
Packit 575503
#define Get_Value(arg,buf,siz)	vmswork(Cli_Get_Value(arg,buf,siz))
Packit 575503
Packit 575503
#ifndef __DECC
Packit 575503
extern void   GAWK_CMD();	/* created with $ SET COMMAND/OBJECT */
Packit 575503
#define gawk_cmd ((const void *)GAWK_CMD) */
Packit 575503
#else	/* Use ANSI definitions for DEC C */
Packit 575503
#pragma extern_model save
Packit 575503
#pragma extern_model strict_refdef
Packit 575503
/* (could use globalvalue rather than _refdef if we omit GAWK_CMD's `&') */
Packit 575503
extern void  *GAWK_CMD;
Packit 575503
#pragma extern_model restore
Packit 575503
#define gawk_cmd ((const void *)&GAWK_CMD)
Packit 575503
#endif
Packit 575503
extern void   _exit(int);
Packit 575503
static int    vms_usage(int);
Packit 575503
Packit 575503
static const char *CmdName = "GAWK";
Packit 575503
Packit 575503
#define ARG_SIZ 250
Packit 575503
union arg_w_prefix {	/* structure used to simplify prepending of "-" */
Packit 575503
    char     value[2+ARG_SIZ+1];
Packit 575503
    struct {
Packit 575503
	char prefix[2];		/* for "-?" */
Packit 575503
	char buf[ARG_SIZ];
Packit 575503
	char suffix[1];		/* room for '\0' */
Packit 575503
    } arg;
Packit 575503
};
Packit 575503
Packit 575503
#define chk_option(qualifier,optname)	\
Packit 575503
    if (Present(qualifier))	\
Packit 575503
	strcat(strcat(buf.arg.buf, W_cnt++ ? "," : ""), optname)
Packit 575503
Packit 575503
Packit 575503
/* vms_gawk() - parse GAWK command line using DCL and convert it into the */
Packit 575503
/*	       appropriate "-arg" values for compatability with GNU code  */
Packit 575503
int
Packit 575503
vms_gawk()
Packit 575503
{
Packit 575503
    U_Long sts;
Packit 575503
    union arg_w_prefix buf;
Packit 575503
    char misc_args[10], *misc_argp;
Packit 575503
    int  argc, W_cnt;
Packit 575503
    int native_dcl = 1,	/* assume true until we know otherwise */
Packit 575503
	short_circ;	/* some options make P1, /commands, /input superfluous */
Packit 575503
Packit 575503
    /* check "GAWK_P1"--it's required; its presence will tip us off */
Packit 575503
    sts = Cli_Present("GAWK_P1");
Packit 575503
    if (CondVal(sts) == CondVal(CLI$_SYNTAX)) {
Packit 575503
	native_dcl = 0;		/* not invoked via a native command verb */
Packit 575503
	/* syntax error indicates that we weren't invoked as a native DCL
Packit 575503
	   command, so we'll now attempt to generate a command from the
Packit 575503
	   foreign command string and parse that.
Packit 575503
	*/
Packit 575503
	sts = Cli_Parse_Command(gawk_cmd, "GAWK");	/* (*not* CmdName) */
Packit 575503
	if (vmswork(sts))
Packit 575503
	    sts = Cli_Present("GAWK_P1");
Packit 575503
    }
Packit 575503
    short_circ = Present("USAGE") || Present("VERSION") || Present("COPYRIGHT");
Packit 575503
    if (vmswork(sts))		/* command parsed successfully */
Packit 575503
	v_add_arg(argc = 0, CmdName);	/* save "GAWK" as argv[0] */
Packit 575503
    else if (CondVal(sts) == CondVal(CLI$_INSFPRM))
Packit 575503
	/* vms_usage() will handle /usage, /version, and /copyright */
Packit 575503
	return short_circ ? vms_usage(0)
Packit 575503
		: native_dcl ? vms_usage(USAGE_FILE_RQRD) : 0; /* insufficient parameters */
Packit 575503
    else if (CondVal(sts) == CondVal(CLI$_CONFLICT))
Packit 575503
	return vms_usage(USAGE_BAD_COMBO);  /* conflicting qualifiers (/input+/command) */
Packit 575503
#if 0	/* 3.1.2: removed since this can't distinguish RUN vs fork+exec */
Packit 575503
    else if (CondVal(sts) == CondVal(CLI$_RUNUSED))
Packit 575503
	return vms_usage(USAGE_RUN_CMD);    /* RUN GAWK won't work (no command line) */
Packit 575503
#endif
Packit 575503
    else
Packit 575503
	return 0;	/* forced to rely on original parsing */
Packit 575503
Packit 575503
    if (short_circ)		/* give usage message & quit or have main() */
Packit 575503
	return vms_usage(0);	/* give --version or --copyleft mesg & quit */
Packit 575503
    else if (! (Present("PROGRAM") || Present("PROGFILE")) )
Packit 575503
	return native_dcl ? vms_usage(USAGE_PROG_RQRD) : 0; /* missing required option */
Packit 575503
Packit 575503
    misc_argp = misc_args;
Packit 575503
    *misc_argp++ = '-';		/* now points at &misc_args[1] */
Packit 575503
    if (Present("OPTIMIZE"))
Packit 575503
	*misc_argp++ = 'O';
Packit 575503
    W_cnt = 0,	buf.arg.buf[0] = '\0';
Packit 575503
    strncpy(buf.arg.prefix, "-W", 2);
Packit 575503
    if (Present("LINT")) {
Packit 575503
	if (!Present("LINT.FATAL") && !Present("LINT.INVALID"))
Packit 575503
	    chk_option("LINT.WARN", "lint");
Packit 575503
	chk_option("LINT.FATAL", "lint=fatal");
Packit 575503
	chk_option("LINT.INVALID", "lint=invalid");
Packit 575503
	chk_option("LINT.OLD", "lint-old");	/* distinct option */
Packit 575503
    }
Packit 575503
    chk_option("POSIX", "posix");
Packit 575503
    if (CondVal(Cli_Present("TRADITIONAL")) != CondVal(CLI$_NEGATED))
Packit 575503
	chk_option("STRICT", "traditional");  /* /strict is synonym for /traditional */
Packit 575503
    if (CondVal(Cli_Present("STRICT")) != CondVal(CLI$_NEGATED))
Packit 575503
	chk_option("TRADITIONAL", "traditional");
Packit 575503
    chk_option("RE_INTERVAL", "re-interval");  /* only used with /traditional */
Packit 575503
    chk_option("SANDBOX", "sandbox");
Packit 575503
    /* potentially a problem due to leading "NO" */
Packit 575503
    chk_option("NON_DECIMAL_DATA", "non-decimal-data");
Packit 575503
    /* note: locale and translation stuff is not supported by vms gawk */
Packit 575503
    chk_option("CHARACTERS_AS_BYTES", "characters-as-bytes");
Packit 575503
    chk_option("USE_LC_NUMERIC", "use-lc-numeric");
Packit 575503
    chk_option("GEN_POT", "gen-pot");
Packit 575503
# if 0
Packit 575503
    /* /copyright and /version don't reach here anymore (short_circ above) */
Packit 575503
    chk_option("COPYRIGHT", "copyright");	/* --copyleft */
Packit 575503
    chk_option("VERSION", "version");
Packit 575503
# endif
Packit 575503
    if (W_cnt > 0)			/* got something */
Packit 575503
	v_add_arg(++argc, strdup(buf.value));
Packit 575503
Packit 575503
#ifdef DEBUG /* most debugging functionality moved to separate DGAWK program */
Packit 575503
    if (Present("DEBUG"))
Packit 575503
	    *misc_argp++ = 'Y';		/* --parsedebug */
Packit 575503
#endif
Packit 575503
    *misc_argp = '\0';		/* terminate misc_args[] */
Packit 575503
    if (misc_argp > &misc_args[1])	/* got something */
Packit 575503
	v_add_arg(++argc, misc_args);	/* store it/them */
Packit 575503
Packit 575503
    if (Present("PROFILE")) {	    /* /profile[=file] */
Packit 575503
	strncpy(buf.arg.prefix, "-p", 2);
Packit 575503
	if (Get_Value("PROFILE", buf.arg.buf, sizeof buf.arg.buf))
Packit 575503
	    v_add_arg(++argc, strdup(buf.value));
Packit 575503
    }
Packit 575503
    if (Present("DUMP_VARIABLES")) { /* /dump_variables[=file] */
Packit 575503
	strncpy(buf.arg.prefix, "-d", 2);
Packit 575503
	if (Get_Value("DUMP_VARIABLES", buf.arg.buf, sizeof buf.arg.buf))
Packit 575503
	    v_add_arg(++argc, strdup(buf.value));
Packit 575503
    }
Packit 575503
    if (Present("FIELD_SEP")) {     /* field separator */
Packit 575503
	strncpy(buf.arg.prefix, "-F", 2);
Packit 575503
	if (Get_Value("FIELD_SEP", buf.arg.buf, sizeof buf.arg.buf))
Packit 575503
	    v_add_arg(++argc, strdup(buf.value));
Packit 575503
    }
Packit 575503
    if (Present("VARIABLES")) {     /* variables to init prior to BEGIN */
Packit 575503
	strncpy(buf.arg.prefix, "-v", 2);
Packit 575503
	while (Get_Value("VARIABLES", buf.arg.buf, sizeof buf.arg.buf))
Packit 575503
	    v_add_arg(++argc, strdup(buf.value));
Packit 575503
    }
Packit 575503
    /* the relative order of -e and -f args matters; unfortunately,
Packit 575503
       we're losing that here... */
Packit 575503
    if (Present("MOREPROG")) {	    /* /extra_input=text -> -e text */
Packit 575503
	strncpy(buf.arg.prefix, "-e", 2);
Packit 575503
	if (Get_Value("MOREPROG", buf.arg.buf, sizeof buf.arg.buf))
Packit 575503
	    v_add_arg(++argc, strdup(buf.value));
Packit 575503
    }
Packit 575503
    if (Present("PROGFILE")) {	    /* program files, /input=file -> -f file */
Packit 575503
	strncpy(buf.arg.prefix, "-f", 2);
Packit 575503
	while (Get_Value("PROGFILE", buf.arg.buf, sizeof buf.arg.buf))
Packit 575503
	    v_add_arg(++argc, strdup(buf.value));
Packit 575503
	v_add_arg(++argc, "--");
Packit 575503
    } else if (Present("PROGRAM")) {	/* program text, /commands -> 'text' */
Packit 575503
	v_add_arg(++argc, "--");
Packit 575503
	if (Get_Value("PROGRAM", buf.value, sizeof buf.value))
Packit 575503
	    v_add_arg(++argc, strdup(buf.value));
Packit 575503
    }
Packit 575503
Packit 575503
    /* we know that "GAWK_P1" is present [data files and/or 'var=value'] */
Packit 575503
    while (Get_Value("GAWK_P1", buf.value, sizeof buf.value))
Packit 575503
	v_add_arg(++argc, strdup(buf.value));
Packit 575503
Packit 575503
    if (Present("OUTPUT")) {	/* let other parser treat this as 'stdout' */
Packit 575503
	strncpy(buf.arg.prefix, ">$", 2);
Packit 575503
	if (Get_Value("OUTPUT", buf.arg.buf, sizeof buf.arg.buf))
Packit 575503
	    v_add_arg(++argc, strdup(buf.value));
Packit 575503
    }
Packit 575503
Packit 575503
    return ++argc;		/*(increment to account for arg[0])*/
Packit 575503
}
Packit 575503
Packit 575503
/* vms_usage() - display one or more messages and then terminate */
Packit 575503
static int	/* note: usually doesn't return */
Packit 575503
vms_usage( int complaint )
Packit 575503
{
Packit 575503
    static const char
Packit 575503
	*usage_txt = "\n\
Packit 575503
usage: %s /COMMANDS=\"awk program text\"  data_file[,data_file,...] \n\
Packit 575503
   or  %s /INPUT=awk_file  data_file[,\"Var=value\",data_file,...] \n\
Packit 575503
   or  %s /INPUT=(awk_file1,awk_file2,...)  data_file[,...] \n\
Packit 575503
   or  %s /INPUT=awk_file /EXTRA_COMMANDS=\"program text\" data_file \n\
Packit 575503
",
Packit 575503
    *options_txt = "\n\
Packit 575503
options: /FIELD_SEPARATOR=\"FS_value\" \n\
Packit 575503
   and   /VARIABLES=(\"Var1=value1\",\"Var2=value2\",...) \n\
Packit 575503
   and   /OPTIMIZE  /PROFILE[=file]  /DUMP_VARIABLES[=file] \n\
Packit 575503
   and   /POSIX  /[NO]TRADITIONAL  /[NO]STRICT  /RE_INTERVAL \n\
Packit 575503
   and   /SANDBOX  /NON_DECIMAL_DATA \n\
Packit 575503
   and   /LINT[=WARN]  or  /LINT=OLD  or  /LINT=FATAL \n\
Packit 575503
   and   /VERSION  /COPYRIGHT  /USAGE \n\
Packit 575503
   and   /OUTPUT=out_file \n\
Packit 575503
",  /* omitted: /LINT=INVALID /CHARACTERS_AS_BYTES /USE_LC_NUMERIC /GEN_POT */
Packit 575503
	*no_prog = "missing required element: /COMMANDS or /INPUT",
Packit 575503
	*no_file = "missing required element: data_file \n\
Packit 575503
       (use \"SYS$INPUT:\" to read data lines from the terminal)",
Packit 575503
	*bad_combo = "invalid combination of qualifiers \n\
Packit 575503
       (/INPUT=awk_file and /COMMANDS=\"awk program\" are mutually exclusive)",
Packit 575503
	*run_used = "\"RUN\" was used; required command components missing";
Packit 575503
    int status, argc;
Packit 575503
Packit 575503
    /* presence of /usage, /version, or /copyright for feedback+quit
Packit 575503
       supersedes absence of required program or data file */
Packit 575503
    if (Present("USAGE")) {
Packit 575503
	complaint = 0;			/* clean exit */
Packit 575503
    } else if (Present("VERSION") || Present("COPYRIGHT")) {
Packit 575503
	/* construct a truncated Unix-style command line to control main() */
Packit 575503
	v_add_arg(argc=0, CmdName);	/* save "GAWK" as argv[0] */
Packit 575503
#if 0
Packit 575503
	v_add_arg(++argc, Present("VERSION") ? "-V" : "-C");
Packit 575503
#else
Packit 575503
	v_add_arg(++argc, "-W");
Packit 575503
	v_add_arg(++argc, Present("VERSION") ? "version" : "copyright");
Packit 575503
#endif
Packit 575503
	/* kludge to suppress 'usage' message from main() */
Packit 575503
	v_add_arg(++argc, "--");		/* no more arguments */
Packit 575503
	v_add_arg(++argc, "{}");		/* dummy program text */
Packit 575503
	v_add_arg(++argc, "NL:");		/* dummy input file */
Packit 575503
	return ++argc;			/* count argv[0] too */
Packit 575503
    }
Packit 575503
Packit 575503
    fflush(stdout);
Packit 575503
    switch (complaint) {
Packit 575503
      case USAGE_PROG_RQRD:
Packit 575503
	fprintf(stderr, "\n%%%s-W-%s, %s \n", CmdName, "PROG_RQRD", no_prog);
Packit 575503
	status = CLI$_VALREQ | STS$M_INHIB_MSG;
Packit 575503
	break;
Packit 575503
      case USAGE_FILE_RQRD:
Packit 575503
	fprintf(stderr, "\n%%%s-W-%s, %s \n", CmdName, "FILE_RQRD", no_file);
Packit 575503
	status = CLI$_INSFPRM | STS$M_INHIB_MSG;
Packit 575503
	break;
Packit 575503
      case USAGE_BAD_COMBO:
Packit 575503
	fprintf(stderr, "\n%%%s-W-%s, %s \n", CmdName, "BAD_COMBO", bad_combo);
Packit 575503
	status = CLI$_CONFLICT | STS$M_INHIB_MSG;
Packit 575503
	break;
Packit 575503
      case USAGE_RUN_CMD:
Packit 575503
	fprintf(stderr, "\n%%%s-W-%s, %s \n", CmdName, "RUN_CMD", run_used);
Packit 575503
	status = CLI$_NOOPTPRS | STS$M_INHIB_MSG;
Packit 575503
	break;
Packit 575503
      default:
Packit 575503
	status = 1;
Packit 575503
	break;
Packit 575503
    }
Packit 575503
    fprintf(stderr, usage_txt, CmdName, CmdName, CmdName, CmdName);
Packit 575503
    fprintf(stderr, options_txt);
Packit 575503
    fflush(stderr);
Packit 575503
Packit 575503
    errno = EVMSERR;
Packit 575503
    vaxc$errno = status;
Packit 575503
    _exit(status);
Packit 575503
    /* NOTREACHED */
Packit 575503
    return 0;
Packit 575503
}