program define swapval
*! 1.0.1 NJC 24 November 1999
	version 6.0

	gettoken a 0 : 0
	unab varlist : `a', min(1) max(2)
	local nvars : word count `varlist'

	if `nvars' == 1 {
		gettoken b 0 : 0
		unab varlist: `a' `b', min(2) max(2)
	}

	tokenize `varlist'
	args a b

	capture confirm string variable `a'
	local aisnum = _rc > 0
	capture confirm string variable `b'
	local bisnum = _rc > 0
	if `aisnum' != `bisnum' {
		di in r "variables must be compatible types"
		error 109
	}

	gettoken inif 0 : 0
	if "`inif'" != "in" & "`inif'" != "if"  & "`inif'" != "" {
		di in r "incorrect syntax"
		exit 198
	}

	if "`inif'" == "in" {
		local n = _N
		if index("`0'", "l") {
			local 0 : subinstr local 0 "l" "`n'"
		}
		if index("`0'", "f") {
			local 0 : subinstr local 0 "f" "1"
		}
		numlist "`0'", int range(>=-`n' <=`n') sort

		chkzero `r(numlist)'

		tokenize `r(numlist)'
	}
	else if "`inif'" == "if"  {
	* test whether `if' condition is acceptable
		qui count if `0'
		if r(N) == 0 {
			di in r "no observations"
			exit 2000
		}
		else local if "if `0'"
	}

	nobreak {

	if "`inif'" == "in" {
		if `aisnum' { /* both variables numeric */
		* I'm guessing here using locals, rather than copying
		* all values for variable, is usually quicker
			qui while "`1'" != "" {
				local 1 = cond(`1' < 0, `n'+`1'+1, `1')
				local copy = `b'[`1']
				replace `b' = `a' in `1'
				replace `a' = `copy' in `1'
				mac shift
			}
		}
		else { /* both variables string */
		* copy variable to keep leading and trailing spaces
			tempvar copy
			local btype : type `b'
			qui gen `btype' `copy' = `b'
			qui while "`1'" != "" {
				replace `b' = `a' in `1'
				replace `a' = `copy' in `1'
				mac shift
			}
		}
	}

	else if "`inif'" == "if" { /* if */
		tempvar copy
		local btype : type `b'
		qui gen `btype' `copy' = `b'
		qui replace `b' = `a' `if'
		qui replace `a' = `copy' `if'
	}

	else {
	* < nothing > => swapping whole variables, so just -rename-
		tempname copy
		rename `b' `copy'
		rename `a' `b'
		rename `copy' `a'
	}

	} /* end nobreak */

	qui compress `a' `b'

end

program def chkzero
* 1.0.1 NJC 24 November 1999
* The arguments are sorted.
* If the first is >0, we need do nothing but exit gracefully.
* If the first is 0, we have found a zero.
* If the first is <0, we search our way past the - elements.
* Thanks to Bill Gould for an improvement.
	if `1' > 0 {
		exit 0
	}
	else if `1' == 0 {
		di in r "0 invalid obs no"
		exit 198
	}
	else {
		local i = 1
		local nnum : word count `0'
		while ``i'' < 0 & `i' < `nnum' {
			local i = `i' + 1
			if ``i'' == 0 {
				di in r "0 invalid obs no"
				exit 198
			}
		}
	}
end