Blame vms/vms_gawk.c

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