*! version 3.1.4  19sep1997  Statalist distribution
program define stack
	version 5.0
	local varlist "req ex min(2)"
	local if "opt"
	local in "opt"
	local options "Into(str) Group(integer 0) CLEAR WIde"
	parse "`*'"
	if ("`into'"=="") {
		if `group'==0 {
			error 198
		}
		Makeinto `group' `varlist'
	}
	else {
		if `group'!=0 {
			di in red "may not specify both group() and into()"
			exit 198
		}
		Fixinto `into'
	}
	local into $S_1
	global S_1

					/* # of args in varlist */
	local vcnt : word count `varlist'
					/* # of args in into()	*/
	local icnt : word count `into'

	local grps `vcnt'/`icnt'	/* # of groups		*/
	if (`grps' != int(`grps') | `grps'<=1) {
		di in red "incorrect number of variables specified"
		exit 198
	}

/*
Removed by wwg 19sep1997-- Stata 5 automatically repartitions memory
			/* verify whether the result will fit	*/
	quietly describe, short
	local maxobs = _result(4)	/* size of partition	*/
	capture count `if' `in'
	local newobs = _result(1)*`grps'	/* # of new obs	*/
	if (`newobs' > `maxobs'-20) {
		di in red "insufficient memory (observations)"
		di in red "`newobs' required and " `maxobs'-20 " available."
		exit 901
	}
*/
			/* present warning			*/
	if "`clear'"=="" {
		di in blu "Warning:  data in memory will be lost." /*
			*/ _n _col(10) /*
			*/ "Press any key to continue, Ctrl-Break to abort."
		set more 0
		more
	}

	tempfile stacktp
			/* save data needed to stack		*/
	if ("`if'"!="" | "`in'"!="") {
		quietly keep `if' `in'
	}
	keep `varlist'
	quietly save "`stacktp'", replace

			/* preserve varlist for wide option	*/
	local vlist "`varlist'"

			/* stack the data			*/
	local grp "1"
	capture {
		while (`grp' <= `grps') {
			parse "`varlist'", parse(" ")
			local i "1"
			local touse
			while (`i' <= `icnt') {
				local touse "`touse' `1'"
				mac shift
				local i = `i' + 1
			}
			local varlist "`*'"	/* reset varlist	*/
			quietly use "`stacktp'", clear
			keep `touse'
			gen int _stack = `grp'
			local i "1"
			while (`i' <= `icnt') {
				local name1 : word `i' of `touse'
				local new1  : word `i' of `into'
				if ("`name1'" != "`new1'") {
					rename `name1' `new1'
				}
				local i = `i' + 1
			}
			tempfile tempfi
			local tf`grp' "`tempfi'"
			quietly save "`tempfi'"
			local grp = `grp' + 1
		}

		quietly use "`tf1'", clear
		local grp 2
		while (`grp' <= `grps') {
			quietly append using "`tf`grp''"
			local grp = `grp' + 1
		}				/* done		*/
		if ("`wide'"!="") { 		/* wide option	*/
			local grp 1
			while (`grp' <= `grps') {
				parse "`vlist'", parse(" ")
				local i "1"
				local touse
				while (`i' <= `icnt') {
					local touse "`touse' `1'"
					mac shift
					local i = `i' + 1
				}
				local vlist "`*'"
				local i "1"
				while (`i' <= `icnt') {
					local name1 : word `i' of `touse'
					capture confirm new variable `name1'
					if (_rc==0) {
						local name2 : word `i' of `into'
						local type : type `name2'
						quietly gen `type' `name1' = /*
							*/ `name2' /*
							*/ if _stack==`grp'
					}
					local i = `i' + 1
				}
				local grp = `grp' + 1
			}
		}
		exit
	}
				/* error-abort code	*/
	if (_rc) {
		local rc = _rc
		drop _all
		di in red "(memory cleared)"
		error `rc'
	}
end


program define Fixinto /* newvarlist */
	parse "`*'", parse("- ")
	while "`1'" != "" {
		if "`2'"=="-" {
			Split "`1'" "`1' `2' `3'"
			local stub "$S_1"
			local n1 $S_2
			Split "`3'" "`1' `2' `3'"
			local n2 "$S_2"
			if "`stub'" != "$S_1" | `n1'>`n2' {
				Fixerr "`1' `2' `3'"
				/*NOTREACHED*/
			}
			local i `n1'
			while `i' <= `n2' {
				local res "`res' `stub'`i'"
				local i = `i' + 1
			}
			mac shift 3
		}
		else {
			local res "`res' `1'"
			mac shift
		}
	}
	global S_2
	global S_1 "`res'"
end


program define Split /* "varname#" "string for error message" */
	if "`1'"=="" {
		Fixerr "`2'"
		/*NOTREACHED*/
	}
	local l = length("`1'")
	while index("0123456789",substr("`1'",`l',1)) {
		local l = `l' - 1
		if `l' == 0 {
			Fixerr "`2'"
			/*NOTREACHED*/
		}
	}
	global S_1 = substr("`1'",1,`l')
	global S_2 = substr("`1'",`l'+1,.)
	if "$S_1"=="" | "$S_2"=="" {
		Fixerr "`2'"
		/*NOTREACHED*/
	}
end

program define Fixerr
	di in red _quote "`1'" _quote " invalid"
	exit 198
end

program define Makeinto /* # varnames */
	local g "`1'"
	if `g' <= 0 {
		di in red "group(`g') invalid"
		exit 198
	}
	mac shift
	local n : word count `*'
	local v = `n' / `g'
	if `v' != int(`v') | `v'==0 {
		di in red "`n' variables cannot be stacked into `g' groups;"
		di in red "there would be " `v' " variables/group."
		exit 198
	}
	local i 1
	global S_1
	while `i' <= `v' {
		global S_1 $S_1 ``i''
		local i = `i' + 1
	}
end
exit