*! version 2.0.3 PR 03apr2007. program define byvar, rclass sortpreserve version 8 tokenize `"`0'"', parse(":") if "`2'"!=":" { di as err "syntax error - maybe missing colon, or unmatched quotes somewhere" exit 198 } local 0 `1' mac shift 2 // skip the colon local command `*' syntax varlist [if] [in], [ E(str) R(str) B(str) SE(str) GRoup(str) GEnerate /// Tabulate REturn Missing Pause noLabel Unique SEParator(string) ] if "`group'"!="" confirm new var `group' if "`unique'"!="" & "`generate'"=="" { di as err "unique requires generate" exit 198 } local bylist `varlist' local s1 `e' local L1 E local s2 `r' local L2 R local s3 `b' local L3 B local s4 `se' local L4 S local tostore=`"`s1'`s2'`s3'`s4'"'!="" if !`tostore' & "`generate'`return'`tabulate'"!="" { di as err "nothing to generate, return or tabulate" exit 198 } if `tostore' & "`generate'`return'`tabulate'"=="" { di as txt "(tabulate assumed)" local tabulat tabulate } local tab="`tabulate'"!="" & `tostore' * Extract multiple commands local ncmd 0 if "`separator'"!="" local sep=substr("`separator'",1,1) else local sep @ tokenize `"`command'"', parse("`sep'") while `"`1'"'!="" { if `"`1'"'!="@" { local ++ncmd local command`ncmd' `1' } mac shift } forvalues i=1/`ncmd' { tokenize `"`command`i''"', parse(",") local cmd1 `1' mac shift local cmd2`i' `*' local pif=index(`"`cmd1'"', " if ") if `pif'>0 { local cmd11`i'=substr(`"`cmd1'"',1,`pif') local cmd12`i'=substr(`"`cmd1'"',`pif'+4,.) local ifalso`i' " & " } else local cmd11`i' `cmd1' } /* 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 first marksample touse, strok 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=r(max) 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'=. forvalues i=1/`GRP' { replace `index'=sum(_n*(`grp'==`i' & `first'==1)) local j=`index'[_N] forvalues k=1/`nby' { local byvar`k' : word `k' of `bylist' local vallab: value label `byvar`k'' local byval=`byvar`k''[`j'] if "`vallab'"!="" & "`label'"!="nolabel" { local by`i'`k': label `vallab' `byval' } else local by`i'`k' `byval' if `i'==1 & `tab' { local dashes "`dashes'---------" noi di as txt %-9s "`byvar`k''" _c } } } drop `index' } if `tab' { di as txt " |" _c local dashes "`dashes'-+" } /* Parse and record items for storage */ forvalues j=1/4 { local i 1 if `"`s`j''"'!="" { tokenize `"`s`j''"' * take care of embedded quotes local k 1 while `"`1'"'!="" { local sk`k' `sk`k'' `1' * Count number of quotes in `1' - should be 2. Do not actually change `1' (discard `z'). local z: subinstr local 1 `"""' "Q", all count(local nquote) // " if `nquote'>0 & `nquote'!=2 { di as err "unmatched quotes in " `"`s`j''"' exit 198 } local ++k mac shift } local l 1 while `l'<`k' { * 1=item, [ 2="=", 3=description of item ], 4=null tokenize `"`sk`l''"', parse("=") local sk`l' if `"`4'"'!="" { di as err "invalid " `"`sk`l''"' exit 198 } local st`j'`i' `1' if `"`3'"'=="" { if `j'==1 local lab e(`1') else if `j'==2 local lab r(`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 "`generate'"!="" { mk_name `L`j'' `1' 6 local `L`j''_`i' `s(name)' qui gen double ``L`j''_`i''=. lab var ``L`j''_`i'' `"`lab' by `bylist'"' } if `tab' { local dashes "`dashes'--------------" local skip=`itemlen'-length(`"`lab'"') di as txt _skip(`skip') `"`lab'"' _c } local ++i local ++l } } local n`j'=`i'-1 } if `tab' di _n as txt "`dashes'" /* Perform calcs */ if `tab' local show quietly else local show noisily tempname thing forvalues i=1/`GRP' { // i indexes members of groups implied by bylist if !`tab' { di as txt _n "-> " _c forvalues k=1/`nby' { di as txt "`byvar`k''==`by`i'`k'' " _c } di } forvalues j=1/`ncmd' { *di `"capture `show' `cmd11`j'' if `grp'==`i' `ifalso`j'' `cmd12`j'' `cmd2`j''"' capture `show' `cmd11`j'' if `grp'==`i' `ifalso`j'' `cmd12`j'' `cmd2`j'' local rc=_rc } if "`pause'"!="" more if `tab' { forvalues k=1/`nby' { di as res %-9s substr("`by`i'`k''",1,8) _c } di as txt " |" _c } forvalues k=1/4 { // k indexes the 4 types of thing to be stored if `n`k''>0 { forvalues l=1/`n`k'' { /* l indexes # of thing */ if `rc'==0 { if `k'==1 scalar `thing'=e(`st`k'`l'') else if `k'==2 scalar `thing'=r(`st`k'`l'') else if `k'==3 scalar `thing'=_b[`st`k'`l''] else if `k'==4 scalar `thing'=_se[`st`k'`l''] } else scalar `thing'=. if "`generate'"!="" { if "`unique'"=="" qui replace ``L`k''_`l''=`thing' if `grp'==`i' else qui replace ``L`k''_`l''=`thing' if `grp'==`i' & `first'==1 } if "`return'"!="" { * gp refers to subgroup (level) of the byvar(s) local r `L`k''`l'gp`i' return scalar `r'=`thing' } if `tab' di _skip(4) as res %10.0g `thing' _c } } } if `tab' di } quietly if "`generate'"!="" { forvalues k=1/4 { /* k indexes type of thing stored */ if `n`k''>0 { forvalues i=1/`n`k'' { /* i indexes item in list of things */ compress ``L`k''_`i'' // if "`firstonly'"!="" bysort `grp': replace ``L`k''_`i''=. if _n>1 return local `L`k''_`i' ``L`k''_`i'' } } } } if "`group'"!="" { cap drop `group' rename `grp' `group' lab var `group' "group by `bylist'" } return scalar byvar_g=`GRP' end program define mk_name, sclass /* meaning make_unique_name <#_chars> */ version 8 args letter base numchar sret clear local name = substr("`letter'`base'",1,`numchar'+1) xi_mkun2 `name'_ end program define xi_mkun2, sclass version 8 /* meaning make_unique_name */ args name local totry "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" local lentot=length("`totry'") local l 0 local len = length("`name'") capture list `name'* in 1 /* try name out */ while _rc==0 { if `l'==`lentot' { di as err "too many terms---limit is " `lentot'+1 exit 499 } local l=`l'+1 local name = substr("`name'",1,`len'-1)+substr("`totry'",`l',1) capture list `name'* in 1 } sret local name "`name'" end