(root)/
gawk-5.2.2/
vms/
vms_gawk.c
       1  /* vms_gawk.c -- parse GAWK command line using DCL syntax
       2  
       3     Copyright (C) 1991-1993, 1996, 2003, 2005, 2011, 2014, 2022, 2023,
       4     the Free Software Foundation, Inc.
       5  
       6     This program is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program; if not, write to the Free Software Foundation,
      18     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
      19  
      20  
      21  /*
      22   * vms_gawk.c - routines to parse the command line as a native DCL command
      23   *	       rather than as a foreign command string.
      24   *							Pat Rankin, Nov'89
      25   *						[ revised for 2.12, May'91 ]
      26   *						[ revised for 4.0.0, Feb'11 ]
      27   */
      28  
      29  #include "awk.h"
      30  #include "vms.h"
      31  
      32  #define USAGE_PROG_RQRD 1
      33  #define USAGE_FILE_RQRD 2
      34  #define USAGE_BAD_COMBO 3
      35  #define USAGE_RUN_CMD	4
      36  #define STS$M_INHIB_MSG 0x10000000
      37  
      38  #define Present(arg)		vmswork(Cli_Present(arg))
      39  #define Get_Value(arg,buf,siz)	vmswork(Cli_Get_Value(arg,buf,siz))
      40  
      41  #ifndef __DECC
      42  extern void   GAWK_CMD();	/* created with $ SET COMMAND/OBJECT */
      43  #define gawk_cmd ((const void *)GAWK_CMD) */
      44  #else	/* Use ANSI definitions for DEC C */
      45  #pragma extern_model save
      46  #pragma extern_model strict_refdef
      47  /* (could use globalvalue rather than _refdef if we omit GAWK_CMD's `&') */
      48  extern void  *GAWK_CMD;
      49  #pragma extern_model restore
      50  #define gawk_cmd ((const void *)&GAWK_CMD)
      51  #endif
      52  extern void   _exit(int);
      53  static int    vms_usage(int);
      54  
      55  static const char *CmdName = "GAWK";
      56  
      57  #define ARG_SIZ 250
      58  union arg_w_prefix {	/* structure used to simplify prepending of "-" */
      59      char     value[2+ARG_SIZ+1];
      60      struct {
      61  	char prefix[2];		/* for "-?" */
      62  	char buf[ARG_SIZ];
      63  	char suffix[1];		/* room for '\0' */
      64      } arg;
      65  };
      66  
      67  #define chk_option(qualifier,optname)	\
      68      if (Present(qualifier))	\
      69  	strcat(strcat(buf.arg.buf, W_cnt++ ? "," : ""), optname)
      70  
      71  
      72  /* vms_gawk() - parse GAWK command line using DCL and convert it into the */
      73  /*	       appropriate "-arg" values for compatability with GNU code  */
      74  int
      75  vms_gawk()
      76  {
      77      U_Long sts;
      78      union arg_w_prefix buf;
      79      char misc_args[10], *misc_argp;
      80      int  argc, W_cnt;
      81      int native_dcl = 1,	/* assume true until we know otherwise */
      82  	short_circ;	/* some options make P1, /commands, /input superfluous */
      83  
      84      /* check "GAWK_P1"--it's required; its presence will tip us off */
      85      sts = Cli_Present("GAWK_P1");
      86      if (CondVal(sts) == CondVal(CLI$_SYNTAX)) {
      87  	native_dcl = 0;		/* not invoked via a native command verb */
      88  	/* syntax error indicates that we weren't invoked as a native DCL
      89  	   command, so we'll now attempt to generate a command from the
      90  	   foreign command string and parse that.
      91  	*/
      92  	sts = Cli_Parse_Command(gawk_cmd, "GAWK");	/* (*not* CmdName) */
      93  	if (vmswork(sts))
      94  	    sts = Cli_Present("GAWK_P1");
      95      }
      96      short_circ = Present("USAGE") || Present("VERSION") || Present("COPYRIGHT");
      97      if (vmswork(sts))		/* command parsed successfully */
      98  	v_add_arg(argc = 0, CmdName);	/* save "GAWK" as argv[0] */
      99      else if (CondVal(sts) == CondVal(CLI$_INSFPRM))
     100  	/* vms_usage() will handle /usage, /version, and /copyright */
     101  	return short_circ ? vms_usage(0)
     102  		: native_dcl ? vms_usage(USAGE_FILE_RQRD) : 0; /* insufficient parameters */
     103      else if (CondVal(sts) == CondVal(CLI$_CONFLICT))
     104  	return vms_usage(USAGE_BAD_COMBO);  /* conflicting qualifiers (/input+/command) */
     105  #if 0	/* 3.1.2: removed since this can't distinguish RUN vs fork+exec */
     106      else if (CondVal(sts) == CondVal(CLI$_RUNUSED))
     107  	return vms_usage(USAGE_RUN_CMD);    /* RUN GAWK won't work (no command line) */
     108  #endif
     109      else
     110  	return 0;	/* forced to rely on original parsing */
     111  
     112      if (short_circ)		/* give usage message & quit or have main() */
     113  	return vms_usage(0);	/* give --version or --copyleft mesg & quit */
     114      else if (! (Present("PROGRAM") || Present("PROGFILE")) )
     115  	return native_dcl ? vms_usage(USAGE_PROG_RQRD) : 0; /* missing required option */
     116  
     117      misc_argp = misc_args;
     118      *misc_argp++ = '-';		/* now points at &misc_args[1] */
     119      if (Present("OPTIMIZE"))
     120  	*misc_argp++ = 'O';
     121      W_cnt = 0,	buf.arg.buf[0] = '\0';
     122      strncpy(buf.arg.prefix, "-W", 2);
     123      if (Present("LINT")) {
     124  	if (!Present("LINT.FATAL") && !Present("LINT.INVALID"))
     125  	    chk_option("LINT.WARN", "lint");
     126  	chk_option("LINT.FATAL", "lint=fatal");
     127  	chk_option("LINT.INVALID", "lint=invalid");
     128  	chk_option("LINT.OLD", "lint-old");	/* distinct option */
     129      }
     130      chk_option("POSIX", "posix");
     131      if (CondVal(Cli_Present("TRADITIONAL")) != CondVal(CLI$_NEGATED))
     132  	chk_option("STRICT", "traditional");  /* /strict is synonym for /traditional */
     133      if (CondVal(Cli_Present("STRICT")) != CondVal(CLI$_NEGATED))
     134  	chk_option("TRADITIONAL", "traditional");
     135      chk_option("RE_INTERVAL", "re-interval");  /* only used with /traditional */
     136      chk_option("SANDBOX", "sandbox");
     137      /* potentially a problem due to leading "NO" */
     138      chk_option("NON_DECIMAL_DATA", "non-decimal-data");
     139      /* note: locale and translation stuff is not supported by vms gawk */
     140      chk_option("CHARACTERS_AS_BYTES", "characters-as-bytes");
     141      chk_option("USE_LC_NUMERIC", "use-lc-numeric");
     142      chk_option("GEN_POT", "gen-pot");
     143  # if 0
     144      /* /copyright and /version don't reach here anymore (short_circ above) */
     145      chk_option("COPYRIGHT", "copyright");	/* --copyleft */
     146      chk_option("VERSION", "version");
     147  # endif
     148      if (W_cnt > 0)			/* got something */
     149  	v_add_arg(++argc, strdup(buf.value));
     150  
     151  #ifdef DEBUG /* most debugging functionality moved to separate DGAWK program */
     152      if (Present("DEBUG"))
     153  	    *misc_argp++ = 'Y';		/* --parsedebug */
     154  #endif
     155      *misc_argp = '\0';		/* terminate misc_args[] */
     156      if (misc_argp > &misc_args[1])	/* got something */
     157  	v_add_arg(++argc, misc_args);	/* store it/them */
     158  
     159      if (Present("PROFILE")) {	    /* /profile[=file] */
     160  	strncpy(buf.arg.prefix, "-p", 2);
     161  	if (Get_Value("PROFILE", buf.arg.buf, sizeof buf.arg.buf))
     162  	    v_add_arg(++argc, strdup(buf.value));
     163      }
     164      if (Present("DUMP_VARIABLES")) { /* /dump_variables[=file] */
     165  	strncpy(buf.arg.prefix, "-d", 2);
     166  	if (Get_Value("DUMP_VARIABLES", buf.arg.buf, sizeof buf.arg.buf))
     167  	    v_add_arg(++argc, strdup(buf.value));
     168      }
     169      if (Present("FIELD_SEP")) {     /* field separator */
     170  	strncpy(buf.arg.prefix, "-F", 2);
     171  	if (Get_Value("FIELD_SEP", buf.arg.buf, sizeof buf.arg.buf))
     172  	    v_add_arg(++argc, strdup(buf.value));
     173      }
     174      if (Present("VARIABLES")) {     /* variables to init prior to BEGIN */
     175  	strncpy(buf.arg.prefix, "-v", 2);
     176  	while (Get_Value("VARIABLES", buf.arg.buf, sizeof buf.arg.buf))
     177  	    v_add_arg(++argc, strdup(buf.value));
     178      }
     179      /* the relative order of -e and -f args matters; unfortunately,
     180         we're losing that here... */
     181      if (Present("MOREPROG")) {	    /* /extra_input=text -> -e text */
     182  	strncpy(buf.arg.prefix, "-e", 2);
     183  	if (Get_Value("MOREPROG", buf.arg.buf, sizeof buf.arg.buf))
     184  	    v_add_arg(++argc, strdup(buf.value));
     185      }
     186      if (Present("PROGFILE")) {	    /* program files, /input=file -> -f file */
     187  	strncpy(buf.arg.prefix, "-f", 2);
     188  	while (Get_Value("PROGFILE", buf.arg.buf, sizeof buf.arg.buf))
     189  	    v_add_arg(++argc, strdup(buf.value));
     190  	v_add_arg(++argc, "--");
     191      } else if (Present("PROGRAM")) {	/* program text, /commands -> 'text' */
     192  	v_add_arg(++argc, "--");
     193  	if (Get_Value("PROGRAM", buf.value, sizeof buf.value))
     194  	    v_add_arg(++argc, strdup(buf.value));
     195      }
     196  
     197      /* we know that "GAWK_P1" is present [data files and/or 'var=value'] */
     198      while (Get_Value("GAWK_P1", buf.value, sizeof buf.value))
     199  	v_add_arg(++argc, strdup(buf.value));
     200  
     201      if (Present("OUTPUT")) {	/* let other parser treat this as 'stdout' */
     202  	strncpy(buf.arg.prefix, ">$", 2);
     203  	if (Get_Value("OUTPUT", buf.arg.buf, sizeof buf.arg.buf))
     204  	    v_add_arg(++argc, strdup(buf.value));
     205      }
     206  
     207      return ++argc;		/*(increment to account for arg[0])*/
     208  }
     209  
     210  /* vms_usage() - display one or more messages and then terminate */
     211  static int	/* note: usually doesn't return */
     212  vms_usage( int complaint )
     213  {
     214      static const char
     215  	*usage_txt = "\n\
     216  usage: %s /COMMANDS=\"awk program text\"  data_file[,data_file,...] \n\
     217     or  %s /INPUT=awk_file  data_file[,\"Var=value\",data_file,...] \n\
     218     or  %s /INPUT=(awk_file1,awk_file2,...)  data_file[,...] \n\
     219     or  %s /INPUT=awk_file /EXTRA_COMMANDS=\"program text\" data_file \n\
     220  ",
     221      *options_txt = "\n\
     222  options: /FIELD_SEPARATOR=\"FS_value\" \n\
     223     and   /VARIABLES=(\"Var1=value1\",\"Var2=value2\",...) \n\
     224     and   /OPTIMIZE  /PROFILE[=file]  /DUMP_VARIABLES[=file] \n\
     225     and   /POSIX  /[NO]TRADITIONAL  /[NO]STRICT  /RE_INTERVAL \n\
     226     and   /SANDBOX  /NON_DECIMAL_DATA \n\
     227     and   /LINT[=WARN]  or  /LINT=OLD  or  /LINT=FATAL \n\
     228     and   /VERSION  /COPYRIGHT  /USAGE \n\
     229     and   /OUTPUT=out_file \n\
     230  ",  /* omitted: /LINT=INVALID /CHARACTERS_AS_BYTES /USE_LC_NUMERIC /GEN_POT */
     231  	*no_prog = "missing required element: /COMMANDS or /INPUT",
     232  	*no_file = "missing required element: data_file \n\
     233         (use \"SYS$INPUT:\" to read data lines from the terminal)",
     234  	*bad_combo = "invalid combination of qualifiers \n\
     235         (/INPUT=awk_file and /COMMANDS=\"awk program\" are mutually exclusive)",
     236  	*run_used = "\"RUN\" was used; required command components missing";
     237      int status, argc;
     238  
     239      /* presence of /usage, /version, or /copyright for feedback+quit
     240         supersedes absence of required program or data file */
     241      if (Present("USAGE")) {
     242  	complaint = 0;			/* clean exit */
     243      } else if (Present("VERSION") || Present("COPYRIGHT")) {
     244  	/* construct a truncated Unix-style command line to control main() */
     245  	v_add_arg(argc=0, CmdName);	/* save "GAWK" as argv[0] */
     246  #if 0
     247  	v_add_arg(++argc, Present("VERSION") ? "-V" : "-C");
     248  #else
     249  	v_add_arg(++argc, "-W");
     250  	v_add_arg(++argc, Present("VERSION") ? "version" : "copyright");
     251  #endif
     252  	/* kludge to suppress 'usage' message from main() */
     253  	v_add_arg(++argc, "--");		/* no more arguments */
     254  	v_add_arg(++argc, "{}");		/* dummy program text */
     255  	v_add_arg(++argc, "NL:");		/* dummy input file */
     256  	return ++argc;			/* count argv[0] too */
     257      }
     258  
     259      fflush(stdout);
     260      switch (complaint) {
     261        case USAGE_PROG_RQRD:
     262  	fprintf(stderr, "\n%%%s-W-%s, %s \n", CmdName, "PROG_RQRD", no_prog);
     263  	status = CLI$_VALREQ | STS$M_INHIB_MSG;
     264  	break;
     265        case USAGE_FILE_RQRD:
     266  	fprintf(stderr, "\n%%%s-W-%s, %s \n", CmdName, "FILE_RQRD", no_file);
     267  	status = CLI$_INSFPRM | STS$M_INHIB_MSG;
     268  	break;
     269        case USAGE_BAD_COMBO:
     270  	fprintf(stderr, "\n%%%s-W-%s, %s \n", CmdName, "BAD_COMBO", bad_combo);
     271  	status = CLI$_CONFLICT | STS$M_INHIB_MSG;
     272  	break;
     273        case USAGE_RUN_CMD:
     274  	fprintf(stderr, "\n%%%s-W-%s, %s \n", CmdName, "RUN_CMD", run_used);
     275  	status = CLI$_NOOPTPRS | STS$M_INHIB_MSG;
     276  	break;
     277        default:
     278  	status = 1;
     279  	break;
     280      }
     281      fprintf(stderr, usage_txt, CmdName, CmdName, CmdName, CmdName);
     282      fprintf(stderr, options_txt);
     283      fflush(stderr);
     284  
     285      errno = EVMSERR;
     286      vaxc$errno = status;
     287      _exit(status);
     288      /* NOTREACHED */
     289      return 0;
     290  }