Exemple #1
0
bool gvcmx_order(void)
{
	mval v;

	gvcmz_doop(CMMS_Q_ORDER, CMMS_R_ORDER, &v);
	if (MV_FORCE_INT(&v))
		return TRUE;
	else
		return FALSE;
}
void ztrap_save_ctxt(void)
{
	int level;
	error_def(ERR_STACKOFLOW);
	error_def(ERR_STACKCRIT);

	level = dollar_zlevel();
	if (level == MV_FORCE_INT(&ztrap_pop2level))
		return;

	PUSH_MV_STENT(MVST_MSAV);
	mv_chain->mv_st_cont.mvs_msav.v = ztrap_pop2level;
	mv_chain->mv_st_cont.mvs_msav.addr = &ztrap_pop2level;
	MV_FORCE_MVAL(&ztrap_pop2level, level);
	return;
}
Exemple #3
0
void coerce(oprtype *a,unsigned short new_type)
{

	mliteral *lit;
	opctype conv, old_op;
	triple *ref, *coerc;

	assert (new_type == OCT_MVAL || new_type == OCT_MINT || new_type == OCT_BOOL);
	assert (a->oprclass == TRIP_REF);
	ref = a->oprval.tref;
	old_op = ref->opcode;
	if (new_type & oc_tab[old_op].octype)
		return;
	if (old_op == OC_COMVAL || old_op == OC_COMINT)
	{
		dqdel(ref,exorder);
		ref = ref->operand[0].oprval.tref;
		old_op = ref->opcode;
		if (new_type & oc_tab[old_op].octype)
			return;
	}
	else if (old_op == OC_LIT && new_type == OCT_MINT)
	{
		lit = ref->operand[0].oprval.mlit;
		if (!(++lit->rt_addr))
			dqdel(lit, que);
		ref->opcode = OC_ILIT;
		ref->operand[0].oprclass = ILIT_REF;
		ref->operand[0].oprval.ilit = MV_FORCE_INT(&(lit->v));
		return;
	}
	if (new_type == OCT_BOOL)
		conv = OC_COBOOL;
	else if (new_type == OCT_MINT)
		conv = OC_COMINT;
	else
		conv = OC_COMVAL;
	coerc = newtriple(conv);
	coerc->operand[0] = put_tref(ref);
	*a = put_tref(coerc);
	return;

}
Exemple #4
0
int mval2fao(
	char		*message,		/* text of message in fao format */
	va_list		pfao,			/* argument list of caller */
	UINTPTR_T	*outparm,		/* array of resulting fao parameters */
	int		mcount, int fcount,	/* mvalcount and faocount */
	char		*bufbase, char *buftop)	/* buffer space for !AC and !AS */
{
	char		*buf;
	int		i, parmcnt, num;
	mval		*fao;

	fao = va_arg(pfao, mval *);
	parmcnt = 0;
	buf = bufbase;
	for ( ; mcount && parmcnt < fcount; )
	{
		MV_FORCE_DEFINED(fao);
		while (*message != '!')
			message++;
		for (i=0;(*++message > 47) && (*message < 58);i++)		/* a length for the fao parameter */
			;
		switch (*message++)
		{
			case '/':
			case '_':
			case '^':
			case '!':	break;
			case 'A':	MV_FORCE_STR(fao);
					switch(*message++)
					{
/* ascii counted string */			case 'C':
								if ((fao)->str.len > 256 || (fao)->str.len < 0)
									return -1;
								if (buf + (fao)->str.len + 1 >= buftop)
									return -1;
								*buf++ = (fao)->str.len;
								memcpy(buf, (fao)->str.addr, (fao)->str.len);
								buf += (fao)->str.len;
								break;
/* len,addr string, '.' filled */		case 'F':
/* len,addr string */				case 'D':
								if (parmcnt + 2 > fcount)
									return parmcnt;
								outparm[parmcnt++] = (unsigned int)(fao)->str.len;
								outparm[parmcnt++] = (UINTPTR_T)(fao)->str.addr;
								break;
/* ascii string descriptor */			case 'S':
								if (buf + sizeof(desc_struct) >= buftop)
									return -1;
								((desc_struct *)buf)->len = (fao)->str.len;
								((desc_struct *)buf)->addr = (fao)->str.addr;
								outparm[parmcnt++] = (UINTPTR_T)buf;
								buf += sizeof(desc_struct);
								break;
						default:	return -1;
					}
					fao = va_arg(pfao, mval *);
					mcount--;
					break;
/* octal number */	case 'O':
/* hex number */	case 'X':
/* signed number */	case 'S':
					num = MV_FORCE_INT(fao);
					switch(*message++)
					{
						case 'B':	outparm[parmcnt++] = (UINTPTR_T)num;
								break;
						case 'W':	outparm[parmcnt++] = (UINTPTR_T)num;
								break;
						case 'L':	outparm[parmcnt++] = (UINTPTR_T)num;
								break;
						default:	return -1;
					}
					fao = va_arg(pfao, mval *);
					mcount--;
					break;
/* zero filled num */	case 'Z':
/* unsigned num */	case 'U':
					num = MV_FORCE_INT(fao);
					switch(*message++)
					{
						case 'B':	outparm[parmcnt++] = (UINTPTR_T)num;
								break;
						case 'W':	outparm[parmcnt++] = (UINTPTR_T)num;
								break;
						case 'L':	outparm[parmcnt++] = (UINTPTR_T)num;
								break;
						default:	return -1;
					}
					fao = va_arg(pfao, mval *);
					mcount--;
					break;
			default:	return -1;
		}
	}
	return parmcnt;
}
Exemple #5
0
void op_svput(int varnum, mval *v)
{
	int	i, ok, state;
	char	*vptr;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	switch (varnum)
	{
		case SV_X:
			MV_FORCE_NUM(v);
			io_curr_device.out->dollar.x = (short)MV_FORCE_INT(v);
			if ((short)(io_curr_device.out->dollar.x) < 0)
				io_curr_device.out->dollar.x = 0;
			break;
		case SV_Y:
			MV_FORCE_NUM(v);
			io_curr_device.out->dollar.y = (short)MV_FORCE_INT(v);
			if ((short)(io_curr_device.out->dollar.y) < 0)
				io_curr_device.out->dollar.y = 0;
			break;
		case SV_ZCOMPILE:
			MV_FORCE_STR(v);
			if ((TREF(dollar_zcompile)).addr)
				free ((TREF(dollar_zcompile)).addr);
			(TREF(dollar_zcompile)).addr = (char *)malloc(v->str.len);
			memcpy((TREF(dollar_zcompile)).addr, v->str.addr, v->str.len);
			(TREF(dollar_zcompile)).len = v->str.len;
			break;
		case SV_ZSTEP:
			MV_FORCE_STR(v);
			op_commarg(v,indir_linetail);
			op_unwind();
			dollar_zstep = *v;
			break;
		case SV_ZGBLDIR:
			MV_FORCE_STR(v);
			if ((dollar_zgbldir.str.len != v->str.len)
			    || memcmp(dollar_zgbldir.str.addr, v->str.addr, dollar_zgbldir.str.len))
			{
				if (0 == v->str.len)
				{
					/* set $zgbldir="" */
					dpzgbini();
					gd_header = NULL;
				} else
				{
					gd_header = zgbldir(v);
					/* update the gd_map */
					SET_GD_MAP;
					dollar_zgbldir.str.len = v->str.len;
					dollar_zgbldir.str.addr = v->str.addr;
					s2pool(&dollar_zgbldir.str);
				}
				if (NULL != gv_currkey)
				{
					gv_currkey->base[0] = '\0';
					gv_currkey->prev = gv_currkey->end = 0;
				} else if (NULL != gd_header)
					gvinit();
				if (NULL != gv_target)
					gv_target->clue.end = 0;
			}
			break;
		case SV_ZMAXTPTIME:
			dollar_zmaxtptime = mval2i(v);
			break;
		case SV_ZROUTINES:
			MV_FORCE_STR(v);
			/* The string(v) should be parsed and loaded before setting $zroutines
			 * to retain the old value in case errors occur while loading */
			zro_load(&v->str);
			if ((TREF(dollar_zroutines)).addr)
				free ((TREF(dollar_zroutines)).addr);
			(TREF(dollar_zroutines)).addr = (char *)malloc(v->str.len);
			memcpy((TREF(dollar_zroutines)).addr, v->str.addr, v->str.len);
			(TREF(dollar_zroutines)).len = v->str.len;
			break;
		case SV_ZSOURCE:
			MV_FORCE_STR(v);
			dollar_zsource.mvtype = MV_STR;
			dollar_zsource.str = v->str;
			break;
		case SV_ZTRAP:
#			ifdef GTM_TRIGGER
			if (0 < gtm_trigger_depth)
				rts_error(VARLSTCNT(1) ERR_NOZTRAPINTRIG);
#			endif
			MV_FORCE_STR(v);
			if (ztrap_new)
				op_newintrinsic(SV_ZTRAP);
			dollar_ztrap.mvtype = MV_STR;
			dollar_ztrap.str = v->str;
			/* Setting either $ZTRAP or $ETRAP to empty causes any current error trapping to be canceled */
			if (!v->str.len)
			{
				dollar_etrap.mvtype = MV_STR;
				dollar_etrap.str = v->str;
				ztrap_explicit_null = TRUE;
			} else /* Ensure that $ETRAP and $ZTRAP are not both active at the same time */
			{
				ztrap_explicit_null = FALSE;
				if (dollar_etrap.str.len > 0)
					gtm_newintrinsic(&dollar_etrap);
			}
			if (ztrap_form & ZTRAP_POP)
				ztrap_save_ctxt();
			if (tp_timeout_deferred && !dollar_zininterrupt)
				/* A tp timeout was deferred. Now that $ETRAP is no longer in effect and no job interrupt is in
				 * effect, the timeout need no longer be deferred and can be recognized.
				 */
				tptimeout_set(0);
			break;
		case SV_ZSTATUS:
			MV_FORCE_STR(v);
			dollar_zstatus.mvtype = MV_STR;
			dollar_zstatus.str = v->str;
			break;
		case SV_PROMPT:
			MV_FORCE_STR(v);
			MV_FORCE_LEN_STRICT(v); /* Ensure that direct mode prompt will not have BADCHARs,
						 * otherwise the BADCHAR error may fill up the filesystem
						 */
			if (v->str.len <= SIZEOF_prombuf)
				(TREF(gtmprompt)).len = v->str.len;
			else if (!gtm_utf8_mode)
				(TREF(gtmprompt)).len = SIZEOF_prombuf;
#			ifdef UNICODE_SUPPORTED
			else
			{
				UTF8_LEADING_BYTE(v->str.addr + SIZEOF_prombuf, v->str.addr, vptr);
				(TREF(gtmprompt)).len = INTCAST(vptr - v->str.addr);
			}
#			endif
			memcpy((TREF(gtmprompt)).addr, v->str.addr, (TREF(gtmprompt)).len);
			break;
		case SV_ECODE:
			MV_FORCE_STR(v);
			if (v->str.len)
			{
				/* Format must be like ,Mnnn,Mnnn,Zxxx,Uxxx,
				 * Mnnn are ANSI standard error codes
				 * Zxxx are implementation-specific codes
				 * Uxxx are end-user defined codes
				 * Note that there must be commas at the start and at the end
				 */
				for (state = 2, i = 0; (i < v->str.len) && (state <= 2); i++)
				{
					switch(state)
					{
						case 2: state = (v->str.addr[i] == ',') ? 1 : 101;
							break;
						case 1: state = ((v->str.addr[i] == 'M') ||
								 (v->str.addr[i] == 'U') ||
								 (v->str.addr[i] == 'Z')) ? 0 : 101;
							break;
						case 0: state = (v->str.addr[i] == ',') ? 1 : 0;
							break;
					}
				}
				/* The above check would pass strings like ","
				 * so double-check that there are at least three characters
				 * (starting comma, ending comma, and something in between)
				 */
				if ((state != 1) || (v->str.len < 3))
				{
					/* error, ecode = M101 */
					rts_error(VARLSTCNT(4) ERR_INVECODEVAL, 2, v->str.len, v->str.addr);
				}
			}
			if (v->str.len > 0)
			{
				ecode_add(&v->str);
				rts_error(VARLSTCNT(2) ERR_SETECODE, 0);
			} else
			{
				NULLIFY_DOLLAR_ECODE;	/* reset $ECODE related variables to correspond to $ECODE = NULL state */
				NULLIFY_ERROR_FRAME;	/* we are no more in error-handling mode */
				if (tp_timeout_deferred && !dollar_zininterrupt)
					/* A tp timeout was deferred. Now that we are clear of error handling and no job interrupt
					 * is in process, allow the timeout to be recognized.
					 */
					tptimeout_set(0);
			}
			break;
		case SV_ETRAP:
			MV_FORCE_STR(v);
			dollar_etrap.mvtype = MV_STR;
			dollar_etrap.str = v->str;
			/* Setting either $ZTRAP or $ETRAP to empty causes any current error trapping to be canceled */
			if (!v->str.len)
			{
				dollar_ztrap.mvtype = MV_STR;
				dollar_ztrap.str = v->str;
			} else if (dollar_ztrap.str.len > 0)
			{	/* Ensure that $ETRAP and $ZTRAP are not both active at the same time */
				assert(FALSE == ztrap_explicit_null);
				gtm_newintrinsic(&dollar_ztrap);
			}
			ztrap_explicit_null = FALSE;
			break;
		case SV_ZERROR:
			MV_FORCE_STR(v);
			dollar_zerror.mvtype = MV_STR;
			dollar_zerror.str = v->str;
			break;
		case SV_ZYERROR:
			MV_FORCE_STR(v);
			dollar_zyerror.mvtype = MV_STR;
			dollar_zyerror.str = v->str;
			break;
		case SV_SYSTEM:
			assert(FALSE);
			rts_error(VARLSTCNT(4) ERR_SYSTEMVALUE, 2, v->str.len, v->str.addr);
			break;
		case SV_ZDIR:
			setzdir(v, NULL); 	/* change directory to v */
			getzdir(); 		/* update dollar_zdir with current working directory */
			break;
		case SV_ZINTERRUPT:
			MV_FORCE_STR(v);
			dollar_zinterrupt.mvtype = MV_STR;
			dollar_zinterrupt.str = v->str;
			break;
		case SV_ZDATE_FORM:
			MV_FORCE_NUM(v);
			TREF(zdate_form) = (short)MV_FORCE_INT(v);
			break;
		case SV_ZTEXIT:
			MV_FORCE_STR(v);
			dollar_ztexit.mvtype = MV_STR;
			dollar_ztexit.str = v->str;
			/* Coercing $ZTEXIT to boolean at SET command is more efficient than coercing before each
			 * rethrow at TR/TRO. Since we want to maintain dollar_ztexit as a string, coercion should
			 * not be performed on dollar_ztext, but on a temporary (i.e. parameter v)
			 */
			dollar_ztexit_bool = MV_FORCE_BOOL(v);
			break;
		case SV_ZQUIT:
			dollar_zquit_anyway = MV_FORCE_BOOL(v);
			break;
		case SV_ZTVALUE:
#			ifdef GTM_TRIGGER
			assert(!dollar_tlevel || (tstart_trigger_depth <= gtm_trigger_depth));
			if (!dollar_tlevel || (tstart_trigger_depth == gtm_trigger_depth))
				rts_error(VARLSTCNT(4) ERR_SETINTRIGONLY, 2, RTS_ERROR_TEXT("$ZTVALUE"));
			if (dollar_ztriggerop != &gvtr_cmd_mval[GVTR_CMDTYPE_SET])
				rts_error(VARLSTCNT(4) ERR_SETINSETTRIGONLY, 2, RTS_ERROR_TEXT("$ZTVALUE"));
			assert(0 < gtm_trigger_depth);
			memcpy(dollar_ztvalue, v, SIZEOF(mval));
			dollar_ztvalue->mvtype &= ~MV_ALIASCONT;	/* Make sure to shut off alias container flag on copy */
			assert(NULL != ztvalue_changed_ptr);
			*ztvalue_changed_ptr = TRUE;
			break;
#			else
			rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
#			endif
		case SV_ZTWORMHOLE:
#			ifdef GTM_TRIGGER
			MV_FORCE_STR(v);
			/* See jnl.h for why MAX_ZTWORMHOLE_SIZE should be less than minimum alignsize */
			assert(MAX_ZTWORMHOLE_SIZE < (JNL_MIN_ALIGNSIZE * DISK_BLOCK_SIZE));
			if (MAX_ZTWORMHOLE_SIZE < v->str.len)
				rts_error(VARLSTCNT(4) ERR_ZTWORMHOLE2BIG, 2, v->str.len, MAX_ZTWORMHOLE_SIZE);
			dollar_ztwormhole.mvtype = MV_STR;
			dollar_ztwormhole.str = v->str;
			break;
#			else
			rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
#			endif
		case SV_ZTSLATE:
#			ifdef GTM_TRIGGER
			assert(!dollar_tlevel || (tstart_trigger_depth <= gtm_trigger_depth));
			if (!dollar_tlevel || (tstart_trigger_depth == gtm_trigger_depth))
				rts_error(VARLSTCNT(4) ERR_SETINTRIGONLY, 2, RTS_ERROR_TEXT("$ZTSLATE"));
			assert(0 < gtm_trigger_depth);
			MV_FORCE_DEFINED(v);
			memcpy((char *)&dollar_ztslate, v, SIZEOF(mval));
			dollar_ztslate.mvtype &= ~MV_ALIASCONT;	/* Make sure to shut off alias container flag on copy */
			break;
#			else
			rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
#			endif
		default:
			GTMASSERT;
	}
	return;
}
Exemple #6
0
void op_svput(int varnum, mval *v)
{
    int		i, ok, state;
    error_def(ERR_UNIMPLOP);
    error_def(ERR_TEXT);
    error_def(ERR_INVECODEVAL);
    error_def(ERR_SETECODE);
    error_def(ERR_SYSTEMVALUE);

    switch (varnum)
    {
    case SV_X:
        MV_FORCE_NUM(v);
        io_curr_device.out->dollar.x = (short)MV_FORCE_INT(v);
        if ((short)(io_curr_device.out->dollar.x) < 0)
            io_curr_device.out->dollar.x = 0;
        break;
    case SV_Y:
        MV_FORCE_NUM(v);
        io_curr_device.out->dollar.y = (short)MV_FORCE_INT(v);
        if ((short)(io_curr_device.out->dollar.y) < 0)
            io_curr_device.out->dollar.y = 0;
        break;
    case SV_ZCOMPILE:
        MV_FORCE_STR(v);
        if (dollar_zcompile.addr)
            free (dollar_zcompile.addr);
        dollar_zcompile.addr = (char *)malloc(v->str.len);
        memcpy (dollar_zcompile.addr, v->str.addr, v->str.len);
        dollar_zcompile.len = v->str.len;
        break;
    case SV_ZSTEP:
        MV_FORCE_STR(v);
        op_commarg(v,indir_linetail);
        op_unwind();
        dollar_zstep = *v;
        break;
    case SV_ZGBLDIR:
        MV_FORCE_STR(v);
        if (!(dollar_zgbldir.str.len == v->str.len &&
                !memcmp(dollar_zgbldir.str.addr, v->str.addr,
                        dollar_zgbldir.str.len)))
        {
            if(v->str.len == 0)
            {
                /* set $zgbldir="" */
                dpzgbini();
                gd_header = NULL;
            } else
            {
                gd_header = zgbldir(v);
                dollar_zgbldir.str.len = v->str.len;
                dollar_zgbldir.str.addr = v->str.addr;
                s2pool(&dollar_zgbldir.str);
            }
            if (gv_currkey)
                gv_currkey->base[0] = 0;
            if (gv_target)
                gv_target->clue.end = 0;
        }
        break;
    case SV_ZMAXTPTIME:
        dollar_zmaxtptime = mval2i(v);
        break;
    case SV_ZROUTINES:
        MV_FORCE_STR(v);
        /* The string(v) should be parsed and loaded before setting $zroutines
         * to retain the old value in case errors occur while loading */
        zro_load(&v->str);
        if (dollar_zroutines.addr)
            free (dollar_zroutines.addr);
        dollar_zroutines.addr = (char *)malloc(v->str.len);
        memcpy (dollar_zroutines.addr, v->str.addr, v->str.len);
        dollar_zroutines.len = v->str.len;
        break;
    case SV_ZSOURCE:
        MV_FORCE_STR(v);
        dollar_zsource = v->str;
        break;
    case SV_ZTRAP:
        MV_FORCE_STR(v);
        if (ztrap_new)
            op_newintrinsic(SV_ZTRAP);
        dollar_ztrap.mvtype = MV_STR;
        dollar_ztrap.str = v->str;
        /* Setting either $ZTRAP or $ETRAP to empty causes any current error trapping to be canceled */
        if (!v->str.len)
        {
            dollar_etrap.mvtype = MV_STR;
            dollar_etrap.str = v->str;
            ztrap_explicit_null = TRUE;
        } else /* Ensure that $ETRAP and $ZTRAP are not both active at the same time */
        {
            ztrap_explicit_null = FALSE;
            if (dollar_etrap.str.len > 0)
                gtm_newintrinsic(&dollar_etrap);
        }
        if (ztrap_form & ZTRAP_POP)
            ztrap_save_ctxt();
        break;
    case SV_ZSTATUS:
        MV_FORCE_STR(v);
        dollar_zstatus.mvtype = MV_STR;
        dollar_zstatus.str = v->str;
        break;
    case SV_PROMPT:
        MV_FORCE_STR(v);
        gtmprompt.len = v->str.len < sizeof(prombuf) ? v->str.len : sizeof(prombuf);
        memcpy(gtmprompt.addr,v->str.addr,gtmprompt.len);
        break;
    case SV_ECODE:
        MV_FORCE_STR(v);
        if (v->str.len)
        {
            /* Format must be like ,Mnnn,Mnnn,Zxxx,Uxxx,
             * Mnnn are ANSI standard error codes
             * Zxxx are implementation-specific codes
             * Uxxx are end-user defined codes
             * Note that there must be commas at the start and at the end
             */
            for (state = 2, i = 0; (i < v->str.len) && (state <= 2); i++)
            {
                switch(state)
                {
                case 2:
                    state = (v->str.addr[i] == ',') ? 1 : 101;
                    break;
                case 1:
                    state = ((v->str.addr[i] == 'M') ||
                             (v->str.addr[i] == 'U') ||
                             (v->str.addr[i] == 'Z')) ? 0 : 101;
                    break;
                case 0:
                    state = (v->str.addr[i] == ',') ? 1 : 0;
                    break;
                }
            }
            /* The above check would pass strings like ","
             * so double-check that there are at least three characters
             * (starting comma, ending comma, and something in between)
             */
            if ((state != 1) || (v->str.len < 3))
            {
                /* error, ecode = M101 */
                rts_error(VARLSTCNT(4) ERR_INVECODEVAL, 2, v->str.len, v->str.addr);
            }
        }
        if (v->str.len > 0)
        {
            ecode_add(&v->str);
            rts_error(VARLSTCNT(2) ERR_SETECODE, 0);
        } else
        {
            NULLIFY_DOLLAR_ECODE;	/* reset $ECODE related variables to correspond to $ECODE = NULL state */
            NULLIFY_ERROR_FRAME;	/* we are no more in error-handling mode */
        }
        break;
    case SV_ETRAP:
        MV_FORCE_STR(v);
        dollar_etrap.mvtype = MV_STR;
        dollar_etrap.str = v->str;
        /* Setting either $ZTRAP or $ETRAP to empty causes any current error trapping to be canceled */
        if (!v->str.len)
        {
            dollar_ztrap.mvtype = MV_STR;
            dollar_ztrap.str = v->str;
        } else if (dollar_ztrap.str.len > 0)
        {   /* Ensure that $ETRAP and $ZTRAP are not both active at the same time */
            assert(FALSE == ztrap_explicit_null);
            gtm_newintrinsic(&dollar_ztrap);
        }
        ztrap_explicit_null = FALSE;
        break;
    case SV_ZERROR:
        MV_FORCE_STR(v);
        dollar_zerror.mvtype = MV_STR;
        dollar_zerror.str = v->str;
        break;
    case SV_ZYERROR:
        MV_FORCE_STR(v);
        dollar_zyerror.mvtype = MV_STR;
        dollar_zyerror.str = v->str;
        break;
    case SV_SYSTEM:
        ok = 1;
        if (!(v->mvtype & MV_STR))
            ok = 0;
        if (ok && v->str.addr[0] != '4')
            ok = 0;
        if (ok && v->str.addr[1] != '7')
            ok = 0;
        if ((' ' != v->str.addr[2]) && !ispunct(v->str.addr[2]))
            ok = 0;
        if (ok)
            dollar_system.str = v->str;
        else
            rts_error(VARLSTCNT(4) ERR_SYSTEMVALUE, 2, v->str.len, v->str.addr);
        break;
    case SV_ZDIR:
        setzdir(v, NULL); /* change directory to v */
        getzdir(); /* update dollar_zdir with current working directory */
        break;
    case SV_ZINTERRUPT:
        MV_FORCE_STR(v);
        dollar_zinterrupt.mvtype = MV_STR;
        dollar_zinterrupt.str = v->str;
        break;
    case SV_ZDATE_FORM:
        MV_FORCE_NUM(v);
        zdate_form = (short)MV_FORCE_INT(v);
        break;
    case SV_ZTEXIT:
        MV_FORCE_STR(v);
        dollar_ztexit.mvtype = MV_STR;
        dollar_ztexit.str = v->str;
        /* Coercing $ZTEXIT to boolean at SET command is more efficient than coercing before each
         * rethrow at TR/TRO. Since we want to maintain dollar_ztexit as a string, coercion should
         * not be performed on dollar_ztext, but on a temporary (i.e. parameter v) */
        dollar_ztexit_bool = MV_FORCE_BOOL(v);
        break;
    default:
        GTMASSERT;
    }
    return;
}
Exemple #7
0
void trigger_delete_all(void)
{
	int			count;
	char			count_str[MAX_DIGITS_IN_INT + 1];
	sgmnt_addrs		*csa;
	mval			curr_gbl_name;
	int			cycle;
	mstr			gbl_name;
	mname_entry		gvent;
	gv_namehead		*hasht_tree, *gvt;
	mval			*mv_count_ptr;
	mval			*mv_cycle_ptr;
	mval			mv_indx;
	gd_region		*reg;
	int			reg_indx;
	int4			result;
	char			save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)];
	gv_key			*save_gv_currkey;
	gd_region		*save_gv_cur_region;
	gv_namehead		*save_gv_target;
	sgm_info		*save_sgm_info_ptr;
	int			trig_indx;
	mval			trigger_cycle;
	mval			trigger_count;
	mval			val;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(0 < dollar_tlevel);
	/* Before we delete any triggers, verify that none of the triggers have been fired in this transaction. If they have,
	 * this creates an un-commitable transaction that will end in a TPFAIL error. Since that error indicates database
	 * damage, we'd rather detect this avoidable condition and give a descriptive error instead (TRIGMODINTP).
	 */
	for (gvt = gv_target_list; NULL != gvt; gvt = gvt->next_gvnh)
	{
		if (gvt->trig_local_tn == local_tn)
			rts_error(VARLSTCNT(1) ERR_TRIGMODINTP);
	}
	SWITCH_TO_DEFAULT_REGION;
	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
	if (0 != gv_target->root)
	{
		/* kill ^#t("#TRHASH") */
		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH));
		gvcst_kill(TRUE);
		/* kill ^#t("#TNAME") */
		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME));
		gvcst_kill(TRUE);
	}
	for (reg_indx = 0, reg = gd_header->regions; reg_indx < gd_header->n_regions; reg_indx++, reg++)
	{
		if (!reg->open)
			gv_init_reg(reg);
		if (!reg->read_only)
		{
			gv_cur_region = reg;
			change_reg();
			csa = cs_addrs;
			SETUP_TRIGGER_GLOBAL;
			INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
			/* There might not be any ^#t in this region, so check */
			if (0 != gv_target->root)
			{	/* Kill all descendents of ^#t(trigvn, indx) where trigvn is any global with a trigger,
				 * but skip the "#XYZ" entries. setup ^#t(trigvn,"$") as the PREV key for op_gvorder
				 */
				BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STRLEN(LITERAL_MAXHASHVAL));
				TREF(gv_last_subsc_null) = FALSE; /* We know its not null, but prior state is unreliable */
				while (TRUE)
				{
					op_gvorder(&curr_gbl_name);
					/* quit:$length(curr_gbl_name)=0 */
					if (0 == curr_gbl_name.str.len)
						break;
					/* $get(^#t(curr_gbl_name,#COUNT)) */
					BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
						LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
					if (gvcst_get(&trigger_count))
					{
						mv_count_ptr = &trigger_count;
						count = MV_FORCE_INT(mv_count_ptr);
						/* $get(^#t(curr_gbl_name,#CYCLE)) */
						BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
							LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE));
						if (!gvcst_get(&trigger_cycle))
							assert(FALSE); /* Found #COUNT, there must be #CYCLE */
						mv_cycle_ptr = &trigger_cycle;
						cycle = MV_FORCE_INT(mv_cycle_ptr);
						/* kill ^#t(curr_gbl_name) */
						BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
						gvcst_kill(TRUE);
						cycle++;
						MV_FORCE_MVAL(&trigger_cycle, cycle);
						/* set ^#t(curr_gbl_name,#CYCLE)=trigger_cycle */
						SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(curr_gbl_name.str.addr, curr_gbl_name.str.len,
							LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE), trigger_cycle, result);
						assert(PUT_SUCCESS == result);
					} /* else there is no #COUNT, then no triggers, leave #CYCLE alone */
					/* get ready for op_gvorder() call for next trigger under ^#t */
					BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
				}
				csa->incr_db_trigger_cycle = TRUE;
				if (dollar_ztrigger_invoked)
				{	/* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction,
					 * on this region, will re-read. See trigger_update.c for a comment on why it is okay
					 * for db_dztrigger_cycle to be incremented more than once in the same transaction
					 */
					csa->db_dztrigger_cycle++;
				}
			}
		}
	}
	util_out_print_gtmio("All existing triggers deleted", FLUSH);
}
Exemple #8
0
int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index)
{
	int			count;
	mval			*mv_cnt_ptr;
	mval			mv_val;
	mval			*mv_val_ptr;
	int			num_len;
	char			*ptr1;
	int4			result;
	int4			retval;
	char			save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)];
	gv_key			*save_gv_currkey;
	stringkey		kill_hash, set_hash;
	int			sub_indx;
	char			tmp_trig_str[MAX_BUFF_SIZE];
	int4			trig_len;
	char			trig_name[MAX_TRIGNAME_LEN];
	int			trig_name_len;
	int			tmp_len;
	char			*tt_val[NUM_SUBS];
	uint4			tt_val_len[NUM_SUBS];
	mval			trigger_value;
	mval			trigger_index;
	mval			xecute_index;
	uint4			xecute_idx;
	uint4			used_trigvn_len;
	mval			val;
	char			val_str[MAX_DIGITS_IN_INT + 1];
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	mv_val_ptr = &mv_val;
	MV_FORCE_MVAL(&trigger_index, index);
	count = MV_FORCE_INT(trigger_count);
	/* build up array of values - needed for comparison in hash stuff */
	ptr1 = tmp_trig_str;
	memcpy(ptr1, trigvn, trigvn_len);
	ptr1 += trigvn_len;
	*ptr1++ = '\0';
	tmp_len = trigvn_len + 1;
	for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
	{
		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[sub_indx],
						 STRLEN(trigger_subs[sub_indx]));
		trig_len = gvcst_get(&trigger_value) ? trigger_value.str.len : 0;
		if (0 == trig_len)
		{
			tt_val[sub_indx] = NULL;
			tt_val_len[sub_indx] = 0;
			continue;
		}
		if (TRIGNAME_SUB == sub_indx)
		{
			trig_name_len = trig_len;
			assert(MAX_TRIGNAME_LEN >= trig_len);
			memcpy(trig_name, trigger_value.str.addr, trig_name_len);
			tt_val[sub_indx] = NULL;
			tt_val_len[sub_indx] = 0;
			continue;
		}
		tt_val[sub_indx] = ptr1;
		tt_val_len[sub_indx] = trig_len;
		tmp_len += trig_len;
		if (0 < trig_len)
		{
			if (MAX_BUFF_SIZE <= tmp_len)
				return VAL_TOO_LONG;
			memcpy(ptr1, trigger_value.str.addr, trig_len);
			ptr1 += trig_len;
		}
		*ptr1++ = '\0';
		tmp_len++;
	}
	/* Get trigger name, set hash value, and kill hash values from trigger before we delete it.
	 * The values will be used in clean ups associated with the deletion
	 */
	/* $get(^#t(GVN,trigger_index,"LHASH") for deletion in  cleanup_trigger_hash */
	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[LHASH_SUB],
		STRLEN(trigger_subs[LHASH_SUB]));
	if (gvcst_get(mv_val_ptr))
		kill_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
	else {
		util_out_print_gtmio("The LHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
		kill_hash.hash_code = 0;
	}
	/* $get(^#t(GVN,trigger_index,"BHASH") for deletion in  cleanup_trigger_hash */
	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[BHASH_SUB],
		STRLEN(trigger_subs[BHASH_SUB]));
	if (gvcst_get(mv_val_ptr))
		set_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
	else {
		util_out_print_gtmio("The BHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
		set_hash.hash_code = 0;
	}
	/* kill ^#t(GVN,trigger_index) */
	BUILD_HASHT_SUB_MSUB_CURRKEY(trigvn, trigvn_len, trigger_index);
	gvcst_kill(TRUE);
	assert(0 == gvcst_data());
	if (1 == count)
	{ /* This is the last trigger for "trigvn" - clean up trigger name, remove #LABEL and #COUNT */
		assert(1 == index);
		BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL));
		gvcst_kill(TRUE);
		BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
		gvcst_kill(TRUE);
		cleanup_trigger_name(trigvn, trigvn_len, trig_name, trig_name_len);
		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, 0);
	} else
	{
		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, index);
		cleanup_trigger_name(trigvn, trigvn_len, trig_name, trig_name_len);
		if (index != count)
		{	/* Shift the last trigger (index is #COUNT value) to the just deleted trigger's index.
			 * This way count is always accurate and can still be used as the index for new triggers.
			 * Note - there is no dependence on the trigger order, or this technique wouldn't work.
			 */
			ptr1 = tmp_trig_str;
			memcpy(ptr1, trigvn, trigvn_len);
			ptr1 += trigvn_len;
			*ptr1++ = '\0';
			for (sub_indx = 0; sub_indx < NUM_TOTAL_SUBS; sub_indx++)
			{
				/* $get(^#t(GVN,trigger_count,sub_indx) */
				BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[sub_indx],
								STRLEN(trigger_subs[sub_indx]));
				if (gvcst_get(&trigger_value))
				{
					trig_len = trigger_value.str.len;
					/* set ^#t(GVN,trigger_index,sub_indx)=^#t(GVN,trigger_count,sub_indx) */
					SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MVAL(trigvn, trigvn_len, trigger_index,
						trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), trigger_value, result);
					assert(PUT_SUCCESS == result);
				} else if (XECUTE_SUB == sub_indx)
				{ /* multi line trigger broken up because it exceeds record size */
					for (xecute_idx = 0; ; xecute_idx++)
					{
						i2mval(&xecute_index, xecute_idx);
						BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, *trigger_count,
							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index);
						if (!gvcst_get(&trigger_value))
							break;
						SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_MVAL(trigvn, trigvn_len, trigger_index,
							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index,
							trigger_value, result);
						assert(PUT_SUCCESS == result);
					}
					assert (xecute_idx >= 2); /* multi-line trigger, indices 0, 1 and 2 MUST be defined */
				} else
				{
					/* in PRO this is a nasty case that will result in an access violation
					 * because data that should be present is not. In the next go around
					 * with trigger installation this case should be handled better */
					assert(!((TRIGNAME_SUB == sub_indx) || (CMD_SUB == sub_indx) ||
						 (CHSET_SUB == sub_indx))); /* these should not be zero length */
					trig_len = 0;
				}
				if (NUM_SUBS > sub_indx)
				{
					tt_val[sub_indx] = ptr1;
					tt_val_len[sub_indx] = trig_len;
					if (0 < trig_len)
					{
						memcpy(ptr1, trigger_value.str.addr, trig_len);
						ptr1 += trig_len;
					}
					*ptr1++ = '\0';
				}
			}
			/* $get(^#t(GVN,trigger_count,"LHASH") for update_trigger_hash_value */
			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[LHASH_SUB],
							 STRLEN(trigger_subs[LHASH_SUB]));
			if (!gvcst_get(mv_val_ptr))
				return PUT_SUCCESS;
			kill_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
			/* $get(^#t(GVN,trigger_count,"BHASH") for update_trigger_hash_value */
			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[BHASH_SUB],
							 STRLEN(trigger_subs[BHASH_SUB]));
			if (!gvcst_get(mv_val_ptr))
				return PUT_SUCCESS;
			set_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
			/* update hash values from above */
			if (VAL_TOO_LONG == (retval = update_trigger_hash_value(trigvn, trigvn_len, tt_val, tt_val_len,
					&set_hash, &kill_hash, count, index)))
				return VAL_TOO_LONG;
			/* fix the value ^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) to point to the correct "index" */
			if (VAL_TOO_LONG == (retval = update_trigger_name_value(trigvn_len, tt_val[TRIGNAME_SUB],
					tt_val_len[TRIGNAME_SUB], index)))
				return VAL_TOO_LONG;
			/* kill ^#t(GVN,COUNT) which was just shifted to trigger_index */
			BUILD_HASHT_SUB_MSUB_CURRKEY(trigvn, trigvn_len, *trigger_count);
			gvcst_kill(TRUE);
		}
		/* Update #COUNT */
		count--;
		MV_FORCE_MVAL(trigger_count, count);
		SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT), *trigger_count,
			result);
		assert(PUT_SUCCESS == result);		/* Size of count can only get shorter or stay the same */
	}
	trigger_incr_cycle(trigvn, trigvn_len);
	return PUT_SUCCESS;
}
Exemple #9
0
STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len)
{
	sgmnt_addrs		*csa;
	mname_entry		gvent;
	gv_namehead		*hasht_tree;
	int4			result;
	char			save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)];
	char			save_altkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)];
	gv_key			*save_gv_altkey;
	gv_key			*save_gv_currkey;
	gd_region		*save_gv_cur_region;
	gv_namehead		*save_gv_target;
	gv_namehead		*save_gvtarget;
	sgm_info		*save_sgm_info_ptr;
	char			trunc_name[MAX_TRIGNAME_LEN + 1];
	uint4			used_trigvn_len;
	mval			val;
	mval			*val_ptr;
	char			val_str[MAX_DIGITS_IN_INT + 1];
	int			var_count;
	boolean_t		is_auto_name;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	/* assume user defined name or auto gen name whose GVN < 21 chars */
	is_auto_name = FALSE;
	if (!trigger_user_name(trigger_name, trigger_name_len))
	{	/* auto gen name uses #TNCOUNT and #SEQNO under #TNAME */
		is_auto_name = TRUE;
		used_trigvn_len = MIN(trigvn_len, MAX_AUTO_TRIGNAME_LEN);
		memcpy(trunc_name, trigvn, used_trigvn_len);
	}
	SAVE_TRIGGER_REGION_INFO;
	SWITCH_TO_DEFAULT_REGION;
	if (0 != gv_target->root)
	{
		if (is_auto_name)
		{
			/* $get(^#t("#TNAME",<trunc_name>,"#TNCOUNT")) */
			BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trunc_name,
							used_trigvn_len, LITERAL_HASHTNCOUNT, STRLEN(LITERAL_HASHTNCOUNT));
			if (gvcst_get(&val))
			{	 /* only long autogenerated names have a #TNCOUNT entry */
				val_ptr = &val;
				var_count = MV_FORCE_INT(val_ptr);
				if (1 == var_count)
				{
					/* kill ^#t("#TNAME",<trunc_name>) to kill #TNCOUNT and #SEQNO */
					BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trunc_name,
								    used_trigvn_len);
					gvcst_kill(TRUE);
				} else
				{
					var_count--;
					MV_FORCE_MVAL(&val, var_count);
					/* set ^#t("#TNAME",GVN,"#TNCOUNT")=var_count */
					SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME),
									trunc_name, used_trigvn_len, LITERAL_HASHTNCOUNT,
									STRLEN(LITERAL_HASHTNCOUNT), val, result);
					assert(PUT_SUCCESS == result);		/* The count size can only decrease */
				}
			}
		}
		/* kill ^#t("#TNAME",<trigger_name>,:) or zkill ^#t("#TNAME",<trigger_name>) if is_auto_name==FALSE */
		BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name,
					    trigger_name_len - 1);
		gvcst_kill(is_auto_name);
	}
	RESTORE_TRIGGER_REGION_INFO;
}
void op_zprevious(mval *v)
{
	int4			n;
	int			min_reg_index, reg_index, res;
	mname_entry		gvname;
	mval			tmpmval, *datamval;
	enum db_acc_method	acc_meth;
	boolean_t		found, ok_to_change_currkey;
	gd_binding		*gd_map_start, *map, *prev_map;
	gd_addr			*gd_targ;
	gvnh_reg_t		*gvnh_reg;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(gv_currkey->prev || !TREF(gv_last_subsc_null));
	if (gv_currkey->prev)
	{	/* If last subscript is a NULL subscript, modify gv_currkey such that a gvcst_search of the resulting gv_currkey
		 * will find the last available subscript. But in case of dba_usr, (the custom implementation of $ZPREVIOUS which
		 * is overloaded for DDP now but could be more in the future) it is better to hand over gv_currkey as it is so
		 * the custom implementation can decide what to do with it.
		 */
		acc_meth = REG_ACC_METH(gv_cur_region);
		ok_to_change_currkey = (dba_usr != acc_meth);
		if (TREF(gv_last_subsc_null) && ok_to_change_currkey)
		{	/* Replace the last subscript with the highest possible subscript value i.e. the byte sequence
			 * 	0xFF (STR_SUB_MAXVAL), 0xFF, 0xFF ...  as much as possible i.e. until gv_currkey->top permits.
			 * This subscript is guaranteed to be NOT present in the database since a user who tried to set this
			 * exact subscripted global would have gotten a GVSUBOFLOW error (because GT.M sets aside a few bytes
			 * of padding space). And yet this is guaranteed to collate AFTER any existing subscript. Therefore we
			 * can safely do a gvcst_zprevious on this key to get at the last existing key in the database.
			 *
			 * With    standard null collation, the last subscript will be 0x01
			 * Without standard null collation, the last subscript will be 0xFF
			 * Assert that is indeed the case as this will be used to restore the replaced subscript at the end.
			 */
			assert(gv_cur_region->std_null_coll || (STR_SUB_PREFIX == gv_currkey->base[gv_currkey->prev]));
			assert(!gv_cur_region->std_null_coll || (SUBSCRIPT_STDCOL_NULL == gv_currkey->base[gv_currkey->prev]));
			assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->prev + 1]);
			assert(gv_currkey->end == gv_currkey->prev + 2);
			assert(gv_currkey->end < gv_currkey->top); /* need "<" (not "<=") to account for terminating 0x00 */
			GVZPREVIOUS_APPEND_MAX_SUBS_KEY(gv_currkey, gv_target);
		}
		if ((dba_bg == acc_meth) || (dba_mm == acc_meth))
		{
			gvnh_reg = TREF(gd_targ_gvnh_reg);
			if (NULL == gvnh_reg)
				found = (gv_target->root ? gvcst_zprevious() : FALSE);
			else
				INVOKE_GVCST_SPR_XXX(gvnh_reg, found = gvcst_spr_zprevious());
		} else if (dba_cm == acc_meth)
			found = gvcmx_zprevious();
		else
			found = gvusr_zprevious();
		v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied (BYPASSOK)
				* by this to-be-overwritten mval */
		if (found)
		{
			gv_altkey->prev = gv_currkey->prev;
			if (!IS_STP_SPACE_AVAILABLE(MAX_KEY_SZ))
			{
				if ((0xFF != gv_altkey->base[gv_altkey->prev])
						&& (SUBSCRIPT_STDCOL_NULL != gv_altkey->base[gv_altkey->prev]))
					n = MAX_FORM_NUM_SUBLEN;
				else
				{
					n = gv_altkey->end - gv_altkey->prev;
					assert(n > 0);
				}
				v->str.len = 0; /* so stp_gcol (if invoked) can free up space currently occupied by this (BYPASSOK)
						 * to-be-overwritten mval */
				ENSURE_STP_FREE_SPACE(n);
			}
			v->str.addr = (char *)stringpool.free;
			v->str.len = MAX_KEY_SZ;
			stringpool.free = gvsub2str(&gv_altkey->base[gv_altkey->prev], &(v->str), FALSE);
			v->str.len = INTCAST((char *)stringpool.free - v->str.addr);
			assert(v->str.addr < (char *)stringpool.top && v->str.addr >= (char *)stringpool.base);
			assert(v->str.addr + v->str.len <= (char *)stringpool.top &&
				v->str.addr + v->str.len >= (char *)stringpool.base);
		} else
			v->str.len = 0;
		v->mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */
		if (TREF(gv_last_subsc_null) && ok_to_change_currkey)
		{	/* Restore gv_currkey to what it was at function entry time */
			gv_currkey->base[gv_currkey->prev + 1] = KEY_DELIMITER;
			if (gv_cur_region->std_null_coll)
				gv_currkey->base[gv_currkey->prev] = SUBSCRIPT_STDCOL_NULL;
			assert(gv_cur_region->std_null_coll || (STR_SUB_PREFIX == gv_currkey->base[gv_currkey->prev]));
			gv_currkey->end = gv_currkey->prev + 2;
			gv_currkey->base[gv_currkey->end] = KEY_DELIMITER;
		}
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end]);
	} else
	{	/* the following section is for $ZPREVIOUS(^gname) */
		assert(2 <= gv_currkey->end);
		assert(gv_currkey->end < (MAX_MIDENT_LEN + 2));	/* until names are not in midents */
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end]);
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end - 1]);
		gd_targ = TREF(gd_targ_addr);
		gd_map_start = gd_targ->maps;
		map = gv_srch_map(gd_targ, (char *)&gv_currkey->base[0], gv_currkey->end - 1);
		assert(map > (gd_map_start + 1));
		/* If ^gname starts at "map" start search from map-1 since $ZPREVIOUS(^gname) is sought */
		BACK_OFF_ONE_MAP_ENTRY_IF_EDGECASE(gv_currkey->base, gv_currkey->end - 1, map);
		found = FALSE;
		/* The first map entry corresponds to local locks. The second map entry does not contain any globals.
		 * Therefore, any search for globals needs to only look after these maps. Hence the "gd_map_start + 1" below.
		 */
		for ( ; map > gd_map_start + 1; map = prev_map)
		{
			prev_map = map - 1;
			gv_cur_region = map->reg.addr;
			if (!gv_cur_region->open)
				gv_init_reg(gv_cur_region);
			change_reg();
			acc_meth = REG_ACC_METH(gv_cur_region);
			/* search region, entries in directory tree could have empty GVT in which case move on to previous entry */
			for ( ; ; )
			{
				assert(0 == gv_currkey->prev);	/* or else gvcst_zprevious could get confused */
				if ((dba_bg == acc_meth) || (dba_mm == acc_meth))
				{
					gv_target = cs_addrs->dir_tree;
					found = gvcst_zprevious();
				} else  if (dba_cm == acc_meth)
					found = gvcmx_zprevious();
				else
					found = gvusr_zprevious();
				if ('#' == gv_altkey->base[0]) /* don't want to give any hidden ^#* global, e.g "^#t" */
					found = FALSE;
				if (!found)
					break;
				assert(1 < gv_altkey->end);
				assert(gv_altkey->end < (MAX_MIDENT_LEN + 2));	/* until names are not in midents */
				res = memcmp(gv_altkey->base, prev_map->gvkey.addr, gv_altkey->end);
				assert((0 != res) || (gv_altkey->end <= prev_map->gvkey_len));
				if (0 > res)
				{	/* The global name we found is less than the maximum value in the previous map
					 * so this name is not part of the current map for sure. Move on to previous map.
					 */
					found = FALSE;
					break;
				}
				gvname.var_name.addr = (char *)gv_altkey->base;
				gvname.var_name.len = gv_altkey->end - 1;
				if (dba_cm == acc_meth)
					break;
				COMPUTE_HASH_MNAME(&gvname);
				GV_BIND_NAME_AND_ROOT_SEARCH(gd_targ, &gvname, gvnh_reg);	/* updates "gv_currkey" */
				assert((NULL != gvnh_reg->gvspan) || (gv_cur_region == map->reg.addr));
				if (NULL != gvnh_reg->gvspan)
				{	/* gv_target would NOT have been initialized by GV_BIND_NAME in this case.
					 * So finish that initialization.
					 */
					datamval = &tmpmval;
					/* The below macro finishes the task of GV_BIND_NAME_AND_ROOT_SEARCH
					 * 	(e.g. setting gv_cur_region for spanning globals)
					 */
					GV_BIND_SUBSNAME_IF_GVSPAN(gvnh_reg, gd_targ, gv_currkey, gvnh_reg->gd_reg);
					op_gvdata(datamval);
					if (MV_FORCE_INT(datamval))
						break;
				} else
				{	/* else gv_target->root would have been initialized by GV_BIND_NAME_AND_ROOT_SEARCH */
					if ((0 != gv_target->root) && (0 != gvcst_data()))
						break;
				}
			}
			if (found)
				break;
			/* If previous map corresponding to a spanning global, then do not update gv_currkey as that would
			 * effectively cause the spanning global to be skipped. If gvkey_len == gvname_len + 1 it is NOT
			 * a spanning global map entry.
			 */
			assert(prev_map->gvkey_len >= (prev_map->gvname_len + 1));
			if ((prev_map > (gd_map_start + 1)) && (prev_map->gvkey_len == (prev_map->gvname_len + 1)))
			{
				assert(strlen(prev_map->gvkey.addr) == prev_map->gvname_len);
				gv_currkey->end = prev_map->gvname_len + 1;
				assert(gv_currkey->end <= (MAX_MIDENT_LEN + 1));
				memcpy(gv_currkey->base, prev_map->gvkey.addr, gv_currkey->end);
				assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end - 1]);
				gv_currkey->base[gv_currkey->end] = KEY_DELIMITER;
				assert(gv_currkey->top > gv_currkey->end);	/* ensure we are within allocated bounds */
			}
		}
		/* Reset gv_currkey as we have potentially skipped one or more regions so we no
		 * longer can expect gv_currkey/gv_cur_region/gv_target to match each other.
		 */
		gv_currkey->end = 0;
		gv_currkey->base[0] = KEY_DELIMITER;
		v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied (BYPASSOK)
				* by this to-be-overwritten mval */
		if (found)
		{
			if (!IS_STP_SPACE_AVAILABLE(gvname.var_name.len + 1))
			{
				v->str.len = 0;	/* so stp_gcol ignores otherwise incompletely setup mval (BYPASSOK) */
				INVOKE_STP_GCOL(gvname.var_name.len + 1);
			}
			v->str.addr = (char *)stringpool.free;
			*stringpool.free++ = '^';
			memcpy(stringpool.free, gvname.var_name.addr, gvname.var_name.len);
			stringpool.free += gvname.var_name.len;
			v->str.len = gvname.var_name.len + 1;
			assert(v->str.addr < (char *)stringpool.top && v->str.addr >= (char *)stringpool.base);
			assert(v->str.addr + v->str.len <= (char *)stringpool.top &&
				v->str.addr + v->str.len >= (char *)stringpool.base);
		} else
			v->str.len = 0;
		v->mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */
		/* No need to restore gv_currkey (to what it was at function entry) as it is already set to NULL */
	}
	return;
}
Exemple #11
0
void op_fnorder(lv_val *src, mval *key, mval *dst)
{
	int			cur_subscr;
	mval			tmp_sbs;
	int             	length;
	sbs_blk			*num, *str;
	boolean_t		found, is_neg;
	int4			i;
	lv_val			**lv;
	lv_sbs_tbl		*tbl;
	sbs_search_status	status;
	boolean_t		is_fnnext;

	is_fnnext = in_op_fnnext;
	in_op_fnnext = FALSE;
	found = FALSE;
	if (src)
	{
		if (tbl = src->ptrs.val_ent.children)
		{
			MV_FORCE_DEFINED(key);
			num = tbl->num;
			str = tbl->str;
			assert(tbl->ident == MV_SBS);
			if ((MV_IS_STRING(key) && key->str.len == 0) || (is_fnnext && MV_IS_INT(key) && key->m[1] == MINUS_ONE))
			{ /* With GT.M collation , if last subscript is null, $o returns the first subscript in that level */
				if (tbl->int_flag)
				{
					assert(num);
					for (i = 0, lv = &num->ptr.lv[0]; i < SBS_NUM_INT_ELE; i++, lv++)
					{
						if (*lv)
						{
							MV_FORCE_MVAL(dst,i);
							found = TRUE;
							break;
						}
					}
				} else if (num)
				{
					assert(num->cnt);
					MV_ASGN_FLT2MVAL((*dst),num->ptr.sbs_flt[0].flt);
					found = TRUE;
				}
			} else
			{
				if (MV_IS_CANONICAL(key))
				{
					MV_FORCE_NUM(key);
					if (tbl->int_flag)
					{
						assert(num);
						is_neg = (key->mvtype & MV_INT) ? key->m[1] < 0 : key->sgn;
						if (is_neg)
							i = 0;
						else
						{
							if (!is_fnnext && (1 == numcmp(key, (mval *)&SBS_MVAL_INT_ELE)))
								i = SBS_NUM_INT_ELE;
							else
							{
								i =  MV_FORCE_INT(key);
								i++;
							}
						}
						for (lv = &num->ptr.lv[i]; i < SBS_NUM_INT_ELE; i++, lv++)
						{
							if (*lv)
							{
								MV_FORCE_MVAL(dst,i);
								found = TRUE;
								break;
							}
						}
					} else if (num && lv_nxt_num_inx(num, key, &status))
					{
						MV_ASGN_FLT2MVAL((*dst),((sbs_flt_struct*)status.ptr)->flt);
						found = TRUE;
					}
				} else
				{
					if (local_collseq)
					{
						ALLOC_XFORM_BUFF(&key->str);
						tmp_sbs.mvtype = MV_STR;
						tmp_sbs.str.len = max_lcl_coll_xform_bufsiz;
						assert(NULL != lcl_coll_xform_buff);
						tmp_sbs.str.addr = lcl_coll_xform_buff;
						do_xform(local_collseq, XFORM, &key->str,
								&tmp_sbs.str, &length);
						tmp_sbs.str.len = length;
						s2pool(&(tmp_sbs.str));
						key = &tmp_sbs;
					}
					if (str && lv_nxt_str_inx(str, &key->str, &status))
					{
						dst->mvtype = MV_STR;
						dst->str = ((sbs_str_struct *)status.ptr)->str;
					} else
					{
						if (!is_fnnext)
						{
							dst->mvtype = MV_STR;
							dst->str.len = 0;
						} else
							MV_FORCE_MVAL(dst, -1);
					}
					found = TRUE;
				}
			}
			if (!found && str)
			{	/* We are here because
				 * a. key is "" and there is no numeric subscript, OR
				 * b. key is numeric and it is >= the largest numeric subscript at this level implying a switch from
				 *    numeric to string subscripts
				 * Either case, return the first string subscript. However, for STDNULLCOLL, skip to the next
				 * subscript should the first subscript be ""
				 */
				assert(str->cnt);
				dst->mvtype = MV_STR;
				dst->str = str->ptr.sbs_str[0].str;
				found = TRUE;
				if (local_collseq_stdnull && 0 == dst->str.len)
				{
					assert(lv_null_subs);
					if (lv_nxt_str_inx(str, &dst->str, &status))
					{
						dst->str = ((sbs_str_struct*)status.ptr)->str;
					} else
						found = FALSE;
				}
			}
		}
	}
	if (!found)
	{
		if (!is_fnnext)
		{
			dst->mvtype = MV_STR;
			dst->str.len = 0;
		} else
			MV_FORCE_MVAL(dst, -1);
	} else if (dst->mvtype == MV_STR && local_collseq)
	{
		ALLOC_XFORM_BUFF(&dst->str);
		assert(NULL != lcl_coll_xform_buff);
		tmp_sbs.str.addr = lcl_coll_xform_buff;
		tmp_sbs.str.len = max_lcl_coll_xform_bufsiz;
		do_xform(local_collseq, XBACK,
				&dst->str, &tmp_sbs.str, &length);
		tmp_sbs.str.len = length;
		s2pool(&(tmp_sbs.str));
		dst->str = tmp_sbs.str;
	}
}
Exemple #12
0
void op_merge(void)
{
	boolean_t		found, check_for_null_subs, is_base_var;
	lv_val			*dst_lv;
	mval 			*mkey, *value, *subsc;
	int			org_glvn1_keysz, org_glvn2_keysz, delta2, dollardata_src, dollardata_dst, sbs_depth;
	unsigned char		*ptr, *ptr2;
	unsigned char  		buff[MAX_ZWR_KEY_SZ];
	unsigned char		nullcoll_src, nullcoll_dst;
	zshow_out		output;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(MAX_STRLEN >= MAX_ZWR_KEY_SZ);
	assert ((merge_args == (MARG1_LCL | MARG2_LCL)) ||
		(merge_args == (MARG1_LCL | MARG2_GBL)) ||
		(merge_args == (MARG1_GBL | MARG2_LCL)) ||
		(merge_args == (MARG1_GBL | MARG2_GBL)));
	assert(!lvzwrite_block || 0 == lvzwrite_block->curr_subsc);
	/* Need to protect value from stpgcol */
	PUSH_MV_STENT(MVST_MVAL);
	value = &mv_chain->mv_st_cont.mvs_mval;
	value->mvtype = 0; /* initialize mval in the M-stack in case stp_gcol gets called before value gets initialized below */
	if (MARG2_IS_GBL(merge_args))
	{	/* Need to protect mkey returned from gvcst_queryget from stpgcol */
		PUSH_MV_STENT(MVST_MVAL);
		mkey = &mv_chain->mv_st_cont.mvs_mval;
		mkey->mvtype = 0; /* initialize mval in M-stack in case stp_gcol gets called before mkey gets initialized below */
		gvname_env_restore(mglvnp->gblp[IND2]);
		/* now $DATA will be done for gvn2. op_gvdata input parameters are set in the form of some GBLREF */
		op_gvdata(value);
		dollardata_src = MV_FORCE_INT(value);
		if (0 == dollardata_src)
		{	/* nothing in source global */
			UNDO_ACTIVE_LV;
			POP_MV_STENT();	/* value */
			POP_MV_STENT(); /* mkey */
			if (MARG1_IS_GBL(merge_args))
				gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
			merge_args = 0;	/* Must reset to zero to reuse the Global */
			return;
		}
		if (NULL == TREF(gv_mergekey2))
		{	/* We need to initialize gvn2 (right hand side). */
			GVKEY_INIT(TREF(gv_mergekey2), DBKEYSIZE(MAX_KEY_SZ));
		}
		org_glvn1_keysz = mglvnp->gblp[IND1]->s_gv_currkey->end + 1;
		org_glvn2_keysz = gv_currkey->end + 1;
		(TREF(gv_mergekey2))->end = gv_currkey->end;
		(TREF(gv_mergekey2))->prev = gv_currkey->prev;
		memcpy((TREF(gv_mergekey2))->base, gv_currkey->base, gv_currkey->end + 1);
		if (MARG1_IS_GBL(merge_args))
		{	/*==================== MERGE ^gvn1=^gvn2 =====================*/
			if (mglvnp->gblp[IND2]->s_gv_target->nct != mglvnp->gblp[IND1]->s_gv_target->nct)
				rts_error(VARLSTCNT(1) ERR_NCTCOLLDIFF);
			/* if self merge then NOOP*/
			if (!merge_desc_check()) /* will not proceed if one is descendant of another */
			{
				gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
				POP_MV_STENT();	/* value */
				merge_args = 0;	/* Must reset to zero to reuse the Global */
				return;
			}
			nullcoll_src = mglvnp->gblp[IND2]->s_gv_cur_region->std_null_coll;
			nullcoll_dst = mglvnp->gblp[IND1]->s_gv_cur_region->std_null_coll;
			if (1 == dollardata_src || 11 == dollardata_src)
			{
				found = op_gvget(value);  /* value of ^glvn2 */
				if (found)
				{	/* SET ^gvn1=^gvn2 */
					gvname_env_restore(mglvnp->gblp[IND1]);
					op_gvput(value);
					/* Note: If ^gvn1's null_sub=ALLOWEXISTING and say ^gvn1("")=^gvn,
					 * this will give NULL_SUBC error
					 */
				}
			}
			check_for_null_subs = (NEVER != mglvnp->gblp[IND2]->s_gv_cur_region->null_subs) &&
				(ALWAYS != mglvnp->gblp[IND1]->s_gv_cur_region->null_subs);
			/* Traverse descendant of ^gvn2 and copy into ^gvn1 */
			for (; ;)
			{
				if (outofband)
				{
					gvname_env_restore(mglvnp->gblp[IND1]); /* naked indicator is restored into gv_currkey */
					outofband_action(FALSE);
				}
				/* Restore last key under ^gvn2 we worked */
				gvname_env_restore(mglvnp->gblp[IND2]);
				assert(0 == gv_currkey->base[gv_currkey->end - 1] && 0 == gv_currkey->base[gv_currkey->end]);
				/* following is an attempt to find immidiate right sibling */
				gv_currkey->base[gv_currkey->end] = 1;
				gv_currkey->base[gv_currkey->end + 1] = 0;
				gv_currkey->base[gv_currkey->end + 2] = 0;
				gv_currkey->end += 2;
				/* Do atomic $QUERY and $GET of current glvn2:
				 * mkey is a mstr which contains $QUERY result in database format (So no conversion necessary)
				 * value is a mstr which contains $GET result
				 */
				if (!op_gvqueryget(mkey, value))
					break;
				assert(MV_IS_STRING(mkey));
				if (mkey->str.len < org_glvn2_keysz)
					break;
				if (0 != *((unsigned char *)mkey->str.addr + (TREF(gv_mergekey2))->end - 1) ||
					memcmp(mkey->str.addr, (TREF(gv_mergekey2))->base, (TREF(gv_mergekey2))->end - 1))
					break; 					/* mkey is not under the sub-tree */
				delta2 = mkey->str.len - org_glvn2_keysz; 	/* length increase of source key */
				assert (0 < delta2);
				/* Save the new source key for next iteration */
				memcpy(mglvnp->gblp[IND2]->s_gv_currkey->base + org_glvn2_keysz - 2,
					mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2);
				mglvnp->gblp[IND2]->s_gv_currkey->end = mkey->str.len - 1;
				/* Create the destination key for this iteration (under ^glvn1) */
				gvname_env_restore(mglvnp->gblp[IND1]);
				if (gv_cur_region->max_key_size < org_glvn1_keysz + delta2)
					ISSUE_GVSUBOFLOW_ERROR(gv_currkey);
				assert(gv_currkey->end == org_glvn1_keysz - 1);
				memcpy(gv_currkey->base + org_glvn1_keysz - 2,
					mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2);
				gv_currkey->end = org_glvn1_keysz + delta2 - 1;
				if (nullcoll_src != nullcoll_dst)
				{
					if (0 == nullcoll_dst)
					{	/* Standard to GTM null subscript conversion*/
						STD2GTMNULLCOLL((unsigned char *)gv_currkey->base + org_glvn1_keysz - 1,
								delta2 - 1);
					} else
					{	/*  GTM to standard null subscript conversion */
						GTM2STDNULLCOLL((unsigned char *)gv_currkey->base + org_glvn1_keysz - 1,
								delta2 - 1);
					}
				}
				/* check null subscripts in destination key, note that we have already restored, destination global
				 * and curresponding region, key information
				 */
				if (check_for_null_subs)
				{
					ptr2 = gv_currkey->base + gv_currkey->end - 1;
					for (ptr = gv_currkey->base + org_glvn1_keysz - 2; ptr < ptr2; )
					{
						if (KEY_DELIMITER == *ptr++ && KEY_DELIMITER == *(ptr + 1) &&
							(0 == gv_cur_region->std_null_coll ? (STR_SUB_PREFIX == *ptr) :
							(SUBSCRIPT_STDCOL_NULL == *ptr)))
							/* Note: For sgnl_gvnulsubsc/rts_error
							 * 	 we do not restore proper naked indicator.
							 * The standard states that the effect of a MERGE command
							 * on the naked indicator is that the naked indicator will be changed
							 * as if a specific SET command would have been executed.
							 * The standard also states that the effect on the naked indicator
							 * will only take be visible after the MERGE command has completed.
							 * So, if there is an error during the execution of a MERGE command,
							 * the standard allows the naked indicator to reflect any intermediate
							 * state. This provision was made intentionally, otherwise it would
							 * have become nearly impossible to create a fully standard
							 * implementation. : From Ed de Moel : 2/1/2
							 */
							sgnl_gvnulsubsc();
					}
				}
				/* Now put value of ^glvn2 descendant into corresponding descendant under ^glvn1 */
				op_gvput(value);
			}
			gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
		} else
		{	/*==================== MERGE lvn1=^gvn2 =====================*/
			assert(MARG1_IS_LCL(merge_args));
			assert(mglvnp->lclp[IND1]);
			/* Need to protect subsc created from global variable subscripts from stpgcol */
			PUSH_MV_STENT(MVST_MVAL);
			subsc = &mv_chain->mv_st_cont.mvs_mval;
			/* Restore ^gvn2 we will work */
			gvname_env_save(mglvnp->gblp[IND2]);
			if (1 == dollardata_src || 11 == dollardata_src)
			{	/* SET lvn1=^gvn2 */
				found = op_gvget(value);
				if (found)
					mglvnp->lclp[IND1]->v = *value;
			}
			for (; ;)
			{
				if (outofband)
				{
					gvname_env_restore(mglvnp->gblp[IND2]);	 /* naked indicator is restored into gv_currkey */
					outofband_action(FALSE);
				}
				assert(0 == gv_currkey->base[gv_currkey->end - 1] && 0 == gv_currkey->base[gv_currkey->end]);
				/* following is an attempt to find immidiate right sibling */
				gv_currkey->base[gv_currkey->end] = 1;
				gv_currkey->base[gv_currkey->end + 1] = 0;
				gv_currkey->base[gv_currkey->end + 2] = 0;
				gv_currkey->end += 2;
				/* Do $QUERY and $GET of current glvn2. Result will be in mkey and value respectively.
				 * mkey->str contains data as database format. So no conversion necessary
				 */
				if (!op_gvqueryget(mkey, value))
					break;
				if (mkey->str.len < (TREF(gv_mergekey2))->end + 1)
					break;
				ptr = (unsigned char *)mkey->str.addr +  (TREF(gv_mergekey2))->end - 1;
				if (0 != *ptr || memcmp(mkey->str.addr, (TREF(gv_mergekey2))->base, (TREF(gv_mergekey2))->end - 1))
					break;
				assert(MV_IS_STRING(mkey));
				delta2 = mkey->str.len - org_glvn2_keysz; /* length increase of key */
				assert (0 < delta2);
				/* Create next key for ^glvn2 */
				memcpy(gv_currkey->base + org_glvn2_keysz - 2, mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2);
				gv_currkey->end = mkey->str.len - 1;
				/* Now add subscripts to create the entire key */
				dst_lv =  mglvnp->lclp[IND1];
				is_base_var = LV_IS_BASE_VAR(dst_lv);
				ptr = (unsigned char *)gv_currkey->base + org_glvn2_keysz - 1;
				assert(*ptr);
				do
				{
					LV_SBS_DEPTH(dst_lv, is_base_var, sbs_depth);
					if (MAX_LVSUBSCRIPTS <= sbs_depth)
						rts_error(VARLSTCNT(3) ERR_MERGEINCOMPL, 0, ERR_MAXNRSUBSCRIPTS);
					ptr2 = gvsub2str(ptr, buff, FALSE);
					subsc->mvtype = MV_STR;
					subsc->str.addr = (char *)buff;
					subsc->str.len = INTCAST(ptr2 - buff);
					s2pool(&subsc->str);
					dst_lv = op_putindx(VARLSTCNT(2) dst_lv, subsc);
					while (*ptr++);	/* skip to start of next subscript */
					is_base_var = FALSE;
				} while (*ptr);
				/* We created the key. Pre-process the node in case a container is being replaced,
				 * then assign the value directly. Note there is no need to worry about MV_ALIASCONT
				 * propagation since the source in this case is a global var.
				 */
				DECR_AC_REF(dst_lv, TRUE);
				dst_lv->v = *value;
			}
			gvname_env_restore(mglvnp->gblp[IND2]);	 /* naked indicator is restored into gv_currkey */
			POP_MV_STENT();     /* subsc */
		}
		POP_MV_STENT();     /* mkey */
	} else
	{	/* source is local */
		op_fndata(mglvnp->lclp[IND2], value);
		dollardata_src = MV_FORCE_INT(value);
		if (0 == dollardata_src)
		{
			UNDO_ACTIVE_LV;
			POP_MV_STENT();	/* value */
			if (MARG1_IS_GBL(merge_args))
				gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
			merge_args = 0;	/* Must reset to zero to reuse the Global */
			return;
		}
		/* not memsetting output to 0 here can cause garbage value of output.out_var.lv.child which in turn can
		 * cause a premature return from lvzwr_var resulting in op_merge() returning without having done the merge.
		 */
		memset(&output, 0, SIZEOF(output));
		if (MARG1_IS_LCL(merge_args))
		{	/*==================== MERGE lvn1=lvn2 =====================*/
			assert(mglvnp->lclp[IND1]);
			/* if self merge then NOOP */
			if (!merge_desc_check()) /* will not proceed if one is descendant of another */
			{
				POP_MV_STENT();	/* value */
				merge_args = 0;	/* Must reset to zero to reuse the Global */
				return;
			}
			output.buff = (char *)buff;
			output.ptr = output.buff;
			output.out_var.lv.lvar = mglvnp->lclp[IND1];
			zwr_output = &output;
			lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v);
			lvzwr_arg(ZWRITE_ASTERISK, 0, 0);
			lvzwr_var(mglvnp->lclp[IND2], 0);
			/* assert that destination got all data of the source and its descendants */
			DEBUG_ONLY(op_fndata(mglvnp->lclp[IND1], value));
			DEBUG_ONLY(dollardata_dst = MV_FORCE_INT(value));
			assert((dollardata_src & dollardata_dst) == dollardata_src);
		} else
		{	/*==================== MERGE ^gvn1=lvn2 =====================*/
			assert(MARG1_IS_GBL(merge_args) && MARG2_IS_LCL(merge_args));
			gvname_env_save(mglvnp->gblp[IND1]);
			output.buff = (char *)buff;
			output.ptr = output.buff;
			output.out_var.gv.end = gv_currkey->end;
			output.out_var.gv.prev = gv_currkey->prev;
			zwr_output = &output;
			lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v);
			lvzwr_arg(ZWRITE_ASTERISK, 0, 0);
			lvzwr_var(mglvnp->lclp[IND2], 0);
			gvname_env_restore(mglvnp->gblp[IND1]);	 /* store destination as naked indicator in gv_currkey */
		}
	}
	POP_MV_STENT();	/* value */
	merge_args = 0;	/* Must reset to zero to reuse the Global */
}
Exemple #13
0
int one_job_param (char **parptr)
{
	boolean_t	neg;
	int		x, len, num;
	error_def	(ERR_JOBPARUNK);
	error_def	(ERR_JOBPARNOVAL);
	error_def	(ERR_JOBPARVALREQ);
	error_def	(ERR_JOBPARNUM);
	error_def	(ERR_JOBPARSTR);

	if ((window_token != TK_IDENT) ||
	   ((x = namelook (job_param_index, job_param_names, window_ident.c)) < 0))
	{
		stx_error (ERR_JOBPARUNK);
		return FALSE;
	}
	advancewindow ();
	*(*parptr)++ = job_param_data[x];
	if (job_param_datatypes[job_param_data[x]] != jpdt_nul)
	{
		if (window_token != TK_EQUAL)
		{
			stx_error (ERR_JOBPARVALREQ);
			return FALSE;
		}
		advancewindow ();
		switch (job_param_datatypes[job_param_data[x]])
		{
		case jpdt_num:
			neg = FALSE;
			if (window_token == TK_MINUS && director_token == TK_INTLIT)
			{
				advancewindow();
				neg = TRUE;
			}
			if (window_token != TK_INTLIT)
			{
				stx_error (ERR_JOBPARNUM);
				return FALSE;
			}
			num = MV_FORCE_INT(&window_mval);
			*((int4 *) (*parptr)) = (neg ? -num : num);
			*parptr += sizeof(int4);
			break;
		case jpdt_str:
			if (window_token != TK_STRLIT)
			{
				stx_error (ERR_JOBPARSTR);
				return FALSE;
			}
			len = window_mval.str.len;
			*(*parptr)++ = len;
			memcpy (*parptr, window_mval.str.addr, len);
			*parptr += len;
			break;
		default:
			GTMASSERT;
		}
		advancewindow ();
	} else if (window_token == TK_EQUAL)
	{
		stx_error (ERR_JOBPARNOVAL);
		return FALSE;
	}
	return TRUE;
}