*! tobexog V1.1.3   C F Baum   0216
* Ref: Smith and Blundell, Econometrica 54:3, 679-686

program define tobexog, rclass
	version 6.0

* parsing code and subroutines taken from -ivreg-  5.0.4
		local n 0

		gettoken lhs 0 : 0, parse(" ,[") match(paren)
		IsStop `lhs'
		if `s(stop)' { error 198 }
		while `s(stop)'==0 {
			if "`paren'"=="(" {
				local n = `n' + 1
				if `n'>1 {
					capture noi error 198
					di in red `"syntax is "(all instrumented variables = instrument variables)""'
					exit 198
				}
				gettoken p lhs : lhs, parse(" =")
				while "`p'"!="=" {
					if "`p'"=="" {
						exit 198
					}
					local end`n' `end`n'' `p'
					gettoken p lhs : lhs, parse(" =")
				}
				tsunab end`n' : `end`n''
				tsunab exog`n' : `lhs'
			}
			else {
				local exog `exog' `lhs'
			}
			gettoken lhs 0 : 0, parse(" ,[") match(paren)
			IsStop `lhs'
		}
		local 0 `"`lhs' `0'"'

		tsunab exog : `exog'
		tokenize `exog'
		local lhs "`1'"
		local 1 " "
		local exog `*'

* NJC suggested code to handle either/both required options
*     problem: ll or ul is sufficient by itself; must accept them as well
* ROC guidance in handling weights

		syntax [if] [in] [aw fw] [,ll(str) ul(str) *]
		local wtype `weight'
		local wtexp "`exp'"
		if "`weight'" != "" { local wgt `"[`weight' `exp']"' }

		local trunc=""
		if "`ll'" != "" {
			local trunc "ll(`ll')"
		}
		else if index(" `options' ", " ll ") {
			local trunc "ll"
		}
		if "`ul'" != "" {
			local trunc "`trunc' ul(`ul')"
		}
		else if index(" `options' ", " ul ") {
			local trunc "`trunc' ul"
		}
		if "`trunc'" == "" {
			di in r "must specify either ll( ) or ul( ) or both"
			exit 198
		}

		marksample touse
		markout `touse' `lhs' `exog' `exog1' `end1'

		Subtract newexog : "`exog1'" "`exog'"
		local endo_ct : word count `end1'
		local ex_ct : word count `newexog'
		if `endo_ct' > `ex_ct' {
			di in red "equation not identified; must have at " /*
			*/ "least as many instruments not in"
			di in red "the model as there are "           /*
			*/ "instrumented variables"
			exit 481
		}
* qui predict
		tokenize `end1'
		local rhadd " "
		local i 1
		while "``i''" != "" {
			qui regress ``i'' `exog' `newexog' `wgt' if `touse'
			tempvar v_`i'
			qui predict `v_`i'',r
* 0216: syntax per dmexog
			local rhadd `rhadd' `v_`i''
			local i = `i' + 1
		}

		local insts `exog' `newexog'
		qui tobit `lhs' `end1' `exog' `rhadd' `wgt' if `touse', `trunc'
		qui test `rhadd'
		return scalar df = r(df)
		return scalar df_r = r(df_r)
		return scalar tobexog = r(F)
		return scalar p = r(p)

		di in gr _n "Smith-Blundell test of exogeneity: "   /*
		*/ in ye %9.0g return(tobexog) in gr            /*
		*/ in gr "  F(" %2.0f in ye return(df) "," return(df_r) /*
		*/ in gr ")  P-value = " in ye %6.0g return(p)
end

program define IsStop, sclass
				/* sic, must do tests one-at-a-time,
				 * 0, may be very large */
	if `"`0'"' == "[" {
		sret local stop 1
		exit
	}
	if `"`0'"' == "," {
		sret local stop 1
		exit
	}
	if `"`0'"' == "if" {
		sret local stop 1
		exit
	}
	if `"`0'"' == "in" {
		sret local stop 1
		exit
	}
	if `"`0'"' == "" {
		sret local stop 1
		exit
	}
	else	sret local stop 0
end

/*  Remove all tokens in dirt from full */
 *  Returns "cleaned" full list in cleaned */

program define Subtract   /* <cleaned> : <full> <dirt> */
	args	    cleaned     /*  macro name to hold cleaned list
		*/  colon	/*  ":"
		*/  full	/*  list to be cleaned
		*/  dirt	/*  tokens to be cleaned from full */

	tokenize `dirt'
	local i 1
	while "``i''" != "" {
		local full : subinstr local full "``i''" "", word all
		local i = `i' + 1
	}

	tokenize `full'			/* cleans up extra spaces */
	c_local `cleaned' `*'
end

exit