*! fvstrip 1.01 ms 24march2015
// takes varlist with possible FVs and strips out b/n/o notation
// returns results in r(varlist)
// optionally also omits omittable FVs
// options:
//   expand calls fvexpand on full varlist
//   onebyone + expand calls fvexpand on elements of varlist
//   dropomit omits omitted variables from stripped r(varlist)
//   noisily displays the stripped r(varlist)
//
// _ms_parse_parts (notes):
// type = variable, error, factor, interaction, product
// k_names = #names if interaction or product, otherwise missing (=1)

program define fvstrip, rclass
	version 11
	syntax [anything] [if] , [ dropomit expand onebyone NOIsily ]
	if "`expand'"~="" {							//  force call to fvexpand
		if "`onebyone'"=="" {
			fvexpand `anything' `if'				//  single call to fvexpand
			local anything `r(varlist)'
		}
		else {
			foreach vn of local anything {
				fvexpand `vn' `if'				//  call fvexpand on items one-by-one
				local newlist	`newlist' `r(varlist)'
			}
			local anything	: list clean newlist
		}
	}
	foreach vn of local anything {						//  loop through varnames
		if "`dropomit'"~="" {						//  check & include only if
			_ms_parse_parts `vn'					//  not omitted (b. or o.)
			if ~`r(omit)' {
				local unstripped	`unstripped' `vn'	//  add to list only if not omitted
			}
		}
		else {								//  add varname to list even if
			local unstripped		`unstripped' `vn'	//  could be omitted (b. or o.)
		}
	}
// Now create list with b/n/o stripped out
	foreach vn of local unstripped {
		local svn ""							//  initialize
		_ms_parse_parts `vn'
		if "`r(type)'"=="variable" & "`r(op)'"=="" {			//  simplest case - no change
			local svn	`vn'
		}
		else if "`r(type)'"=="variable" & "`r(op)'"=="o" {		//  next simplest case - o.varname => varname
			local svn	`r(name)'
		}
		else if "`r(type)'"=="variable" {				//  has other operators so strip o but leave .
			local op	`r(op)'
			local op	: subinstr local op "o" "", all
			local svn	`op'.`r(name)'
		}
		else if "`r(type)'"=="factor" {					//  simple factor variable
			local op	`r(op)'
			local op	: subinstr local op "b" "", all
			local op	: subinstr local op "n" "", all
			local op	: subinstr local op "o" "", all
			local svn	`op'.`r(name)'				//  operator + . + varname
		}
		else if"`r(type)'"=="interaction" {				//  multiple variables
			forvalues i=1/`r(k_names)' {
				local op	`r(op`i')'
				local op	: subinstr local op "b" "", all
				local op	: subinstr local op "n" "", all
				local op	: subinstr local op "o" "", all
				local opv	`op'.`r(name`i')'		//  operator + . + varname
				if `i'==1 {
					local svn	`opv'
				}
				else {
					local svn	`svn'#`opv'
				}
			}
		}
		else if "`r(type)'"=="product" {
			di as err "fvstrip error - type=product for `vn'"
			exit 198
		}
		else if "`r(type)'"=="error" {
			di as err "fvstrip error - type=error for `vn'"
			exit 198
		}
		else {
			di as err "fvstrip error - unknown type for `vn'"
			exit 198
		}
		local stripped `stripped' `svn'
	}
	local stripped	: list retokenize stripped				//  clean any extra spaces

	if "`noisily'"~="" {							//  for debugging etc.
di as result "`stripped'"
	}

	return local varlist	`stripped'					//  return results in r(varnames)
end