Example #1
0
LISTID MakeRuleArgList(LISTID idVarList, LISTID idClassList)
    {
    LISTID      idRuleList;
    ITEMID      idVar, idItem;
    LPVAR       lpVar;
    GLOBALHANDLE hLoop, hLoop2;
    LISTLOOP    lpLoop, lpLoop2;

    idRuleList = KppMakeList(0);
    INIT_LIST_LOOP(idVarList, hLoop, lpLoop);
    INIT_LIST_LOOP(idClassList, hLoop2, lpLoop2);
    while ((idItem = NEXT_LIST_ELEMENT(lpLoop)) != NULLID)
        {
        idVar = KppAddItem(VAR, (LPLPSTR)&lpVar);
        VARNAME(lpVar) = idItem;
        BINDINGS(lpVar) = NULLID;
        idItem = NEXT_LIST_ELEMENT(lpLoop2);
        VARCLASS(lpVar) = idItem;
        KppReleaseItem(VAR, idVar);
        KppAppendElem(idRuleList, idVar);
    }
    RELEASE_LIST_LOOP(hLoop, lpLoop);
    RELEASE_LIST_LOOP(hLoop2, lpLoop2);

    return idRuleList;
}
Example #2
0
short PEXPORT Kpp__SetupFunc(LPFUNC lpFunc, LISTID idAtomList, EXPID idBody)
{
    LISTID idVarList = KppMakeList(0);

    if (idAtomList && idAtomList != lpIDs->idNull)
    {
        LIST_LOOP loop;
        ATOMID idItem;
        
        kpc_init_loop(idAtomList, &loop);
        while (idItem = KppNextListElement(&loop)) {
            LPVAR lpVar;
            VARID idVar = KppAddItem(VAR, (LPLPSTR) &lpVar);
            
            VARNAME(lpVar) = idItem;
            BINDINGS(lpVar) = NULLID;
            VARCLASS(lpVar) = NULLID;
            VARPREV(lpVar) = NULLID;
            KppReleaseItem(VAR, idVar);
            KppAppendElem(idVarList, idVar);
        }
    }
    KppDeleteList(idAtomList);

    NUMVARS(lpFunc) = KppListLen(idVarList);
    if (!idBody)
        idBody = KppBuildNullExp();
    else
        KppResetBoundFlag(idBody);
    BODY(lpFunc) = idBody;
    VARS(lpFunc) = idVarList;
    if (NUMVARS(lpFunc))
    {
        KppClearVarList(idVarList);
        KppBindVars(idVarList, idBody);
    }
    
    return TRUE;
}
long getmodel(Symbolhandle list, long nargs, long startKey, long silent,
			  Symbolhandle symhWts, Symbolhandle symhOffset,
			  Symbolhandle symhN)
{
	long            i, j, i2, inc;
	long            ny, ndata, nvars, nfactors, nterms, nerrorterms;
	long            needed, balanced;
	long            foundNonIntY = 0, foundNonIntN = 0;
	long            intercept;
	long            nmissing, nzerowt;
	long            dim[2];
	modelPointer    kterm;
	Symbolhandle    symh;
	double          tmp;
	double         *glmoffset, *casewts, *misswts, *ptmp, *factorvar;
	double          yi, logitni, *y, *logitn, maxlevel;
	long            caseweights = MODELTYPE & CASEWEIGHTS;
	char           *ipfwarning =
		"WARNING: ipf() cannot be used, poisson() substituted";
	modelInfoPointer info = (modelInfoPointer) 0;
	WHERE("getmodel");
	TRASH(NTRASH,errorExit);

	*OUTSTR = '\0';
	USEGLMOFFSET = 0;
	
	if (!initmodelparse(STRMODEL) || modelparse() != 0)
	{/* parse it */
		goto errorExit;
	}
	info = getModelInfo(); /* retrieve model information */
	if((ndata = checkVariables(info)) < 0)
	{
		goto errorExit;
	}
	if(!(GLMCONTROL & MULTIVAR) && !isVector(info->modelvars[0]))
	{
		sprintf(OUTSTR,
				"ERROR: non-vector response variable for %s()", FUNCNAME);
		goto errorExit;
	}
	
	NVARS = nvars = MODELINFO->nvars = info->nvars;
	NFACTORS = nfactors = MODELINFO->nfactors = info->nfactors;
	NTERMS = nterms = MODELINFO->nterms = info->nterms;
	
	NERRORTERMS = nerrorterms = MODELINFO->nerrorterms = info->nerrorterms;
	for(i=0;i<nerrorterms;i++)
	{
		modeltermAssign((modelPointer) info->errorterms[i],
						(modelPointer) MODELINFO->errorterms[i]);
	}
/* Note: As of 930601, INTMODEL has been eliminated */
	MODEL = info->model;
	info->model = (modelHandle) 0;
	
	if(MODELTYPE & (OLSREG|LEAPS))
	{
		NFACTORS = nfactors = MODELINFO->nfactors = 0;
		intercept = 0;
		for(j=0;j<nterms;j++)
		{
			kterm = modelterm(MODEL,j);
			if(nvInTerm(kterm) > 1)
			{
				sprintf(OUTSTR,
						"ERROR: crossed variates and/or factors are illegal for %s()",
						FUNCNAME);
				goto errorExit;
			} /*if(nvInTerm(modelterm(MODEL,j)) > 1)*/
			if(modeltermEqual(kterm,(modelPointer) NULLTERM))
			{
				intercept = 1;
			}
		} /*for(j=0;j<nterms;j++)*/
	} /*if(MODELTYPE & (OLSREG|LEAPS))*/

	if (MODELTYPE & LEAPS && !intercept)
	{
		sprintf(OUTSTR,
				"ERROR: a model without an intercept is illegal for %s()",
				FUNCNAME);
		goto errorExit;
	}

	/* set up MODELVARS */
	for (i = 0; i <= nvars; i++)
	{
		if(MODELVARS[i] != (Symbolhandle) 0)
		{
			Delete(MODELVARS[i]);
		}
		
		MODELVARS[i] = Makesymbol(REAL);
		if (MODELVARS[i] == (Symbolhandle) 0)
		{
			goto errorExit;
		}
		
		if (!Copy(info->modelvars[i], MODELVARS[i]))
		{
			goto errorExit;
		}
		info->modelvars[i] = (Symbolhandle) 0;
		strcpy(VARNAMES[i], NAME(MODELVARS[i]));
		if(i < nvars)
		{
			NCLASSES[i] = info->nclasses[i];
		}			
		clearNotes(MODELVARS[i]);
	} /*for (i = 0; i <= nvars; i++)*/

	/* set up Y and X */
	/* response and factors are known to be matrix or vector */
	for (i = 0; i <= nvars; i++)
	{
		symh = MODELVARS[i];
		(void) isMatrix(symh,dim); /* get dimensions */
		if (HASLABELS(symh) && NDIMS(symh) != 2)
		{
			if (!fixupMatLabels(symh, USEBOTHLABELS))
			{
				goto errorExit;
			}
		} /*if (HASLABELS(symh) && NDIMS(symh) != 2)*/
		else
		{
			Setdims(symh, 2, dim);
		}
		
		if(i == 0)
		{
			Y = DATA(symh);
			ny = dim[1];
			NDATA = (double) ndata;
			NY = (double) ny;
			/* make sure dimensions are correct, always 2 */
		} /*if(i == 0)*/
		else
		{/* i > 0 */
			X[i - 1] = DATA(symh);

			if (isVariate(i-1))
			{
				GLMCONTROL |= UNBALANCED;
			} /*if (isVariate(i-1))*/
		}  /*if(i == 0){}else{}*/
		if(*OUTSTR)
		{
			goto errorExit;
		}
	} /*for (i = 0; i <= nvars; i++)*/

	/* check for crossed variates */

	for (i = 0; i < nvars-1; i++)
	{
		if (isVariate(i))
		{
			/* variable i is a variate */
			for (j = 0; j < nterms; j++)
			{					/* 
				find the terms it is in and check to see it is not crossed
				with another variate
			  */
				kterm = modelterm(MODEL,j);
				
				if(inTerm(i,kterm) && nvInTerm(kterm) > 1)
				{
					/* 
					  j-th term has variable i and there are at least 2
					  variables or factors in the term.
					  Check to see if j-th term has another variate
					*/
					for (i2 = i+1; i2 < nvars; i2++)
					{
						if (isVariate(i2) && inTerm(i2,kterm))
						{
							sprintf(OUTSTR,
									"ERROR: crossed variates in model are illegal for %s()",
									FUNCNAME);
							goto errorExit;
						} /*if (isVariate(i2) && inTerm(i2,kterm))*/
					} /*for (i2 = 0; i2 < nvars; i2++)*/
				} /*if(inTerm(i,kterm))*/
			} /*for (j = 0; j < nterms; j++)*/
		} /*if (isVariate(i))*/
	} /*for (i = 0; i < nvars; i++)*/

	/* check for case weights, i.e., user specified weights */

	if (caseweights)
	{
		if (symhWts == (Symbolhandle) 0)
		{
			sprintf(OUTSTR,
					"ERROR: no weights given for %s()",FUNCNAME);
		}
		else if (TYPE(symhWts) != REAL || !isVector(symhWts) ||
				 symbolSize(symhWts) != ndata)
		{
			sprintf(OUTSTR,
					"ERROR: weights for %s() not REAL vector with length = nrows(%s)",
					FUNCNAME, NAME(MODELVARS[0]));
		}
		else
		{
			CASEWTS = (double **) mygethandle(ndata * sizeof(double));
			if (CASEWTS == (double **) 0)
			{
				goto errorExit;
			}
			casewts = *CASEWTS;

			doubleCopy( DATAPTR(symhWts), casewts, ndata);
			for (i = 0; i < ndata; i++)
			{
				if (!isMissing(casewts[i]) && casewts[i] < 0)
				{
					sprintf(OUTSTR,"ERROR: negative case weights for %s()",
							FUNCNAME);
					break;
				}
			} /*for (i = 0; i < ndata; i++)*/
		}
		if(*OUTSTR)
		{
			goto errorExit;
		}
	} /* if(caseweights) */

	/* check for logistic N */
	if (GLMCONTROL & BINOMDIST)
	{
		if (symhN == (Symbolhandle) 0)
		{
			sprintf(OUTSTR,"ERROR: no N variable given for %s()", FUNCNAME);
		}
		else if(!isVector(symhN) || TYPE(symhN) != REAL || 
				symbolSize(symhN) != ndata && symbolSize(symhN) != 1)
		{
			sprintf(OUTSTR,
					"ERROR: %s() N not REAL scalar or vector of same length as response",
					FUNCNAME);
		}
		else
		{
			LOGITN = (double **) mygethandle(ndata * sizeof(double));
			if (LOGITN == (double **) 0)
			{
				goto errorExit;
			}
		}
		if(*OUTSTR)
		{
			goto errorExit;
		}
		inc = (symbolSize(symhN) == 1) ? 0 : 1;
		i2 = 0;
		y = *Y;
		logitn = *LOGITN;
		ptmp = DATAPTR(symhN);
		for (i = 0; i < ndata; i++)
		{
			yi = y[i];
			logitni = logitn[i] = ptmp[i2];
			if (!isMissing(yi) && !isMissing(logitni))
			{
				tmp = floor(logitni);
				if (tmp <= 0.0)
				{
					sprintf(OUTSTR,
							"ERROR:  N values must be nonnegative for %s()",
							FUNCNAME);
				}
				else if (yi < 0.0 || yi > logitni)
				{
					sprintf(OUTSTR,
							"ERROR: response value out of range for %s()",
							FUNCNAME);
				}
				if(*OUTSTR)
				{
					goto errorExit;
				}
				if (!foundNonIntY && yi != floor(yi))
				{
					foundNonIntY = 1;
				}
				if (!foundNonIntN && logitni != tmp)
				{
					foundNonIntN = 1;
				}
			} /*if (!isMissing(yi) && !isMissing(logitni))*/
			i2 += inc;
		}/* for (i = 0; i < ndata; i++) */
	} /*if (GLMCONTROL & BINOMDIST)*/
	else if (GLMCONTROL & POISSONDIST)
	{/* check for nonnegative Y in Poisson distributed glm */
		y = *Y;
		for (i = 0; i < ndata; i++)
		{
			yi = y[i];
			if (!isMissing(yi))
			{
				if (yi < 0.0)
				{
					sprintf(OUTSTR,
							"ERROR: response variable negative for %s()",
							FUNCNAME);
					goto errorExit;
				}
				if (!foundNonIntY && floor(yi) != yi)
				{
					foundNonIntY = 1;
				}
			} /*if (!isMissing(yi))*/			
		} /*for (i = 0; i < ndata; i++)*/
	} /*if (glmcontrol & POISSONDIST)*/

	if (!silent)
	{
		if (foundNonIntY)
		{
			sprintf(OUTSTR,
					"WARNING: non-integer value(s) of response variable for %s()",
					FUNCNAME);
			putErrorOUTSTR();
		}
		if (foundNonIntN)
		{
			sprintf(OUTSTR,
					"WARNING: non-integer number N of trials for %s()",
					FUNCNAME);
			putErrorOUTSTR();
		}
	} /*if (!silent)*/
	
	/* check for user defined glmoffset */

	if (symhOffset != (Symbolhandle) 0)
	{
		if (TYPE(symhOffset) != REAL || !isVector(symhOffset) ||
			symbolSize(symhOffset) != ndata)
		{
			sprintf(OUTSTR,
					"ERROR: offsets for %s() not REAL vector nrows(offset) = nrows(response)",
					FUNCNAME);
			goto errorExit;
		}

		USEGLMOFFSET = 1;
		GLMOFFSET = (double **) mygethandle(ndata * sizeof(double));
		if (GLMOFFSET == (double **) 0)
		{
			goto errorExit;
		}
		doubleCopy(DATAPTR(symhOffset), *GLMOFFSET, ndata);
	} /*if (symhOffset != (Symbolhandle) 0)*/

	/* check for missing & fill MISSWTS if any are missing*/
	nmissing = countMissing(MODELINFO, &MISSWTS);
	if(nmissing < 0)
	{
		goto errorExit;
	}

	if(caseweights || GLMCONTROL & BINOMDIST || USEGLMOFFSET)
	{
		casewts = (caseweights) ? *CASEWTS : (double *) 0;
		logitn = (GLMCONTROL & BINOMDIST) ? *LOGITN : (double *) 0;
		glmoffset = (USEGLMOFFSET) ? *GLMOFFSET : (double *) 0;
		misswts = (nmissing > 0) ? *MISSWTS : (double *) 0;
		for (i = 0; i < ndata; i++)
		{
			if (caseweights && isMissing(casewts[i]) ||
				(GLMCONTROL & BINOMDIST) && isMissing(logitn[i]) ||
				USEGLMOFFSET && isMissing(glmoffset[i]))
			{
				if(nmissing == 0)
				{
					MISSWTS = (double **) mygethandle(ndata * sizeof(double));
					if (MISSWTS == (double **) 0)
					{
						goto errorExit;
					}
					misswts = *MISSWTS;
					doubleFill(misswts, 1.0, ndata);
					casewts = (caseweights) ? *CASEWTS : (double *) 0;
					logitn = (GLMCONTROL & BINOMDIST) ? *LOGITN : (double *) 0;
					glmoffset = (USEGLMOFFSET) ? *GLMOFFSET : (double *) 0;
				} /*if(nmissing == 0)*/
				if (misswts[i] != 0.0)
				{
					misswts[i] = 0.0;
					nmissing++;
				}
			}
		} /*for (i = 0; i < ndata; i++)*/
	} /*if(caseweights || GLMCONTROL & BINOMDIST || USEGLMOFFSET)*/
	
	if(nmissing > 0)
	{
		MODELTYPE |= MISSWEIGHTS;
		GLMCONTROL |= UNBALANCED;
		misswts = *MISSWTS;
	} /*if(nmissing > 0)*/

	/* find the actual maximum factor levels included */
	if (nfactors > 0)
	{
		for (j = 0; j < nvars; j++)
		{
			if (!isVariate(j))
			{
				factorvar = *(X[j]);
				maxlevel = 0;
				for (i = 0;i < ndata; i++)
				{
					if (!isMissing(factorvar[i]) && factorvar[i] > maxlevel &&
						(nmissing == 0 || misswts[i] > 0.0))
					{
						maxlevel = factorvar[i];
					}
				} /*for (i = 0;i < ndata; i++)*/
				NCLASSES[j] = (long) maxlevel;
			} /*if (!isVariate(j))*/
		} /*for (j = 0; j < nvars; j++)*/
	} /*if (nfactors > 0)*/
	
	if (nmissing > 0 && !silent)
	{
		putOutErrorMsg("WARNING: cases with missing values deleted");
	}

	/* check for zero case weights, i.e., user specified weights */
	if (caseweights)
	{
		casewts = *CASEWTS;
		misswts = (MODELTYPE & MISSWEIGHTS) ? *MISSWTS : (double *) 0;
		nzerowt = 0;
		for (i = 0; i < ndata; i++)
		{
			if ((!(MODELTYPE & MISSWEIGHTS) || misswts[i] > 0.0) &&
				casewts[i] == 0)
			{
				nzerowt++;
			}
		}
		if (nzerowt != 0 && !silent)
		{
			putOutErrorMsg("WARNING: cases with zero weight completely removed");
		}
		nmissing += nzerowt;
	} /*if (caseweights)*/
	NOTMISSING = NDATA - nmissing;

	if(NOTMISSING == 0)
	{
		sprintf(OUTSTR,
				"ERROR: no non-missing cases with non-zero weight");
		goto errorExit;
	}
	
	/*
	   Check for possible Latin Square or other balanced main effect design
	    for which balanced computation is appropriate
	  In the future, we need code to recognize fractional factorials,
	  confounded factorials, etc
	 */

	balanced = (!(GLMCONTROL & UNBALANCED) && !(MODELTYPE & FASTANOVA) &&
				isBalanced(ONEWAYBALANCE));
	
	if (balanced && nvars > 1)
	{
		if (anovaEffectsOnly(1))
		{
			balanced = isBalanced(TWOWAYBALANCE);
		}
		else
		{
			balanced = isBalanced(COMPLETEBALANCE);
		}
		if (balanced < 0)
		{
			goto errorExit;
		}
	} /*if (balanced)*/
	
	if(!balanced)
	{
		GLMCONTROL |= UNBALANCED;
		if (MODELTYPE & IPF)
		{
			MODELTYPE &= ~IPF;
			MODELTYPE |= POISSONREG;
			if(!silent)
			{
				putOutErrorMsg(ipfwarning);
			}
		}
	} /*if(!balanced)*/

	/* check for incremental deviances specified by extra argument */
	if (MODELTYPE & (ITERGLMS | IPF) && !INCREMENTAL &&
		nargs > startKey && !isKeyword(COMPVALUE(list,nargs-1)))
	{
		INCREMENTAL = 1;
	}

	/*
	  990319 moved creation of side-effect variables DEPVNAME and
	  TERMNAMES to glm()
    */
	/* save dependent variable name */
	needed = strlen(VARNAME(0)) + 1;
	
	DEPVNAME = mygethandle(needed);
	if(DEPVNAME == (char **) 0)
	{
		goto errorExit;
	}
	/* re-dereference name after memory allocation */
	strcpy(*DEPVNAME, VARNAME(0));
	
	/* Create TERMNAMES */
	needed = makeTermNames(0); /* get space requirement */
	TERMNAMES = mygethandle(needed);
	if (TERMNAMES == (char **) 0)
	{
		goto errorExit;
	}
	
	/* now fill in TERMNAMES */

	(void) makeTermNames(needed);

	emptyTrash();
	
	return (0); /* normal (no error) return */

/* NOTE: cleanup of globals is done in glm after error return */
 errorExit:
	putErrorOUTSTR();
	emptyTrash();
	if(info != (modelInfoPointer) 0)
	{
		mydisphandle((char **) info->model);
		MODEL = info->model = (modelHandle) 0;
	}
	
	return (1);

} /*getmodel()*/
static long makeTermNames(long needed)
{
	long             i, k;
	long             nterms = NTERMS;
	long             nerrorterms = NERRORTERMS;
	long             nvars = NVARS;
	int              countOnly = (needed == 0);
	char            *termNames, *varName;
	modelPointer     kterm;
	WHERE("makeTermNames");
	
	if (!countOnly)
	{
		termNames = *TERMNAMES;
	}	

	for (i = 0; i < nterms; i++)
	{
		kterm = modelterm(MODEL,i);
		if (modeltermEqual(kterm,(modelPointer) NULLTERM))
		{
			varName = "CONSTANT";
			if (countOnly)
			{
				needed += strlen(varName) + 1;
			}
			else
			{
				strcpy(termNames, varName);
				termNames = skipStrings(termNames, 1);
			}			
		} /*if (modeltermEqual(kterm,(modelPointer) NULLTERM))*/
		else
		{
			/* check to see if it is an error term */
			for (k = 0; k < nerrorterms - 1; k++)
			{
				if (modeltermEqual(kterm, MODELINFO->errorterms + k))
				{
					varName = "ERROR";
					if (countOnly)
					{
						needed += strlen(varName) + ((k >= 9) ? 2 : 1) + 1;
					}
					else
					{
						strcpy(termNames, varName);
						termNames = skipStrings(termNames, 1) - 1;
						if(k >= 9)
						{
							*termNames++ = (k+1)/10 + '0';
						}
						*termNames++ = (k+1)%10 + '0';
						*termNames++  = '\0';
					}
					break;
				} /*if (modeltermEqual(kterm, MODELINFO->errorterms + k))*/
			} /*for (k = 0; k < nerrorterms - 1; k++)*/

			if (k == nerrorterms - 1)
			{/* regular (not error) term */
				for (k = 0; k < nvars; k++)
				{
					if (inTerm(k,kterm))
					{
						int      evaluated = isevaluated(VARNAMES[k+1]);
						
						varName = VARNAME(k+1);

						if (!evaluated && istempname(varName))
						{/* strip off TEMPPREFIX ('@') if temporary name */
							varName++;
						}
						if (countOnly)
						{
							needed += strlen(varName) + 1;
							if (evaluated)
							{
								needed += 2;
							}
						} /*if (countOnly)*/
						else
						{
							if (evaluated)
							{
								*termNames++ = '{';
							}
							strcpy(termNames, varName);
							termNames = skipStrings(termNames, 1) - 1;
							if (evaluated)
							{
								*termNames++ = '}';
							}
							*termNames++ = 
								(moreInTerm(k,kterm,nvars)) ? '.' : '\0';
						} /*if (countOnly){}else{}*/
					 } /*if (inTerm(k,kterm))*/
				 } /*for (k = 0; k < nvars; k++)*/
			} /*if (k == nerrorterms - 1)*/
		} /*if (modeltermEqual(kterm,(modelPointer) NULLTERM)){...}else{...}*/
	} /*for (i = 0; i < nterms; i++)*/

	varName = "ERROR";
	if (countOnly)
	{
		needed += strlen(varName) + ((nerrorterms > 9) ? 2 : 1) + 1;
	}
	else
	{
		strcpy(termNames, varName);
		termNames = skipStrings(termNames, 1) - 1;
		if(nerrorterms > 9)
		{
			*termNames++ = nerrorterms/10 + '0';
		}
		*termNames++ = nerrorterms%10 + '0';
		*termNames++ = '\0';
	} /*if (countOnly){}else{}*/
			
	return (needed);
} /*makeTermNames()*/
Example #5
0
LPEXP KlwGetBinding(ATOMID idVarName)
{
    varctx ctx = varstack ? (varctx) GLOBALLOCK(varstack->hCtx) : NULL;

    while (ctx) {
        GLOBALHANDLE hPrev = ctx->hPrev;
        LPEXP lpBinding = NULL;
        
        if (ctx->idCode && ctx->idCode != srclns.idCode ||
            ctx->wType && ctx->wType != srclns.wType)
        {
            GLOBALUNLOCK(ctx->hCtx);
            return NULL;
        }
        
        if (ctx->idVarList)
        {
            VARID idVar;
            LIST_LOOP loop;
            
            kpc_init_loop(ctx->idVarList, &loop);
            
            while (idVar = next(&loop)) {
                LPVAR lpVar = (LPVAR) KppGetItem(VAR, idVar);
                
                if (lpVar)
                {
                    LISTID idBindings = BINDINGS(lpVar);
                    ITEMID idValue = VARVALUE(lpVar);
                    ATOMID idName = VARNAME(lpVar);
                    WORD wFlags = VARFLAGS(lpVar);
                
                    KppReleaseItem(VAR, idVar);
                    if (idName == idVarName)
                    {
                        if (wFlags & EXPBOUND)
                        {
                            EXPFLAGS(&resexp) = wFlags;
                            CAR(&resexp) = idValue;
                            lpBinding = &resexp;
                        }
                        else if (idBindings)
                        {
                            WORD wIndex = KppGetElem(idBindings, 1);
                        
                            if (!wIndex)
                                break;
                            lpBinding = ctx->lpBody + wIndex - 1;
                        }
                        break;
                    }
                }
            }
        }
        
        GLOBALUNLOCK(ctx->hCtx);
            
        if (lpBinding)
            return lpBinding;
            
        if (hPrev)
            ctx = (varctx) GLOBALLOCK(hPrev);
        else
            return NULL;
    }
    
    return NULL;
}