/****************************************************************
 *								*
 *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#include "mdef.h"

#include "gtm_string.h"

#include "compiler.h"
#include "opcode.h"
#include "toktyp.h"
#include "nametabtyp.h"
#include "io_params.h"
#include "zshow_params.h"
#include "advancewindow.h"
#include "namelook.h"
#include "cvtparm.h"
#include "deviceparameters.h"

error_def(ERR_DEVPARINAP);
error_def(ERR_DEVPARUNK);
error_def(ERR_DEVPARVALREQ);
error_def(ERR_RPARENMISSING);

LITREF unsigned char io_params_size[];
LITREF dev_ctl_struct dev_param_control[];
LITDEF nametabent dev_param_names[] =
{
	 {2,"AF*"}
	,{2,"AL*"}	,{4,"ALLO"}
	,{2,"AP*"}
	,{2,"AT*"}

	,{4,"BIGR*"}
	,{2,"BL*"}	,{4,"BLOC"}
	,{4,"BU*"}

	,{2,"CA"}, {4,"CANT*"}
	,{4,"CANO*"}
	,{2,"CE*"}
	,{3,"CHA*"}
	,{3,"CHS*"}
	,{3,"CLE*"}
	,{3,"CLI"}
	,{4,"COMM*"},	{7,"COMMAND"}
	,{4,"CONN*"}
	,{4,"CONT*"}
	,{4,"CONV*"}
	,{3,"COP*"}
	,{2,"CP*"}
	,{2,"CT*"}	,{4,"CTRA"}

	,{4,"DELE*"}    ,{4,"DELE"}
	,{4,"DELI*"}
	,{4,"DEST*" }	,{7,"DESTROY"}
	,{3,"DET*"}
	,{3,"DOU*"}
	,{3,"DOW*"}

	,{2,"EB*"}	,{4,"EBCD"}
	,{2,"EC*"}
	,{2,"ED*"}	,{4,"EDIT"}
	,{6,"ERASEL*"}
	,{6,"ERASET*"}
	,{2,"ES*"}
	,{3,"EXC*"}	,{4,"EXCE"}
	,{3,"EXT*"}	,{4,"EXTE"}
	,{4,"EXTG*"}

	,{1,"F"}	,{3,"FIE*"}	,{5,"FIELD"}
	,{3,"FIF*"}	,{4,"FIFO"}
	,{3,"FIL*"}
	,{3,"FIR*"}
	,{3,"FIX*"}	,{5,"FIXED"}
	,{3,"FLA*"}
	,{3,"FLU*"}
	,{2,"FO*"}

	,{1,"G"}	,{2,"GR*"}

	,{2,"HE*"}
	,{3,"HOL*"}
	,{3,"HOS*"}	,{4,"HOST"}

	,{6,"ICHSET"}
	,{4,"INDE*"}	,{11,"INDEPENDENT"}
	,{2,"IN*"}	,{4,"INSE"}
	,{3,"IOE*"}

	,{3,"LAB*"}
	,{3,"LAS*"}
	,{2,"LE*"}	,{4,"LENG"}
	,{2,"LI*"}
	,{4,"LOGF*"}
	,{4,"LOGQ*"}
	,{3,"LOW*"}

	,{1,"M"}
        ,{8,"MOREREAD*"}
	,{3,"MOU*"}

	,{2,"NA*"}
	,{3,"NEW*"}
	,{3,"NEX*"}
	,{6,"NOBIGR*"}
	,{4,"NOBU*"}
	,{4,"NOCA*"}
	,{4,"NOCE*"}	,{6,"NOCENE"}
	,{6,"NOCONV*"}
	,{6,"NODELI*"}
	,{6,"NODEST*"}	,{9,"NODESTROY"}
	,{5,"NODOU*"}
	,{4,"NOEB*"}
	,{4,"NOEC*"}	,{6,"NOECHO"}
	,{4,"NOED*"}	,{6,"NOEDIT"}
	,{4,"NOES*"}	,{6,"NOESCA"}
	,{5,"NOEXT*"}
	,{5,"NOFIL*"}
	,{5,"NOFIX*"}
	,{5,"NOFLA*"}
	,{4,"NOHE*"}
	,{5,"NOHOL*"}
	,{5,"NOHOS*"}	,{6,"NOHOST"}
	,{4,"NOIN*"}	,{6,"NOINSE"}
	,{5,"NOLAB*"}
	,{5,"NOLOW*"}
	,{6,"NONOTI*"}
	,{5,"NOPAG*"}
	,{6,"NOPASS*"}
	,{6,"NOPAST*"}
	,{6,"NOPRIN*"}
	,{4,"NORC*"}
	,{6,"NOREAD"}	,{7,"NOREADO*"}
	,{7,"NOREADS*"}
	,{5,"NORES*"}
	,{5,"NORET*"}
	,{4,"NOSE*"}
	,{4,"NOST*"}
	,{4,"NOTE"}
	,{5,"NOTER*"}
	,{4,"NOTI*"}
	,{5,"NOTRA*"}
	,{5,"NOTRU*"}
	,{4,"NOTT*"}	,{6,"NOTTSY"}
	,{4,"NOTY*"}	,{6,"NOTYPE"}
	,{4,"NOUR*"}
	,{4,"NOWA*"}
	,{4,"NOWC*"}
	,{4,"NOWR"}	,{5,"NOWRA*"}	,{6,"NOWRAP"}
	,{7,"NOWRITE*"}
	,{2,"NU*"}

	,{1,"O"}
	,{6,"OCHSET"}
	,{2,"OP*"}
	,{2,"OV*"}
	,{2,"OW*"}

	,{2,"P1"}
	,{2,"P2"}
	,{2,"P3"}
	,{2,"P4"}
	,{2,"P5"}
	,{2,"P6"}
	,{2,"P7"}
	,{2,"P8"}
	,{3,"PAD"}
	,{3,"PAG*"}
	,{4,"PARS*"}	,{5,"PARSE"}
	,{4,"PASS*"}
	,{4,"PAST*"}
	,{4,"PRIO*"}
	,{4,"PRIN*"}
	,{3,"PRM*"}	,{6,"PRMMBX"}
	,{3,"PRO*"}

	,{3,"QUE*"}

	,{2,"RC*"}	,{4,"RCHK"}
	,{4,"READ"}	,{5,"READO*"}
	,{5,"READS*"}
	,{3,"REC*"}
	,{3,"REM*"}
	,{3,"REN*"}
	,{3,"RES*"}
	,{3,"RET*"}
	,{3,"REW*"}
	,{3,"RFA"}
	,{3,"RFM"}

	,{1,"S"}
	,{3,"SEQ*"}
	,{3,"SET*"}
	,{2,"SH"}	,{3,"SHA*"}	,{4,"SHAR"}
	,{4,"SHEL*"}	,{5,"SHELL"}
	,{2,"SK*"}
	,{2,"SO*"}
	,{3,"SPA*"}
	,{3,"SPO*"}
	,{2,"ST"}	,{3,"STR*"}
	,{4,"STDE*"}	,{6,"STDERR"}
	,{2,"SU*"}
	,{2,"SY*"}

	,{2,"TE*"}	,{4,"TERM"}
	,{2,"TM*"}
	,{3,"TRA*"}
	,{3,"TRU*"}
	,{2,"TT*"}	,{4,"TTSY"}
	,{2,"TY*"}	,{4,"TYPE"}

	,{2,"UI*"}	,{3,"UIC"}
	,{2,"UN*"}
	,{2,"UP*"}
	,{2,"UR*"}
	,{2,"US*"}

	,{2,"VA*"}

	,{1,"W"}
	,{2,"WA*"}	,{4,"WAIT"}
	,{2,"WC*"}	,{4,"WCHK"}
	,{2,"WI*"}	,{5,"WIDTH"}
	,{2,"WO*"}
	,{2,"WR"}	,{3,"WRA*"}
	,{5,"WRITE"}
	,{7,"WRITELB"}
	,{7,"WRITEOF"}
	,{7,"WRITEON*"}
	,{7,"WRITETM"}

	,{1,"X"}

	,{1,"Y"}

	,{2,"ZB*"}
	,{2,"ZD*"}
	,{3,"ZEX*"}
	,{4,"ZFIL*"}
	,{3,"ZFF"}
	,{2,"ZI*"}
	,{4,"ZLEN*"}
	,{4,"ZLIS*"}

	,{8,"ZNODELAY"} /* ZNO* have to be spelled out fully */
	,{9,"ZNOFILTER"}
	,{5,"ZNOFF"}
	,{7,"ZNOWRAP"}

	,{4,"ZWID*"}
	,{4,"ZWRA*"}
};
/* Offset of letter in dev_param_names */
LITDEF	unsigned char dev_param_index[27] =
{
/*	A    B    C    D    E    F    G    H    I    J    K    L    M    N   */
	0,   5,   9,   26,  34,  47,  59,  61,  65,  71,  71,  71,  79,  82,
/*	O    P    Q    R    S    T    U    V    W    X    Y    Z    end	     */
	144, 149, 168, 169, 182, 200, 209, 215, 216, 231, 232, 233, 247
};
/* Offset of string within letter in dev_param_names */
/* maintained in conjunction with zshow_params.h   = offset in letter, letter  */
LITDEF zshow_index zshow_param_index[] =
{
/*	ALLO     BLOC    COMMAND   CONV     CTRA     DELE   DEST     EBCD     EDIT    EXCE     EXTE     FIELD   FIL     FIXED  */
	{2,0},   {2,1},   {9,2},  {12,2},  {16,2},  {1,3},  {3,3},  {1,4},   {4,4},  {9,4},   {11,4},  {2,5},  {5,5},  {8,5},
/*  	HOST    ICHSET   INDEPENDENT  INSE     LAB */
	{3,7},	{0,8},   {2,8},      {4,8},   {1,11},
/*	LENG     NOCENE   NODEST    NOECHO   NOEDIT   NOESCA    NOHOST   NOINSE     */
	{3,11},  {7,13},  {10,13},  {15,13}, {17,13}, {19,13}, {27,13}, {29,13},
/*	NOPAST   NOREADS  NOTTSY   NOTYPE   NOWRAP   OCHSET   PAD     PARSE   PAST     PRMMBX   RCHK    */
	{35,13}, {40,13}, {51,13}, {53,13}, {59,13}, {1,14},  {8,15}, {11,15}, {13,15}, {17,15}, {1,17},
/*      READ     READS	  REC      SHAR     SHELL    STDERR   TERM     TTSY     TYPE    UIC      WAIT     WCHK    WIDTH   WRITE  */
	{2,17},  {4,17},  {5,17},  {5,18},  {7,18},  {15,18},  {1,19},  {6,19},  {8,19}, {1,20},  {2,22},  {4,22}, {6,22}, {10,22}
};

int deviceparameters(oprtype *c, char who_calls)
{
	oprtype 	x;
	oprtype 	cat_list[n_iops];
	int		cat_cnt;
	mval		tmpmval;
	triple		*ref, *parm;
	int		n;
	int		status;
	char		parstr[MAXDEVPARLEN];
	char		*parptr;
	boolean_t	is_parm_list;
	boolean_t	parse_warn;

	static readonly unsigned char dev_param_data[] =
	{
		 iop_after
		,iop_allocation	,iop_allocation
		,iop_append
		,iop_attach

		,iop_bigrecord
		,iop_blocksize ,iop_blocksize
		,iop_burst

		,iop_canctlo, iop_canctlo
		,iop_canonical
		,iop_cenable
		,iop_characteristic
		,iop_chset
		,iop_clearscreen
		,iop_cli
		,iop_command ,iop_command
		,iop_connect
		,iop_contiguous
		,iop_convert
		,iop_copies
		,iop_cpulimit
		,iop_ctrap ,iop_ctrap

		,iop_delete ,iop_delete
		,iop_delimiter
		,iop_destroy ,iop_destroy
		,iop_detach
		,iop_doublespace
		,iop_downscroll

		,iop_ebcdic ,iop_ebcdic
		,iop_echo
		,iop_editing ,iop_editing
		,iop_eraseline
		,iop_erasetape
		,iop_escape
		,iop_exception ,iop_exception
		,iop_extension ,iop_extension
		,iop_extgap

		,iop_field ,iop_field ,iop_field
		,iop_fifo, iop_fifo
		,iop_filter
		,iop_firstpage
		,iop_fixed ,iop_fixed
		,iop_flag
		,iop_flush
		,iop_form

		,iop_g_protection, iop_g_protection

		,iop_header
		,iop_hold
		,iop_hostsync, iop_hostsync

		,iop_ipchset
		,iop_independent ,iop_independent
		,iop_insert ,iop_insert
		,iop_ioerror

		,iop_label
		,iop_lastpage
		,iop_length ,iop_length
		,iop_listen
		,iop_logfile
		,iop_logqueue
		,iop_lowercase

		,iop_m
		,iop_morereadtime
		,iop_mount

		,iop_name
		,iop_newversion
		,iop_next
		,iop_nobigrecord
		,iop_noburst
		,iop_nocanonical
		,iop_nocenable ,iop_nocenable
		,iop_noconvert
		,iop_nodelimiter
		,iop_nodestroy ,iop_nodestroy
		,iop_nodoublespace
		,iop_noebcdic
		,iop_noecho ,iop_noecho
		,iop_noediting ,iop_noediting
		,iop_noescape ,iop_noescape
		,iop_inhextgap
		,iop_nofilter
		,iop_nofixed
		,iop_noflag
		,iop_noheader
		,iop_nohold
		,iop_nohostsync ,iop_nohostsync
		,iop_noinsert ,iop_noinsert
		,iop_nolabel
		,iop_nolowercase
		,iop_nonotify
		,iop_page
		,iop_nopassall
		,iop_nopasthru
		,iop_noprint
		,iop_nordcheckdata
		,iop_noreadonly ,iop_noreadonly
		,iop_noreadsync
		,iop_norestart
		,iop_inhretry
		,iop_nosequential
		,iop_nostream
		,iop_note
		,iop_noterminator
		,iop_notify
		,iop_notrailer
		,iop_notruncate
		,iop_nottsync ,iop_nottsync
		,iop_notypeahead ,iop_notypeahead
		,iop_nourgent
		,iop_nowait
		,iop_nowtcheckdata
		,iop_nowrap ,iop_nowrap ,iop_nowrap
		,iop_nowriteonly
		,iop_nl

		,iop_o_protection
		,iop_opchset
		,iop_operator
		,iop_noinsert
		,iop_o_protection

		,iop_p1
		,iop_p2
		,iop_p3
		,iop_p4
		,iop_p5
		,iop_p6
		,iop_p7
		,iop_p8
		,iop_pad
		,iop_page
		,iop_parse ,iop_parse
		,iop_passall
		,iop_pasthru
		,iop_priority
		,iop_print
		,iop_prmmbx ,iop_prmmbx
		,iop_o_protection

		,iop_queue

		,iop_rdcheckdata ,iop_rdcheckdata
		,iop_readonly ,iop_readonly
		,iop_readsync
		,iop_recordsize
		,iop_remote
		,iop_rename
		,iop_restart
		,iop_retry
		,iop_rewind
		,iop_rfa
		,iop_rfm

		,iop_s_protection
		,iop_sequential
		,iop_setup
		,iop_shared ,iop_shared, iop_shared
		,iop_shell ,iop_shell
		,iop_skipfile
		,iop_socket
		,iop_space
		,iop_spool
		,iop_stream, iop_stream
		,iop_stderr, iop_stderr
		,iop_submit
		,iop_s_protection

		,iop_terminator, iop_terminator
		,iop_tmpmbx
		,iop_trailer
		,iop_truncate
		,iop_ttsync ,iop_ttsync
		,iop_typeahead ,iop_typeahead

		,iop_uic ,iop_uic
		,iop_unload
		,iop_upscroll
	        ,iop_urgent
		,iop_user

		,iop_nofixed

		,iop_w_protection
		,iop_wait ,iop_wait
		,iop_wtcheckdata ,iop_wtcheckdata
		,iop_width ,iop_width
		,iop_w_protection
		,iop_wrap ,iop_wrap
		,iop_writeonly
		,iop_writelb
		,iop_writeof
		,iop_writeonly
		,iop_writetm

		,iop_x

		,iop_y

		,iop_zbfsize
		,iop_zdelay
		,iop_exception /* for ZEXCEPTION; ZEXC* is a synonym for EXC* */
		,iop_filter /* for ZFILTER; ZFIL* is a synonym for FIL* */
		,iop_zff
		,iop_zibfsize
		,iop_length /* for ZLENGTH; ZLEN* is a synonym for LE* and LENG */
		,iop_zlisten

		,iop_znodelay
		,iop_nofilter /* for ZNOFILTER; ZNOFILTER is a synonym for NOFIL* */
		,iop_znoff
		,iop_nowrap /* for ZNOWRAP; ZNOWRAP is a synonym for NOWR, NOWRA*, NOWRAP */
		,iop_width /* for ZWIDTH; ZWID* is a synonym for WI*, WIDTH */
		,iop_wrap /* for ZWRAP; ZWRA* is a synonym for WR, and WRA* */
	} ;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert((SIZEOF(dev_param_names) / SIZEOF(nametabent) == dev_param_index[26]));
	assert((SIZEOF(dev_param_data) / SIZEOF(unsigned char)) == dev_param_index[26]);
	is_parm_list = (TK_LPAREN == TREF(window_token));
	if (is_parm_list)
		advancewindow();
	cat_cnt = 0;
	parptr = parstr;
	parse_warn = FALSE;
	for (;;)
	{
		if ((TK_IDENT != TREF(window_token))
			|| (0
			 > (n = namelook(dev_param_index, dev_param_names, (TREF(window_ident)).addr, (TREF(window_ident)).len))))
		{	/* NOTE assignment above */
			STX_ERROR_WARN(ERR_DEVPARUNK);	/* sets "parse_warn" to TRUE */
			break;
		}
		n = dev_param_data[n];
		if (!(dev_param_control[n].valid_with & who_calls))
		{
			STX_ERROR_WARN(ERR_DEVPARINAP);	/* sets "parse_warn" to TRUE */
			break;
		}
		advancewindow();
		*parptr++ = n;
		if (io_params_size[n])
		{
			if (TK_EQUAL != TREF(window_token))
			{
				STX_ERROR_WARN(ERR_DEVPARVALREQ);	/* sets "parse_warn" to TRUE */
				break;
			}
			advancewindow();
			if (EXPR_FAIL == expr(&x, MUMPS_EXPR))
				return FALSE;
			assert(TRIP_REF == x.oprclass);
			if (OC_LIT == x.oprval.tref->opcode)
			{
				/* check to see if this string could overflow (5 is a int4 word plus a parameter code for
				   safety)  Must check before cvtparm, due to the fact that tmpmval could otherwise
				   be garbage collected by a later putstr
				*/
				if (parptr - parstr + x.oprval.tref->operand[0].oprval.mlit->v.str.len + 5 > SIZEOF(parstr))
				{
					cat_list[cat_cnt++] = put_str(parstr, INTCAST(parptr - parstr));
					parptr = parstr;
				}
				assert(MLIT_REF == x.oprval.tref->operand[0].oprclass);
				status = cvtparm(n, &x.oprval.tref->operand[0].oprval.mlit->v, &tmpmval);
				if (status)
				{
					stx_error(status);
					return FALSE;
				}
				memcpy(parptr, tmpmval.str.addr, tmpmval.str.len);
				parptr += tmpmval.str.len;
			} else
			{
				if (parptr > parstr)
				{
					cat_list[cat_cnt++] = put_str(parstr, INTCAST(parptr - parstr));
					parptr = parstr;
				}
				ref = newtriple(OC_CVTPARM);
				ref->operand[0] = put_ilit(n);
				ref->operand[1] = x;
				cat_list[cat_cnt++] = put_tref(ref);
			}
		}
		if (!is_parm_list)
			break;
		if (TK_COLON == TREF(window_token))
		{
			advancewindow();
			continue;
		}
		else if (TK_RPAREN == TREF(window_token))
		{
			advancewindow();
			break;
		}
		stx_error(ERR_RPARENMISSING);
		return FALSE;
	}
	if (parse_warn)
	{	/* Parse the remaining arguments until the corresponding RIGHT-PAREN or SPACE or EOL is reached */
		if (!parse_until_rparen_or_space())
			return FALSE;
		if (TK_RPAREN == TREF(window_token))
			advancewindow();
	}
	*parptr++ = iop_eol;
	cat_list[cat_cnt++] = put_str(parstr,INTCAST(parptr - parstr));
	if (cat_cnt <= 1)
		*c = cat_list[0];
	else
	{
		ref = newtriple(OC_CAT);
		ref->operand[0] = put_ilit(cat_cnt + 1);
		*c = put_tref(ref);
		for (n = 0 ; n < cat_cnt ; n++)
		{
			parm = newtriple(OC_PARAMETER);
			ref->operand[1] = put_tref(parm);
			ref = parm;
			ref->operand[0] = cat_list[n];
		}
	}
	return TRUE;
}
