*! v1.0.1 25/6/02 ARB
* Now using tabdisp to show results
*! Tabulate a variable in multi-record data
program define xtab, rclass sortpreserve byable(recall)
	version 7
	syntax varname [if] [in] [, I(varname) T(varname) Missing OCCasion(string)]
	xt_iis `i'
	local ivar "`s(ivar)'"
	marksample touse, novarlist
	markout `touse' `ivar'
	qui count if `touse'== 1
	if r(N)==0 {
		disp "{txt:no observations}"
		exit
	}
	if !missing("`occasion'") {
		* check occasion is valid
		local l=length("`occasion'")
		if "`occasion'" == substr("ever",1,`l') {
			local prot 1
			local footn * Number of clusters where value has ever occurred
		}
		else if "`occasion'" == substr("never",1,`l') {
			local prot 2
			local footn * Number of clusters where value has never occurred
		}
		else if "`occasion'" == "1" | "`occasion'" == substr("first",1,`l') | "`occasion'" == "min" {
			local prot 3
			local occasion 1
			local footn * Number of clusters where value occurred in first observation
		}
		else if "`occasion'" == "_N" | "`occasion'" == substr("last",1,`l') | "`occasion'" == "max" {
			local prot 4
			local occasion _N
			local footn * Number of clusters where value occurred in last observation
		}
		else {
			* is occasion a number?
			cap confirm integer number `occasion'
			if _rc {
				disp "{error:occasion not recognised}
				exit 198
			}
			if `occasion'==2 {
				local desc 2nd
			}
			else if `occasion'==3 {
				local desc 3rd
			}
			else if `occasion'>3 {
				local desc `occasion'th
			}
			local footn * Number of clusters where value occurred in `desc' observation
			local prot 5
		}
	}
	else {
		local prot 1
	}
	preserve
	tempvar flag N uniq svar
	qui {
	if `prot'>2 {
		* occasion specific - time var must be defined
		xt_tis `t'
		local tvar "`s(timevar)'"
		markout `touse' `tvar'
		count if `touse'== 1
		if r(N)==0 {
			nois disp "{txt:no observations}"
			exit
		}
		sort `ivar' `touse' `tvar'
		if missing("`missing'") {
			by `ivar' `touse': gen byte `uniq' = (_n==`occasion' & `touse' & !missing(`varlist'))
		}
		else {
			by `ivar' `touse': gen byte `uniq' = (_n==`occasion' & `touse')
		}
		by `ivar' `touse': gen byte `flag'=(_n==`occasion' & `touse')
	}
	else {
		* ever/never
		bysort `ivar' `touse': gen byte `uniq' = (_n==1 & `touse')
		bysort `ivar' `varlist' `touse': gen byte `flag'=(_n==1 & `touse')
	}
	summ `uniq', meanonly
	local Ntot = r(sum)
	if `prot'==2 {
		* never
		bysort `varlist' `flag': gen `N'=`Ntot'-_N if _n==1 & `touse'
	}
	else {
		* ever or occasion
		bysort `varlist' `flag': gen `N'=_N if _n==1 & `touse'
	}
	keep if `flag' & !missing(`N')
	if missing("`missing'") {
		drop if missing(`varlist')
	}
	if missing("`footn'") {
		local fti Freq.
	}
	else {
		local fti Freq*
	}
	* Output
	local varlab : variable label `varlist'
	if missing("`varlab'") { local varlab `varlist' }
	local vlab : value label `varlist'
	local stubsize 11
    	* Calculate stub size
	tokenize `varlab'
	while !missing("`1'") {
		if length("`1'")>`stubsize' {
			local stubsize=length("`1'")+1
		}
		mac shift
	}
	* Turn var into string
	local type : type `varlist'
	if substr("`type'",1,3)=="str" {
		gen `type' `svar'=`varlist'
		compress `svar'
	}
	else {
		if "`vlab'"!="" {
			decode `varlist', gen(`svar') maxlen(31)
		}
		else {
			gen str1 `svar'=""
		}
		replace `svar'=string(`varlist') if missing(`svar')
	}
	* Get maximum value label length
	local type : type `svar'
	local s = substr("`type'",4,.)
	local stubsize = cond(`s'>`stubsize',`s',`stubsize')
	local ssp1 = `stubsize'+1
	}	/* end quietly */
    	* Display variable label
	foreach 1 of local varlab {
		local todisp `nextdisp'
		local nextdisp `nextdisp' `1'
		if length("`nextdisp'")>`stubsize' {
			disp _n "{txt}{ralign `stubsize':`todisp'} {c |}" _c
			local nextdisp `1'
		}
	}
	if !missing("`nextdisp'") {
		disp _n "{txt}{ralign `stubsize':`nextdisp'} {c |}" _c
	}
	disp "{txt} {ralign 10:`fti'} {ralign 11:Percent}"
	disp "{txt}{hline `ssp1'}{c +}{hline 23}"
	local j 1
	while `j' <= _N {
		local stub = `svar'[`j']
		disp "{txt}{ralign `stubsize':`stub'} {c |} {res}" /*
			*/ %10.0f `N'[`j'] /*
			*/ %12.2f 100*`N'[`j']/`Ntot'
		local j=`j'+1
	}
	disp "{txt}{hline `ssp1'}{c +}{hline 23}"
	disp "{txt}{ralign `stubsize':Total} {c |} {res}" /*
		*/ %10.0f `Ntot' /*
		*/ %12.2f 100
	disp "{txt}`footn'"
end