*! version 2.1.3 September 19, 2007 @ 13:16:06 *! executes a characteristic as a command (with some twists) program define dochar , rclass version 9 local myname "dochar" /* 2.1.2 - quiet now squelches error messages from fast method */ /* - added >=, >, ==, <, <= to initial expression for easier simple rules */ /* 2.1.2 - added quiet option for use by ckvar */ /* 2.1.1 - keeps a trail to keep a loop of likes from giving a cryptic error */ /* 2.1.0 - allows slow option to use if statements --- executes tmp do file */ /* 2.0.0 - Uses semicolons rather than separate characteristics to run multiple commands */ /* 1.0.0 - An initial attempt to bury code in charactaristics */ syntax anything, [self(str) loud TEMPnames(str) tmpfile slow trail(str) quiet] capture local doThis : char `anything' if _rc { display as error "`myname': could not use " as input `"`anything'"' as error " as varname[char] format!" error _rc } if "`quiet'"=="" | "`loud'"!="" { local noisily "noisily" } if `"`doThis'"'=="" { if "`noisily'"!="" { display as text "Nothing to run for `anything'" } return local havechar "no" exit 0 } if "`slow'"!="" { local tmpfile "tmpfile" display as text "The -slow- option is becoming obsolete, and could disappear. Please use the -tmpfile- option in its place in the future." } tokenize "`anything'", parse("[]") if `"`1'"'=="_dta" { local xvar "_dta" } else { unab xvar: `1', min(1) max(1) name(`myname': `1') } local char `"`3'"' /* pulling apart the extra options to allow temp variables to be passed in */ /* if the `tmpfile' option is chosen, these should be at the top of the dummy do file */ if `"`tempnames'"'!="" { tokenize "`tempnames'", parse(": ") local cnt 1 while "``cnt''"!="" { local next = `cnt' + 1 local value = `cnt' + 2 if ("``cnt''"==":") | ("``next''"!=":") | ("``value''"==":") { display as error "`myname': could not figure out the lclname:value list" display as error "`options'" exit 198 } local ``cnt'' "``value''" local cnt = `cnt' + 3 } local passTempnames "tempnames(`tempnames')" } if "`self'"=="" { local self "`xvar'" } _ck4like `xvar', evalchar(`char') caller(dochar) if `r(islike)' { local likevar `r(like)' if "`loud'"!="" { display as text "doing it like " as result "`likevar'" } local looped: list likevar in trail if `looped' { local trail: subinstr local trail " " " -> " display as error "Uh oh, there is a loop of likes: " as result "`trail' -> `xvar' -> `likevar'" exit 459 } dochar `likevar'[`char'], self(`self') `loud' `passTempnames' `tmpfile' trail(`trail' `xvar') local likeVarlist "`r(likeVarlist)' `likevar'" } else { local like: word 1 of `doThis' local char1 = substr(trim(`"`doThis'"'),1,1) local compare = (`"`char1'"'=="<") | (`"`char1'"'=="=") | (`"`char1'"'==">") /* check for -in- char --- awful hack */ if `compare' | (`"`like'"'=="in") { /* if using an `in' clause, the first value in the lclname:value list is the new variable name */ /* pull off possible closing ; from dofileedit */ local doThis : subinstr local doThis ";" "" tokenize "`tempnames'", parse(": ") local gen `3' if `"`like'"'=="in" { local doThis : subinstr local doThis "in" "" capture _set2logic `self' `doThis' if _rc { capture _stata2logic, values(`doThis') if _rc { display as error "`myname': had trouble figuring out -in- clause for `self'[`char']" exit 198 } else { gen byte `gen' = inlist(`self',`r(theList)') } } else { gen byte `gen' = `r(logic)' } } /* have a compare */ else { gen byte `gen' = `self' `doThis' } } else { /* this nice, clever solution won't work, because of the way that semicolons are evaluated... */ /* #delimit ; */ /* `doThis'; */ /* #delimit cr */ if "`tmpfile'"!="" { tempname localdo tempfile localdofile file open `localdo' using "`localdofile'", write text /* reparsing the temp names */ if `"`tempnames'"'!="" { tokenize "`tempnames'", parse(": ") local cnt 1 while "``cnt''"!="" { local next = `cnt' + 1 local value = `cnt' + 2 file write `localdo' `"local ``cnt'' "``value''""' _n local cnt = `cnt' + 3 } } tokenize `"`macval(doThis)'"', parse(";") local cnt 1 while `"``cnt''"'!="" { if `"``cnt''"'!=";" { file write `localdo' `"`macval(`cnt')'"' _n } local ++cnt } file close `localdo' if "`loud'"=="" { run `localdofile' } else { do `localdofile' } } else { tokenize `"`macval(doThis)'"', parse(";") local cnt 1 while `"``cnt''"'!="" { if `"``cnt''"'!=";" { if "`loud'"!="" { display as text "Trying to execute " as result `"``cnt''"' } capture `noisily' ``cnt'' local rc = _rc if `rc' { if "`quiet'"=="" { display as error "`myname': Had trouble executing " as input `"``cnt''"' } exit `rc' } } local ++cnt } } /* end of slow split */ } /* end of check for in */ } /* end of check for like */ return local havechar "yes" return local likeVarlist "`likeVarlist'" end program define like dochar `*'[$doCharChar], self($doVarVar) end