#delim ;
prog def listtex;
version 10.0;
*
 List the variables in -varlist- as a table
 to the file in -using- and/or to the Stata log
 with a value delimiter string
 and (optionally) a begin-line and/or end-line string.
 This program is mainly intended to output data to a file
 which is then input into a TeX table,
 in which case the value delimiter is usually "&"
 and the line terminator is usually "\cr".
*! Author: Roger Newson
*! Date: 25 September 2009
*;

syntax [varlist (min=1)] [using/] [if] [in]
 [, Begin(passthru) Delimiter(passthru) End(passthru) Missnum(passthru)
  RStyle(passthru)
  HEadlines(string asis) FOotlines(string asis)
  noLabel Type REPLACE APpendto(string) HAndle(name) ];
*
  -varlist- specifies variables to be written to output file.
  -using- specifies output file.
  -begin()- is string at beginning of each obs
    (set to "" if absent).
  -delimiter()- is delimiter for separating values of same obs
    (set in default to "&").
  -end()- is string at end of each obs
    (set to "" if absent).
  -missnum()- is string code for missing numeric value
    (defaulting to empty string if absent)
  -rstyle()- is a row style
    (a named combination of -begin-, -end-, -using- and -missnum-)
  -headlines()- is a list of head lines to be added to the -using- file
  -footlines()- is a list of foot lines to be added to the -using- file
  -nolabel- specifies that numeric variables with value labels
    must be output as numbers and not as value labels.
  -type- specifies that the output file must be typed to the Stata log.
  -replace- specifies that any pre-existing file
    with the same name as the -using- file must be overwritten.
  -appendto()- specifies the name of a file not currently open,
    to which the variables (and headlines and footlines if specified)
    will be written, closing the file at the end of execution.
  -handle()- specifies a handle of a file currently open
    as a text file in write mode (using the -file open- command),
    to which the variables (and headlines and footlines if specified)
    will be written, leaving the file open at the end of execution,
    so that further output can be added using the -file- command.
*;

* Check that the user has specified either -using-, -type-, -appendto()- or -handle()- *;
if (`"`using'"'=="")&("`type'"=="")&(`"`appendto'"'=="")&("`handle'"=="") {;
  disp as error "You must specify using and/or type and/or appendto() and/or handle()."
    _n "If type is specified, then data are typed to the Stata log."
    _n "If using is specified, then data are output to a file."
    _n "If appendto() is specified, then data are appended to a file."
    _n "If handle() is specified, then data are added to a file already open with that handle.";
  error 498;
};

* Default output file *;
if `"`using'"'=="" {;
  tempfile tf0;
  local using `"`tf0'"';
};

*
 Extract row style elements
*;
listtex_rstyle, `begin' `delimiter' `end' `missnum' `rstyle';
mata: st_local("begin",st_global("r(begin)"));
mata: st_local("delimiter",st_global("r(delimiter)"));
mata: st_local("end",st_global("r(end)"));
mata: st_local("missnum",st_global("r(missnum)"));

local nvar:word count `varlist';

marksample touse, novarlist strok;

*
 Create temporary variables
 containing begin, delimiter and end strings
*;
tempvar beginv delimv endv;
qui {;
  gene str1 `beginv'="";
  gene str1 `delimv'="";
  gene str1 `endv'="";
  replace `beginv'=`"`begin'"' if `touse';
  replace `delimv'=`"`delimiter'"' if `touse';
  replace `endv'=`"`end'"' if `touse';
};

*
 Create list of output variables
*;
local ovarlist `"`beginv'"';
forvalues i1=1(1)`nvar' {;
  local vari1:word `i1' of `varlist';
  local typei1:type `vari1';
  if substr("`typei1'",1,3)=="str" {;
    * String variable - do not convert *;
    local ovarlist `"`ovarlist' `vari1'"';
  };
  else {;
    * Numeric variable - convert to temporary string variable *;
    tempvar sv`i1';
    local vli1: value label `vari1';
    if ("`label'"!="nolabel")&("`vli1'"!="") {;
      qui decode `vari1', gene(`sv`i1'');
    };
    else {;
      local fmti1: format `vari1';
      qui gene str1 `sv`i1''="";
      qui replace `sv`i1''=string(`vari1',"`fmti1'") if `touse';
      qui replace `sv`i1''=`"`missnum'"' if `touse' & missing(`vari1');
    };
    local ovarlist `"`ovarlist' `sv`i1''"';
  };
  * Append delimiter or end *;
  if `i1'==`nvar' {;local ovarlist `"`ovarlist' `endv'"';};
  else {;local ovarlist `"`ovarlist' `delimv'"';};
};

* Output to temporary file *;
tempfile tempout;
qui outfile `ovarlist' using `"`tempout'"' if `touse', runtogether replace;

*
 Copy temporary output file to permanent output file,
 adding headlines and footlines if requested
*;
* Tokenize headlines and footlines and count the tokens *;
mata:listtex_token_count("nhead","headlines");
tokenize `"`headlines'"';
forv i1=1(1)`nhead' {;
  local headline`i1' `"`macval(`i1')'"';
};
mata:listtex_token_count("nfoot","footlines");
tokenize `"`footlines'"';
forv i1=1(1)`nfoot' {;
  local footline`i1' `"`macval(`i1')'"';
};
if `nhead'<=0 & `nfoot'<=0 {;
  * No headlines or footlines *;
  copy `"`tempout'"' `"`using'"', text `replace';
};
else {;
  * Headlines or footlines required *;
  tempfile tempout2;
  tempname handle1 handle2;
  file open `handle2' using `"`tempout2'"', write text;
  forv i1=1(1)`nhead' {;
    local linecur `"`macval(headline`i1')'"';
    file write `handle2' `"`macval(linecur)'"' _n;
  };
  file open `handle1' using `"`tempout'"',read;
  file read `handle1' linecur;
  while r(eof)==0 {;
    file write `handle2' `"`macval(linecur)'"' _n;
    file read `handle1' linecur;
  };
  file close `handle1';
  forv i1=1(1)`nfoot' {;
    local linecur `"`macval(footline`i1')'"';
    file write `handle2' `"`macval(linecur)'"' _n;
  };
  file close `handle2';
  copy `"`tempout2'"' `"`using'"', text `replace';
};

* Append to a file if -appendto()- is requested *;
if `"`appendto'"'!="" {;
  tempname aphandle uhandle;
  file open `aphandle' using `"`appendto'"', write append text;
  file open `uhandle' using `"`using'"', read;
  file read `uhandle' linecur;
  while r(eof)==0 {;
    file write `aphandle' `"`macval(linecur)'"' _n;
    file read `uhandle' linecur;
  };
  file close `uhandle';
  file close `aphandle';
};

* Add to an already open text file if -handle()- is requested *;
if "`handle'"!="" {;
  tempname uhandle;
  file open `uhandle' using `"`using'"', read;
  file read `uhandle' linecur;
  while r(eof)==0 {;
    file write `handle' `"`macval(linecur)'"' _n;
    file read `uhandle' linecur;
  };
  file close `uhandle';
};

* Type to the Stata log if requested *;
if "`type'"!="" {;type `"`using'"';};

end;

#delim cr
version 10.0
/*
  Private Mata programs
*/
mata:

void listtex_token_count(string scalar tokencount,string scalar tokenlist)
{
/*
 Count tokens in local macro with name in tokenlist
 and return result in local macro with name in tokencount
*/
string rowvector tokenrow;
/*
 tokenrow will be a row vector of the tokens
*/

tokenrow=tokens(st_local(tokenlist));
st_local(tokencount,strofreal(cols(tokenrow)));

}

end