*! version 1.0.1 NJC 1 June 1997 strok on markout
* version 1.0.0 PR 05Jul95.            (STB-27: ip9)
program define byvar2 /* byvar2 [, options] : stata_cmd */
version 3.1
parse "`*'", parse(" ,:")
while "`1'"!="," & "`1'"!=":" {
	if "`1'"=="" { error 198 }
	local bylist "`bylist' `1'"
	mac shift
}
if trim("`bylist'")=="" {
	error 198
}
if "`1'"=="," {
	mac shift
	while "`1'"!=":" {
		if "`1'"=="" { error 198 }
		local optlist "`optlist' `1'"
		mac shift
	}
}
mac shift		/* the colon 	*/
local command `*'	/* the Stata cmd */

_crcunab `bylist'
local bylist $S_1

parse "`command'", parse(",")
local cmd1 `1'
mac shift
local cmd2 `*'
local pif=index("`cmd1'", " if ")
if `pif'>0 {
	local cmd11=substr("`cmd1'",1,`pif')
	local cmd12=substr("`cmd1'",`pif'+4,.)
	local ifalso " & "
}
else local cmd11 `cmd1'

#delimit ;
local options "Macro(str) Result(str) Coef(str) Se(str) GRoup(str) GENerate
 TAbulate STore MIssing Pause" ;
#delimit cr

parse ", `optlist'"
if "`group'"!="" { confirm new var `group' }

local s1 "`macro'"
local L1 M
local s2 "`result'"
local L2 R
local s3 "`coef'"
local L3 C
local s4 "`se'"
local L4 S
local tostore="`s1'`s2'`s3'`s4'"!=""
if !`tostore' & "`generat'`store'`tabulat'"!="" {
	di in red "nothing to generate, store or tabulate"
	exit 198
}
if `tostore' & "`generat'`store'`tabulat'"=="" {
	di in red "nowhere to store or tabulate results"
	exit 198
}

local tab="`tabulat'"!="" & `tostore'

/* Number and count the groups	*/
quietly {
/*
	Default is to exclude missing groups in bylist from analysis.
	Their corresponding group codes are set to missing and sorted to
	end of data.
*/
	tempvar grp touse first
	mark `touse'
	if "`missing'"=="" {
		markout `touse' `bylist', strok
		replace `touse'=. if `touse'==0
	}
	sort `touse' `bylist'
	by `touse' `bylist': gen byte `first'=1 if _n==1 & `touse'==1
	gen int `grp'=sum(`first') if `touse'==1
	drop `touse'
	sum `grp'
	local GRP=_result(6)
	if `GRP'==0 { noisily error 2000 }

	local itemlen 14
/*
	Extract group-defining values of bylist variables
	and store in macros
*/
	local nby : word count `bylist'
	if `tab' {
		noi di
		local dashes
	}
	tempvar index
	gen long `index'=.
	local i 1
	while `i'<=`GRP' {
		replace `index'=sum(_n*(`grp'==`i' & `first'==1))
		local j=`index'[_N]
		local k 1
		while `k'<=`nby' {
			local byvar`k' : word `k' of `bylist'
			local by`i'`k'=`byvar`k''[`j']
			if `i'==1 & `tab' {
				local dashes "`dashes'---------"
				local skip=9-length("`byvar`k''")
				noi di _skip(`skip') in gr "`byvar`k''" _c
			}
			local k=`k'+1
		}
		local i=`i'+1
	}
	drop `index'
}
if `tab' {
	di in gr " |" _c
	local dashes "`dashes'-+"
}
/*
	Parse and record items for storage
*/
local j 1
while `j'<=4 {
	local i 1
	if "`s`j''"!="" {
		parse "`s`j''", parse(" ")
		local k 1
		while "`1'"!="" {
			local sk`k' "`1'" /* item[:label] */
			local k=`k'+1
			mac shift
		}
		local l 1
		while `l'<`k' {
			parse "`sk`l''", parse("=")
			if "`4'"!="" {
				di in red "invalid `sk`l''"
				exit 198
			}
			local st`j'`i' `1' /* item to be stored */
			if "`3'"=="" {
				if      `j'==1 { local lab "macro `1'" }
				else if `j'==2 { local lab "_result(`1')" }
				else if `j'==3 { local lab "_b[`1']" }
				else if `j'==4 { local lab "_se[`1']" }
			}
			else {
				local lab=substr("`3'",1,`itemlen'-1)
			}
			if "`generat'"!="" {
				cap drop _`L`j''_`i'
				qui gen _`L`j''_`i'=.
				lab var _`L`j''_`i' "`lab' by `bylist'"
			}
			if `tab' {
				local dashes "`dashes'--------------"
				local skip=`itemlen'-length("`lab'")
				di in gr _skip(`skip') "`lab'" _c
			}
			local i=`i'+1
			local l=`l'+1
		}
	}
	local n`j'=`i'-1
	local j=`j'+1
}
if `tab' { di _n in gr "`dashes'" }

/* Perform calcs		*/
if `tab' { local show quietly }
tempname thing
local i 1
while `i'<=`GRP' { /* i indexes members of groups implied by bylist */
	if !`tab' {
		di in bl _n "-> " _c
		local k 1
		while `k'<=`nby' {
			di in bl "`byvar`k''==`by`i'`k'' " _c
			local k=`k'+1
		}
		di
	}
	`show' `cmd11' if `grp'==`i' `ifalso' `cmd12' `cmd2'
	if "`pause'"!="" { more }

	if `tab' {
*		di in ye %8.0g `i' _c
		local k 1
		while `k'<=`nby' {
			di %9.0g `by`i'`k'' _c
			local k=`k'+1
		}
		di in gr " |" _c
	}
	local k 1
	while `k'<=4 { /* k indexes the 4 types of thing to be stored */
	    if `n`k''>0 {
		local l 1
		while `l'<=`n`k'' { /* l indexes # of thing */
		    if `k'==1 {
			scalar `thing'=${`st`k'`l''}
		    }
		    else if `k'==2 {
			scalar `thing'=_result(`st`k'`l'')
		    }
		    else if `k'==3 {
			scalar `thing'=_b[`st`k'`l'']
		    }
		    else if `k'==4 {
			scalar `thing'=_se[`st`k'`l'']
		    }
		    if "`generat'"!="" {
			qui replace _`L`k''_`l'=`thing' if `grp'==`i'
		    }
		    if "`store'"!="" {
			global `L`k''`l'_`i'=`thing'
		    }
		    if `tab' {
			di _skip(4) in ye %10.0g `thing' _c
		    }
		    local l=`l'+1
		}
	    }
	    local k=`k'+1
	}
	if `tab' { di }
	local i=`i'+1
}
if "`group'"!="" {
	cap drop `group'
	rename `grp' `group'
	lab var `group' "group by `bylist'"
}
global S_1 `GRP'
end