*! savasas Version 2.1 dan.blanchette@duke.edu  12Mar2009
*! Center of Entrepreneurship and Innovation Duke University's Fuqua School of Business
** - made savasas able to be run by saswrapper
** - added some date formats, and made it so that any date format will be kept at least as
**    mmddyy10. format in SAS
** savasas Version 2.0 dan_blanchette@unc.edu  03Jul2008
** research computing, unc-ch
** - created check to make sure user is not trying to create a SAS datafile named with
**    more than 32 characters in the name.
** - created a check to make sure SAS ran without errors.  If not, then messy option is turned on.
** - fixed the string comparison that generated the the "too many literals" error message
**    when saving long value labels as user-defined SAS formats
** - fixed all long string comparisons
** - fixed it so savas does not accidently find an error message in the savasas log
** - added dataset label saying savasas created dataset on date
** - added error message that -savasas- cannot be run in Stata batch in Windows
** - made it so that variable labels can contain macro var references etc.
** - no longer dealing with sortedby vars since SAS and Stata sort orders are different
**    depending on missing values and DESCENDING sorts
** savasas Version 1.4 dan_blanchette@unc.edu  29May2007
** - fixed ability to save special missing values with value label as SAS formats
** - now label values of negative numbers are also saved as SAS formats
** - fixed dataset filenames when using the sascode option
** savasas Version 1.3 dan_blanchette@unc.edu  08Aug2006
** - fixed it so that vars with non-existent value labels don't throw things off.
** - fixed situation where value labels with invalid SAS format names were not
**    haiving the rename format assigned to all variables.
** - added ability to tell savasas where the SAS executable is, but for non-windows os's only.
** savasas Version 1.2 dan_blanchette@unc.edu  05Aug2005
** - updated to allow for up to 32 character format value names now possible with SAS 9
**    and maintain Stata 9 value labels up to 32,000 characters to SAS 9 as well.
** - totally changed how value label names are checked
** - now using -labvalclone- by Nick Cox included at bottom of file
** - no longer using -uselabel-
** - now only trimming off trailing blanks for string variables (no longer trimming leading blanks)
** savasas Version 1.1 dan_blanchette@unc.edu  04Nov2004
** - added ability to save data when directory path provided but no SAS file name provided
** - now allows for SAS file to be saved in a directory using universal filenaming convention e.g."\\\MyServer\sys1\projects\sasf.sas7bdat"
** - fixed check option so that it only checks the vars and obs specified in the "if and in" if one or both were specified
** savasas Version 1.1 dan_blanchette@unc.edu  10Sep2004
** - SAS 9 doesn't support .sd7 as a file extension so -savasas- no longer does for any version of SAS
** savasas Version 1.1 dan_blanchette@unc.edu  13Jul2004
** savasas Version 1.1 dan_blanchette@unc.edu  15Nov2003
** - fixed "keep if in" to select subset of observations
**  and sortedby varnames when longer than 8 characters
** savasas Version 1.0 dan_blanchette@unc.edu  27Oct2003
** the carolina population center, unc-ch

program define savasas, rclass
 version 8.1  /* using fdasave */
syntax [varlist] [using/] [in] [if] [, replace sascode Type(string) FORmats udir(string)  ///
                                        MEssy CHeck REName script usas(string) saswrapper ///
                                        saswrap_data(string) sysjobid(string) ]



/* log usage of savasas */
capture which usagelog
if _rc == 0 {
 usagelog , start type(savas) message(`"savasas using `using' `in' `if' , `replace' `sascode' type(`type')  `formats' `messy' `check' `rename' "') `script'
 usagelog , type(savas) message("Input Stata dataset has `c(N)' obs and `c(k)' vars")
}

if "`c(os)'" == "Windows" & "`c(mode)'" == "batch" {
  di as err "{help savasas:savasas} cannot be run in batch mode on Windows"
  /* log usage of savasas */
  capture which usagelog
  if _rc == 0 {
   usagelog , type(savas) uerror(8) etime
  }
  exit  499
}


capture which fdasave
if _rc != 0 {
 di `"{error}You need an up to date Stata 8 to run {browse "http://www.cpc.unc.edu/services/computer/presentations/sas_to_stata/savastata.html":savasas}.  {help savasas:savasas} {error}uses the {res}fdasave {error}command."'

 /* log usage of savasas */
 capture which usagelog
 if _rc == 0 {
  usagelog , type(savas) uerror(1) etime
 }
 exit _rc
}


* FIGURE OUT WHERE SAS EXECUTABLE IS
* ----------------------------------
if "`saswrapper'" != "" {
 local quietly quietly
}
`quietly' sasexe savasas `sascode' `usas'

local wsas `r(wsas)'
local usas `r(usas)'
local rver `r(rver)'  // version of sas that's being run i.e. "v8", "v9" etc


* FIGURE OUT FILENAME and DIRECTORY
* ---------------------------------
// see if there is even one double quote in using
local subtest : subinstr local using `"""' `""' , count(local cnt)
if `cnt' != 0 {
 di `"{help savasas} {error}cannot handle directory or file names that contain double quotes. "'
  capture which usagelog
 if _rc == 0 {
  usagelog , type(savas) uerror(2) etime
 }
 exit 499
}

if `: length local using' == 0 {   // using is empty so try c(filename)
  local filename "`c(filename)'"
  if `: length local filename' != 0 {
   local subtest :  subinstr local filename `"http://"' `""' , count(local cnt)
   if `cnt' != 0  {
     capture _getfilename `"`filename'"'  // get error message if only dir in using
     local using `"`r(filename)'"'  // make using just the filename
   }
   else {  // use the file name and directory of the Stata dataset in memory
     local using="`filename'"
   }
  }
  else if `: length local filename' == 0 {
   di "{error}No file name provided to save data."
   /* log usage of savasas */
   capture which usagelog
   if _rc == 0 {
    usagelog , type(savas) uerror(4) etime
   }
   exit 198
  }
}

// now process using
/* `: length local using' != 0  */

local subtest : subinstr local using `"/"' `""' , count(local cnt)
if `cnt' != 0 & "`c(os)'" == "Windows" {
   local using : subinstr local using "/" "\" , all
}
if "`c(os)'" == "Windows" {
  local dirsep="\"
}
else {
  local dirsep="`c(dirsep)'"
}

** if file name is given with directory info too,
 *  strip to just file name and to dir location
// see if using contains directory info
local subtest : subinstr local using `"`dirsep'"' `""' , count(local cnt)
if `cnt' != 0 {   // Universal naming convention okay here
  capture _getfilename `"`using'"'  // get error message if only dir in using
  local filen `"`r(filename)'"'
  if "`filen'" != "" {    // dir and filename in using
    local dir : subinstr local using `"`filen'"' `""'
  }
  else if `: length local using' != 0 {  // only directory in using
    local dir `"`using'"'
    _getfilename `"`c(filename)'"'
    local filen `"`r(filename)'"'
  }
}
else {  // no directory given
       local filen="`using'"
       local dir ="`c(pwd)'`dirsep'"
}


local subtest : subinstr local dir `"/"' `""' , count(local cnt)
if `cnt' != 0 & "`c(os)'" == "Windows" {
   local dir : subinstr local dir "/" "\" , all
}
confirmdir `"`dir'"'
if _rc != 0 {
  local rc _rc
  di `"{error}The directory "`dir'" does not exist."'
   /* log usage of savasas */
   capture which usagelog
   if _rc == 0 {
    usagelog , type(savas) uerror(16) etime
   }
  exit `rc'
}


// filen could still be empty
if `"`filen'"' == `""' {
   di "{error}No file name provided to save data."
   /* log usage of savasas */
   capture which usagelog
   if _rc == 0 {
    usagelog , type(savas) uerror(14) etime
   }
   exit 198
}


* Data will be changed during program so preserve it so that it will
*  be restored after program finishes running
preserve


* FIX TYPE
* --------
if lower("`type'") == "" | index(lower("`type'"),"sas7") ///
                         | index(lower("`type'"),"sas8") ///
                         | index(lower("`type'"),"sas9")  {
  local type "sas"
 }
else if lower("`type'") == "ssd01" | lower("`type'") == "sas6" | lower("`type'") == "sd2"  {
  local type "sas6"
 }
else if index(lower("`type'"),"x") | index(lower("`type'"),"tran")  {
  local type "sasx"
 }


* IF/IN
* -----

if `: length local if' != 0 | `: length local in' != 0 {
  quietly keep `if' `in'
}


keep `varlist'

if `c(N)' == 0 {
 di as error "{help savasas:savasas} cannot save your dataset because it has no observations. *"
 /* log usage of savasas */
 capture which usagelog
 if _rc == 0 {
  usagelog , type(savas) uerror(5) etime
 }
 exit 2000
}

di _n "{txt}Selected dataset contains {result}`c(N)' {txt}observations and {result}`c(k)' {txt}variables. *"

// because savasas needs to test that vars are all unique -rename- is used which
//  temporarily creates the new var plus a tempvar so that adds 2 variables for a bit
if `c(k)' > 32765 {
  di as error "{help savasas:savasas} can only handle datasets up to 32,765 variables"
  di as error "Your dataset has `c(k)' variables."
 /* log usage of savasas */
 capture which usagelog
 if _rc == 0 {
  usagelog , type(savas) uerror(17) etime
 }
 exit 103
}
if `c(k)' > 1000 | `c(N)' > 50000 {
 di _n "{txt}This may take a few minutes.        *"
}


* DATA LIST
* ---------

 //  extract file extension if there is one
if index("`filen'",".sas7bdat") & index("`filen'",".sas7bdat") == length("`filen'") - 8 {
 local ext = ".sas7bdat"
 local type = "sas"
}
else if index("`filen'",".sd7") & index("`filen'",".sd7") == length("`filen'") - 3 {
 if "`c(os)'" == "Windows" {
  local ext = ".sas7bdat"
  di "{error}Starting with SAS 9 short filename extensions are no longer supported."
  di "{error}Your output SAS datafile will end in .sas7bdat instead of .sd7."
  di "{error}If you are still using an earlier version of SAS, rename the file after it is saved if you like."
  local type = "sas"
  /* local shortfileext="shortfileext" */
 }
 else {
  local ext = ".sas7bdat"
  local type = "sas"
 }
}
else if index("`filen'",".ssd01") & index("`filen'",".ssd01") == length("`filen'") - 5 /*
      */ & "`c(os)'" == "Unix" & "`c(machine_type)'" != "PC" {
 local ext = ".ssd01"
 local type = "sas6"
}
else if index("`filen'",".ssd02") & index("`filen'",".ssd02") == length("`filen'") - 5 /*
      */ & "`c(os)'" == "Unix" & "`c(machine_type)'" == "PC" {
 local ext = ".ssd02"
 local type = "sas6"
}
else if index("`filen'",".sd2") & index("`filen'",".sd2") == length("`filen'") - 3  /*
      */ & "`c(os)'" == "Windows" & "`c(machine_type)'" == "PC" {
 local ext = ".sd2"
 local type = "sas6"
}
else if index("`filen'",".xpt") &  index("`filen'",".xpt") == length("`filen'") - 3 {
 local ext = ".xpt"
 local type = "sasx"
}
else if index("`filen'",".xport") & index("`filen'",".xport") == length("`filen'") - 5 {
 local ext = ".xport"
 local type = "sasx"
}
else if index("`filen'",".export") & index("`filen'",".export") == length("`filen'") - 6 {
 local ext = ".export"
 local type = "sasx"
}
else if index("`filen'",".expt") & index("`filen'",".exp") == length("`filen'") - 3 {
 local ext = ".exp"
 local type = "sasx"
}
else if index("`filen'",".v5x") & index("`filen'",".v5x") == length("`filen'") - 3 {
 local ext = ".v5x"
 local type = "sasx"
}
else if index("`filen'",".v6x") & index("`filen'",".v6x") == length("`filen'") - 3 {
 local ext = ".v6x"
 local type = "sasx32 "
}
else if index("`filen'",".") {
 local ext = substr("`filen'",index("`filen'","."),length("`filen'"))
 while index("`ext'",".") > 0 {
  local ext = substr("`ext'",index("`ext'",".") + 1,length("`ext'"))
 }
 local ext=".`ext'"
}
if index("`filen'",".") {
 local middle=substr("`filen'",1,index("`filen'","`ext'") - 1) /* middle will not end in a period */
 local filen=substr("`filen'",1,index("`filen'",".") - 1)
 local middle=substr("`middle'",length("`filen'")+1,length("`middle'"))
}

 if `"`filen'"' == `""' {
    // This should never be the case, but leave in just as a catch
    di `"{error} you have to specify the SAS file name when specifying a file location"'
  /* log usage of savasas */
  capture which usagelog
  if _rc == 0 {
   usagelog , type(savas) uerror(15) etime
  }
  exit 198
 }


****** Check for invalid SAS data file name ************
local fc = substr("`filen'",1,1)
// have to use inlist() since the first char is likely a letter
//  and have to split it into two since it can't handle 11 arguments!
local swn = "0"
local hsc = "0"
if inlist("`fc'","0","1","2","3","4") | ///
   inlist("`fc'","5","6","7","8","9")  { // name starts with a number
  local swn = "1"
}

if  index("`filen'","~") | /// Has a bad character in name
    index("`filen'","!") | ///
    index("`filen'","@") | ///
    index("`filen'","#") | ///
    index("`filen'","$") | ///
    index("`filen'","%") | ///
    index("`filen'","^") | ///
    index("`filen'","&") | ///
    index("`filen'","*") | ///
    index("`filen'","(") | ///
    index("`filen'",")") | ///
    index("`filen'","-") | ///
    index("`filen'","+") | ///
    index("`filen'","=") | ///
    index("`filen'","[") | ///
    index("`filen'","]") | ///
    index("`filen'",":") | ///
    index("`filen'",";") | ///
    index("`filen'","'") | ///
    index("`filen'","<") | ///
    index("`filen'",">") | ///
    index("`filen'","?") | ///
    index("`filen'",",") | ///
    index("`filen'","|") | ///
    index("`filen'"," ") | ///
    index("`filen'","{") | ///
    index("`filen'","}") {
  local hsc = "1"
}

if "`swn'" == "1" | "`hsc'" == "1" {
  if "`rename'" == "" {
    di `"{error}File name {res}"`filen'" {error}is not a valid SAS file name. *"'
    if "`swn'" == "1" {
      di `"{error}SAS file names cannot start with a number.  *"'
    }
    if "`hsc'" == "1" {
      di `"{error}SAS file names cannot contain special characters.  *"'
    }
  }
  if "`hsc'" == "1" {
    // remove bad characters
    foreach char in ~ ! @ # $ % ^ & * ( ) - + = [ ] : ; ' < > ? , | {
      local filen = subinstr("`filen'","`char'","_",.)
    }
    local filen = subinstr("`filen'","{","_",.)
    local filen = subinstr("`filen'","}","_",.)
    local filen = subinstr("`filen'"," ","_",.)

    if `"`: subinstr local filen "_" "" , all'"' == "" {  // if nothing left, meaning, person used all bad characters
      local filen = "okpopeye"
    }
  } // end of contains bad character

  if "`swn'" == "1" { // name starts with a number
    if length("`filen'") == 32  {
      local filen = substr("`filen'",2,length("`filen'"))
      local filen = "_`filen'"
    }
    else {
      local filen = "_`filen'"
    }
  } // end of if started with number
  if "`rename'" == "" {
    di `"{error}The {res}rename {error}option will rename it for you to be: {res}"`filen'" "'
    /* log usage of saswrapper */
    capture which usagelog
    if _rc == 0 {
     usagelog , type(savas) uerror(6) etime
    }
    exit 198
  }
} /* if filen is not a valid SAS data file name */


if "`type'" == "sasx" {
 if !("`ext'" == ".xpt"    | /*
  */  "`ext'" == ".xport"  | /*
  */  "`ext'" == ".export" | /*
  */  "`ext'" == ".expt"   | /*
  */  "`ext'" == ".trans"  | /*
  */  "`ext'" == ".exp"    | /*
  */  "`ext'" == ".sasx"   | /*
  */  "`ext'" == ".v5x"    | /*
  */  "`ext'" == ".v6x")  {
  local middle = "`middle'`ext'"
  local ext = ".xpt"
  }
 if length("`filen'") > 8 & "`rename'" == "" {
  di `"{error}File name {res}"`filen'" {error}is not a valid SAS xport file name. *"'
  di `"{error}SAS xport file names have to be 8 or less characters long.  *"'
  local filen = substr("`filen'",1,8)
  di `"{error}The {res}rename {error}option will rename it for you to be: {res}"`filen'" {error}*"'
  /* log usage of savasas */
  capture which usagelog
  if _rc == 0 {
   usagelog , type(savas) uerror(7) etime
  }
  exit 198
 }
 else if length("`filen'") > 8 & "`rename'" != "" {
  local filen = substr("`filen'",1,8)
 }

 if "`middle'" == ".dta" {
  local middle = ""
 }
 local using = "`macval(dir)'`filen'`middle'"
 local filen = "`filen'"+"`middle'"
} /* end of if type=sasx */
else {
 local using = "`macval(dir)'`filen'"
 local ext = ".sas7bdat"
 if "`type'" == "sas6" & "`c(os)'" == "Unix" & "`c(machine_type)'" != "PC" {
  local ext = ".ssd01"
 }
 else if "`type'" == "sas6" & "`c(os)'" == "Unix" & "`c(machine_type)'" == "PC" {
  local ext = ".ssd02"
 }
 else if "`type'" == "sas6" & "`c(os)'" == "Windows" {
  local ext = ".sd2"
 }
}
if "`type'" == "sas6" {
 if length("`filen'") > 8 & "`rename'" == "" {
  di `"{error}File name {res}"`filen'" {error}is not a valid SAS version 6 file name. *"'
  di `"{error}SAS version 6 file names have to be 8 or less characters long.  *"'
  local filen = substr("`filen'",1,8)
  di `"{error}The {res}rename {error}option will rename it for you to be: {res}"`filen'" {error}*"'
  /* log usage of savasas */
  capture which usagelog
  if _rc == 0 {
   usagelog , type(savas) uerror(8) etime
  }
  exit 198
 }
 else if length("`filen'") > 8 & "`rename'" != "" {
  local filen = substr("`filen'",1,8)
 }
}
if "`type'" != "sasx" | "`type'" != "sas6"  {
 if length("`filen'") > 32 & "`rename'" == "" {
  di `"{error}File name {res}"`filen'" {error}is not a valid SAS file name. *"'
  di `"{error}SAS file names have to be 32 or less characters long.  *"'
  local filen = substr("`filen'",1,32)
  di `"{error}The {res}rename {error}option will rename it for you to be: {res}"`filen'" {error}*"'
  /* log usage of savasas */
  capture which usagelog
  if _rc == 0 {
   usagelog , type(savas) uerror(8) etime
  }
  exit 198
 }
 else if length("`filen'") > 32 & "`rename'" != "" {
  local filen = substr("`filen'",1,32)
 }
}




if "`replace'" == "" & "`sascode'" == ""  {
  if index(`"`macval(dir)'"',"\") == 1 {  // Universal naming  doesn't seem to be a problem
    capture confirm file `"`macval(dir)'`filen'`ext'"'
  }
  else {
   capture confirm file `"`macval(dir)'`filen'`ext'"'
  }
  if _rc == 0 {
    di `"{error}The SAS file: "`macval(dir)'`filen'`ext'" already exists."'
    di "{error}Use the {res}replace {error}option if you really want to replace it."
    /* log usage of savasas */
    capture which usagelog
    if _rc == 0 {
      usagelog , type(savas) uerror(9) etime
    }
    exit 602
  }
} // end of if replace option not used

if "`script'" == "" {
 /* set where temp directory is */
 tmpdir
 local tmpdir `"`r(tmpdir)'"'

 local tfn = subinstr("`c(current_time)'",":","",.)
 local sysjobid = substr("`tfn'",length("`tfn'") - 5,length("`tfn'"))
 local sysjobid = "_`sysjobid'"
}
else if "`script'" != ""  local tmpdir `"`udir'"'

if  "`type'" == "sasx" {
 if `c(k)' > 9999 {
  di _n "{error}SAS Xport/Transport files can only handle up to 9,999 variables.        *"
  /* log usage of savasas */
  capture which usagelog
  if _rc == 0 {
   usagelog , type(savas) uerror(10) etime
  }
  exit 103
 }
} /* end of if sasx */


* TEST FOR UNIQUE VARNAMES
* ------------------------

** test that vars will work in SAS transport and version 6 files **
local j = 1
local srenamed = 0
local verror = 0
local k = 0
local stop = 0
local sasvars ""
foreach var of varlist _all {
 local ovar = "`var'"
 local valid = upper("`var'")  /* make all renamed vars uppercase */
 ** Test for invalid SAS varnames and **
 ** test if variables are not unique for SAS since SAS is case insensitive **
 if  upper("`var'") == "_ERROR_" |      /*  invalid SAS names
  */ upper("`var'") == "_N_" |          /*
  */ upper("`var'") == "_NUMERIC_" |    /*
  */ upper("`var'") == "_CHARACTER_" |  /*
  */ upper("`var'") == "_ALL_"  {
  local verror = 1
 } /* end of if var is an invalid SAS varname */
 if ("`type'" == "sasx" | "`type'" == "sas6") & length("`var'") > 8 {
   local verror = 1
 }
 if "`var'" != upper("`var'") {  /* don't check vars that are already upper case */
  capture rename `var' `valid'
  if _rc != 0 {
    local verror = 2
  }
  else {
   local var="`valid'"
  }
 } /* end of don't check if var already upper case */
 if "`rename'" == "" & `verror' >= 1 {
  if `j' == 1 {
   di "{error}Not all Stata variables are valid SAS variables.  *"
   di "{error}Specify the {res}rename {error}option for {help savasas:savasas} {error}to rename them. *"
   di "{error}List of variables that need to be renamed: * "
   local stop = 1
   local j = `j'+1
  }
  di "{res}`ovar'  *"
 } /* end of if "`rename'" == "" & verror >= 1 */
 else if "`rename'" != "" & `verror' >= 1 {
  local k = 0
  while length("`k'") < 6  {   /* make up to 99,999 attempts to rename the variable */
   if ("`type'" == "sasx" | "`type'" == "sas6") & length("`var'") > 8 {
    if `k' == 0 {  /* take first 8 characters */
     local valid = upper(substr("`var'",1,8))
    }
    else {
     local valid = upper(substr("`var'",1,8 - length("`k'"))) + "`k'"
    }
   }  /* end if sasx or sas6 */
   else {
    if `k' == 0 {
     local k = 1
    }
    local valid = upper(substr("`var'",1,32 - length("`k'"))) + "`k'"
   }
   capture rename `var' `valid'
   if _rc != 0 & length("`k'") == 6 {
     local verror = 1
   }
   else if _rc == 0 {
    if `j' == 1  {
     noi di "The following variables were renamed to valid SAS variable names:  * "
     local srenamed = 1
     local j = `j' + 1
    }
    noi di "{res}`ovar' {txt}-> {res}`valid'    *"
    local k = "success!"
   }  /* end of if _rc == 0 */
   if "`k'" != "success!" {
    local k = `k'+1   /* count attempts to rename vars */
   }
  } /* end of while length(k) < 6 */
 } /* end of if rename and verror */
 if `srenamed' == 0 {   /* make sure all vars are valid */
  capture rename `var' `valid'
 }
 if `stop' == 0 {
  if `verror' == 0 {
   local sasvars "`sasvars' `ovar'"  /* keep list of vars that have original case if possible */
  }
  else if `verror' >= 1 {
   local sasvars "`sasvars' `valid'"  /* keep list of vars that have original case if possible */
  }
 } /* if foreach not stopped */
 local verror = 0
 local srenamed = 0
} /* end of foreach */

if `stop' == 1 {   /* This should not be possible. */
 if "`rename'" != "" {
  noi di "{error}ERROR: {help savasas:savasas} was unable to rename variables uniquely to shorter names. *"
 }
 /* log usage of savasas */
 capture which usagelog
 if _rc == 0 {
  usagelog , type(savas) uerror(11) etime
 }
 exit 499
} /* end of if verror=1 */

/* rename all vars so that fdasave won't have to */
local k = 0
local stop = 0
local cvars ""
foreach valid of varlist _all {
 if length("`valid'") > 8 {
  local k = 0
  while length("`k'") < 6 {   /* make up to 99,999 attempts to rename the variable */
   if `k' == 0 {  /* take first 8 characters */
    local xptvar = upper(substr("`valid'",1,8))
   }
   else {
    local xptvar = upper(substr("`valid'",1,8 - length("`k'"))) + "`k'"
   }
   capture rename `valid' `xptvar'
   if _rc == 0  {
    local k = "success!"
   }  /* end of if _rc == 0 */
   else {
    local k = `k'+1   /* count attempts to rename vars */
   }
  } /* end of while length(k) < 6 */
 }  /* end if valid varname > 8 */
 if length("`valid'") <= 8 {
  local xptvar = "`valid'"
 }
 local vt : type `xptvar'
 if index("`vt'","str") {
  local cvars "`cvars' `xptvar'"
 }
} /* end of foreach */


* FIX STRING VARS
* ---------------
// remove trailing blanks in string data
if "`cvars'" != "" {
 local i = 1
 foreach var of varlist `cvars' {
  if  `c(maxstrvarlen)' > 80 {
   quietly compress `var'
   local vt : type `var'
   if real(substr(rtrim("`vt'"),4,length("`vt'"))) > 200 {
    if `i' == 1 {
     // because xport files have a 200 character limit and savasas uses fdasave there is a 200 character limit
     noi di "{help savasas:savasas} {error}can only store the first 200 characters in string variables. *"
     noi di "{error}List of string variables reduced to 200:   *"
     local i = `i' + 1
    }
    noi di "{res} `var'   *"
   } /* if length > 200 */
  } /* end of if SE dataset */
  quietly replace `var' = substr(rtrim(`var'),1,200)  // trim off trailing blanks for all string vars
 } /* end of foreach */
}  /* end of if there are cvars in dataset */

local xfilen = substr("`filen'",1,6)
if `c(k)' > 9999 {
 local vars1 ""
 local vars2 ""
 local vars3 ""
 local vars4 ""
 local i = 0
 local files = 1
 foreach var of varlist _all {
  local i = `i' + 1
  if `i' <= 9999 {
   local vars1 "`vars1' `var'"
  }
  if `i' > 9999 & `i' <= 19998 {
   local vars2 "`vars2' `var'"
  }
  else if `i' > 19998 & `i' <= 29997 {
   local vars3 "`vars3' `var'"
  }
  else if `i' > 29997 {
   local vars4 "`vars4' `var'"
  }
 }  /* end of foreach */
 local sysjobid1 = "`sysjobid'1"
 local xfilen1 = substr("`filen'",1,6) + "1"
 if `i' > 9999  {
  local files = 2
  local sysjobid2 = "`sysjobid'2"
  local xfilen2 = substr("`filen'",1,6) + "2"
 }
 if `i' > 19998  {
  local files = 3
  local sysjobid3 = "`sysjobid'3"
  local xfilen3 = substr("`filen'",1,6) + "3"
 }
 if `i' > 29997  {
  local files = 4
  local sysjobid4 = "`sysjobid'4"
  local xfilen4 = substr("`filen'",1,6) + "4"
 }
}  /* if > 9999 vars */

if "`type'" == "sas" {
  local eng = "`rver'"
}
else if "`type'" == "sas6" {
 local eng = "v6"
}
else if "`type'" == "sasx" {
 local eng = "xport"
}

if "`files'" == "" {
 local temp `"`macval(tmpdir)'`sysjobid'"'
 if "`sascode'" == "" {  /* save xpt file to temp dir */
  local raw `"`macval(temp)'"'
 }
 else {  /* save xpt file to using dir */
  local raw `"`macval(dir)'`filen'"'
  local raw0 `"`macval(dir)'`xfilen'"'
 }
}
else {
 foreach file of numlist 1/`files' {
  local temp `"`macval(tmpdir)'`sysjobid'"'
  local raw`file' `"`macval(tmpdir)'`sysjobid`file''"'
  local raw `"`macval(tmpdir)'`sysjobid'"'
  if "`sascode'" != ""  {  /* save xpt file to using dir */
   local raw`file' `"`macval(dir)'`xfilen`file''"'
   local raw       `"`macval(dir)'_`xfilen'"'
  }
 } /* end of foreach file */
} /* end of else multiple files */


* RUN CHECK REPORT
* ----------------
  if "`check'" != "" {
    tempfile xpt_ready
    quietly save "`xpt_ready'"
    restore, preserve   /* do check on original data */
     if "`script'" == "script" {
       if "`eng'" == "`xport'" {
         /* if xport file then filen may have periods in it */
         local filenx=substr("`filen'",1,index("`filen'",".") - 1)
         log using `"`macval(dir)'`filenx'_STATAcheck.log"', replace
       }
       else if "`eng'" != "`xport'" {
        log using `"`macval(dir)'`filen'_STATAcheck.log"', replace
       }
     } /* if running savasas from script */
     if "`eng'" == "`xport'" {
       di `"Compare results with SAS output: `macval(dir)'`filenx'_SAScheck.lst "'
       global S_FN = "`filenx'"
     }
     else if "`eng'" != "`xport'" {
       di `"Compare results with SAS output: `macval(dir)'`filen'_SAScheck.lst "'
       global S_FN = "`filen'"
     }
     if `srenamed' == 1  { /* if any vars were renamed */
       di "NOTE: The Stata variables here may not match the SAS variables "
       di "      because the SAS variables may have been renamed. "
     }
     local five_n = 5
     if _N < 5 {
       local five_n = _N
     }
     // no reason to set more off because if user quits no temp files have been written yet
     // data already subset
     summarize
     describe
     list in 1/`five_n'
     if "`script'" == "script" {
       log close
     }
     use `xpt_ready', clear  // though no reason to have to clear since data didn't change!
  } /* end of if check */


* WRITE SAS PROGRAM TO READ IN DATA
* ---------------------------------
savasas_sas , dir(`dir') sysjobid(`sysjobid') filen(`filen') raw(`raw') ext(`ext')                   ///
                          engine(`eng') rver(`rver') `check' `sascode' `formats' middle(`middle')    ///
                          sysjobid1(`sysjobid1')  sysjobid2(`sysjobid2') sasvars(`sasvars')          ///
                          sysjobid3(`sysjobid3') sysjobid4(`sysjobid4') files(`files')               ///
                          raw0(`raw0') raw1(`raw1') raw2(`raw2') raw3(`raw3') raw4(`raw4')           ///
                          `shortfileext' xfilen(`xfilen') xfilen1(`xfilen1') xfilen2(`xfilen2')      ///
                          xfilen3(`xfilen3') xfilen4(`xfilen4')                                      ///
                          vars1(`vars1') vars2(`vars2') vars3(`vars3') vars4(`vars4') messy(`messy') ///
                          `saswrapper' saswrap_data(`saswrap_data')


* SAVE DATA
* ---------
/* min and max values will be tested by fdasave */
if "`files'" == "" {
  if "`sascode'" == "" {
   quietly fdasave "`raw'", rename vallabfile(none) replace
  }
  else {
   quietly fdasave "`raw0'", rename vallabfile(none) replace
  }
}
else if "`files'" != "" {
 foreach file of numlist 1/`files' {
  local nvars : word count "`vars`file''"
  quietly fdasave `vars`file'' using "`raw`file''", rename vallabfile(none) replace
 }
}

if "`sascode'" == "" {
 // if replacing SAS file then see if user has permission to do so
 if index(`"`macval(dir)'"',"\") == 1 {  // Universal naming doesn't seem to be a problem
    capture confirm file `"/`macval(dir)'`filen'`ext'"'
 }
 else {
   capture confirm file `"`macval(dir)'`filen'`ext'"'
 }
 if _rc == 0 {
   if "`script'" == "" {
     capture erase `"`macval(dir)'`filen'`ext'"'
   }
   if _rc != 0 {
     di ""
     di `"{error}The SAS file: `macval(dir)'`filen'`ext' cannot be replaced."'
     di `"{error}Check your directory/folder permissions and file permissons."'
     /* log usage of savasas */
     capture which usagelog
     if _rc == 0 {
      usagelog , type(savas) uerror(13) etime
     }
     exit 608
   }
 } /* end of if file exists */

 * RUN SAS
 * -------
 if "`c(os)'" == "Unix" /* or Linux */ {
  shell "`usas'" "`temp'_infile.sas"       -log "`temp'_infile.log"
  run "`temp'_infile_report.do"
 } /* end of if Unix */
 else if "`c(os)'" == "Windows" /* Windows */ {
  shell `wsas' "`temp'_infile.sas" -nologo -log "`temp'_infile.log"
  run "`temp'_infile_report.do"
 } /* end of if Windows */
 sas_rep  /* run the SAS report */
 if "`r(sas_rep_error)'" != "" {
   local messy "messy"
 }
 if "`messy'" == "" {
  capture erase "`temp'_infile.sas"
  capture erase "`temp'_infile.log"
  capture erase "`temp'_infile_report.do"
  capture erase "`temp'_formats.txt"
  if "`files'" == "" {  // if only 1 xpt file created
   capture erase "`temp'.xpt"
  }
  else {
   foreach file of numlist 0/`files' { // if multiple xpt files created
    capture erase "`raw`file''.xpt"
   }
  } /* end of else */
 } /* end of messy */
 else  if "`messy'" != "" & "`script'" == "" {
  di _n "{res}You have requested {help savasas:savasas} not to delete the intermediary files created by savasas:"
  di _n `"in directory: `tmpdir'"'
  dir `"`temp'*"'
  if "`files'" != "" {
    dir `"`raw'*.xpt"'
  }

  if "`c(console)'" == "" {  // not in console mode or batch mode
    if "`c(os)'" != "Windows" {  // sysjobid starts with an underscore in savasas
      di `"{res} {stata usesasdel `"`tmpdir'"' `sysjobid' :Click here to erase them all.} "'
    }
    if "`c(os)'" == "Windows" {
      local usesasdeldir : subinstr local tmpdir `":"' `"\\\`= char(58)'"', all
                                // sysjobid starts with an underscore in savasas
      di `"{res} {stata usesasdel `"`usesasdeldir'"' `sysjobid' :Click here to erase them all.} "'
    }
  }  // not in console or batch mode

 }
} /* end of if not wanting only sascode */
else if "`sascode'" == "sascode" {
 if "`files'" == "" {  // if only 1 xpt file created
   if index("`raw0'","\") == 1 {  // Universal naming doesn't seem to be a problem
    capture confirm file `"/`macval(raw0)'.xpt"'
   }
   else {
    capture confirm file "`raw0'.xpt"
   }
   if _rc == 0 {
    di `"{txt}The xport data file you requested is:  *"'
    di `"{res} "`raw0'.xpt"  *"'
   }
   else if _rc != 0 {
    di `"{help savasas:savasas} {error}did not save:  *"'
    di `"{txt} "`raw0'.xpt" * "'
   }
 }
 else { // more than one xpt file created
   foreach file of numlist 1/`files' {
     if index("`raw`file''","\") == 1 {  // Universal naming doesn't seem to be a problem
       capture confirm file `"/`macval(raw`file')'.xpt"'
     }
     else {
       capture confirm file "`raw`file''.xpt"
     }
     if _rc == 0 {
       if `file' == 1  di `"{txt}The xport data files you requested are:  *"'
       di `"{res} "`raw`file''.xpt"  *"'
     }
     else if _rc != 0 {
       if `file' == 1  di `"{help savasas:savasas} {error}did not save:  *"'
       di `"{txt} "`raw`file''.xpt" * "'
     }
   }
 }
 if index("`raw'","\") == 1 {  // Universal naming  doesn't seem to be a problem
  capture confirm file "/`macval(raw)'_infile.sas"
 }
 else capture confirm file "`raw'_infile.sas"
 if _rc == 0 {
  di `"{txt}The SAS program to read in the xport data file is: *"'
  di `"{res} "`raw'_infile.sas"  *"'
 }
 else if _rc != 0 {
  di `"{help savasas:savasas} {error}did not save:"'
  di `"{txt} "`raw'_infile.sas" * "'
 }
} /* end of if sascode=sascode */

return local sasfile `"`macval(dir)'`filen'`ext'"'

restore

/* log usage of savasas */
capture which usagelog
if _rc == 0 {
 usagelog , type(savas) uerror(0) etime
}

end /* end of savasas */


program define savasas_sas
syntax [varlist]  [, engine(string) rver(string) dir(string) sysjobid(string) ext(string) files(string)  ///
                      sascode filen(string) CHeck FORmats raw(string) middle(string)                     ///
                      sysjobid1(string) sysjobid2(string) sysjobid3(string) sysjobid4(string)            ///
                      raw0(string) raw1(string) raw2(string) raw3(string) raw4(string) sasvars(string)   ///
                      xfilen(string) xfilen1(string) xfilen2(string) xfilen3(string) xfilen4(string)     ///
                      vars1(string) vars2(string) vars3(string) vars4(string) shortfileext messy(string) ///
                      saswrapper saswrap_data(string) ]
 version 8

quietly {
	file open sasfile using "`raw'_infile.sas", replace text write
	* DATA LIST
	* ---------

        if "`sascode'" == "" {
          local in_dset `"`raw'.xpt"'
        }
        else {
          local in_dset `"`raw0'.xpt"'
        }

        file write sasfile _n `"/********************************************************"' /*
                        */ _n `"** program: `raw'_infiles.sas  "'                           /*
                        */ _n `"** programmer: savasas  "'                                  /*
                        */ _n `"** date: `c(current_date)' "'                               /*
                        */ _n `"** comments: SAS program to read and label:  "'             /*
                        */ _n `"**  `in_dset' "'                                            /*
                        */ _n `"**           which contains data from a Stata dataset"'     /*
                        */ _n `"********************************************************/"' /*
                        */ _n _n `"options nofmterr nocenter linesize=max;"'   _n _n

        file write sasfile _n `" ** this version of _infile_report.do will be overwritten if all goes well. **; "'
        file write sasfile _n `" data _null_;"' _n `"file "`raw'_infile_report.do"; "'   ///
           _n `" put "capture program drop sas_rep"; "'   ///
           _n `" put "program define sas_rep, rclass"; "'  ///
           _n `" put "di as err "" SAS failed to create `filen' "" "; "'  ///
           _n `" put "di as err "" Look at {view `raw'_infile.log:`raw'_infile.log} to see what error occurred. "" "; "'
        if "`messy'" == "" {
          file write sasfile _n `" put "di as err "" The {help savasas:savasas} option messy is now on. "" "; "'
        }
        file write sasfile _n `" put "local sas_rep_error = 1 "; "' ///
           _n `" put "return local sas_rep_error ""\`sas_rep_error\'"" "; "' ///
           _n `" put "end"; "'


       if "`engine'" == "v6" {
        file write sasfile _n _n `"libname library v6 "`dir'" `shortfileext';  "' _n _n
        file write sasfile _n _n `"options fmtsearch=(out.`filen');  "' _n _n
       }
       else {
        file write sasfile _n _n `"libname library `engine' "`dir'" `shortfileext';  "' _n _n
        file write sasfile `"options fmtsearch=(out.`filen');  "' _n _n
       }

       if "`engine'" == "`rver'" | "`engine'" == "v6"  {
         file write sasfile `"libname out `engine' "`dir'" `shortfileext' ;  "' _n _n
       }
       else if "`engine'" == "xport" {
         file write sasfile `"libname out xport "`macval(dir)'`filen'`ext'";  "' _n _n
          /* if xport file then filen may have periods in it then get rid of them
           *  since filen no longer needs them now that libname out defined */
         if index("`filen'",".") {
          local filen=substr("`filen'",1,index("`filen'",".")-1)
         }
       }

     if `c(k)' <= 9999 {
       if "`sascode'" == "" {
        file write sasfile `"libname raw xport "`raw'.xpt";  "' _n _n
       }
       else {
        file write sasfile `"libname raw xport "`raw0'.xpt";  "' _n _n
       }
     }  /* if <= 9999 vars */
     else if `c(k)' > 9999 {
      foreach file of numlist 1/`files' {
       file write sasfile _n _n `"libname raw`file' xport "`raw`file''.xpt";  "' _n  _n
      } /* end of foreach file */
      if "`sascode'" == "" {
        file write sasfile `" /* do observational merge to create one big file */  "'  /*
        */ _n `" data `sysjobid'; "'  /*
        */ _n `"  merge raw1.`sysjobid1' raw2.`sysjobid2' "'
       if `c(k)' > 19998 {
        file write sasfile `" raw3.`sysjobid3' "'
         if `c(k)' > 29997 {
          file write sasfile `" raw4.`sysjobid4' "'
         } /* end of if > 29997 vars */
        } /* end of if > 19998 vars */
       file write sasfile `";"' _n `"run;"'
      } /* end of if not sascode  */
      else {
        file write sasfile `" /* do observational merge to create one big file */  "'  /*
        */ _n `" data `xfilen'; "'  /*
        */ _n `"  merge raw1.`xfilen1' raw2.`xfilen2' "'
       if `c(k)' > 19998 {
        file write sasfile `" raw3.`xfilen3' "'
         if `c(k)' > 29997 {
          file write sasfile `" raw4.`xfilen4' "'
         } /* end of if > 29997 vars */
        } /* end of if > 19998 vars */
       file write sasfile `";"' _n `"run;"'
      } /* end of if sascode  */
     } /* end of if > 9999 vars */



   * CREATE USER-DEFINED FORMATS FROM VALUE LABELS
   * ---------------------------------------------
    local hasvl 0
    if "`formats'" != "" {
      label dir
      if "`r(names)'" != "" {  // dataset has value labels but not sure if they are used in data
        local names `"`r(names)'"'
        local hasvl = 1
        /* establish what is the max length of a user-defined format name
         *  based on what version of SAS datafile is desired */
        if index("`engine'","v8") | ///
           index("`engine'","v6") | ///
           index("`engine'","xport")   local ml = 8
        else local ml = 32

        // create a list of all value labels used in data set that are defined
        //  a variable can be assigned a label that has not been defined...this is not good
        local all_vlabs `""'
        // create a list of all variables with value labels associated to them
        //  that are actually defined
        local lvvars `""'
        foreach var of varlist `varlist' {
          local lbl : value label `var'
          if `"`lbl'"' != "" {  // if variable has value label associated to it
            capture label list `lbl'  // check to see if exists as defined label
            // if it doesn't give up and move on!
            if _rc == 111 {  // label isn't defined
              local lbl ""
              // remove association of label to variable since it isn't defined
              label value `var'
            }
            else {   // var has label that is defined
              // all vars with defined labels need to be sent to sav_lvchk
              local lvvars `"`lvvars' `var'"'  // create list of vars with value labels
              // label exists and not already listed
              if `: list posof `"`lbl'"' in local(all_vlabs)' == 0  {
                local all_vlabs `"`all_vlabs' `lbl'"'
              }
            }
          }
        } // end of foreach var

        // drop defined labels that are not associated to variables in current dataset
        foreach lbl of local names {
          if `: list posof `"`lbl'"' in local(all_vlabs)' == 0  {
             label drop `lbl'
          }
        }
        // re-create local macro names now that it's cleaned up
        label dir
        local names `"`r(names)'"'
      } /* end of if dataset has value labels */
      else {
        local hasvl 0
      }

      if "`r(names)'" != "" {  // if dataset really has value labels
        // check and rename value labels if necessary
        capture noisily sav_lvchk, ml(`ml') vars(`lvvars')

        if _rc == 499 {  /* value labels were not uniquely named */
          if "`script'" == "" {
            erase "`raw'_infile.sas"
          }
          /* log usage of savasas */
          capture which usagelog
          if _rc == 0 {
            usagelog , type(savas) uerror(12) etime
          }
          exit 499
        }


        if `= real(substr("`rver'",2,length("`rver'")))' > 8 {
          file write sasfile _n `"options NoQuoteLenMax;"' // new option in SAS 9
	}
	else if `c(version)' >= 9   {
	  noi di as res _n `"WARNING: Value labels longer than 200 characters may be truncated. *"' _n
	}

        sav_labs_data `varlist', fhandle(sasfile) ml(`ml') filen(`filen') raw(`"`raw'"')

      } /* end of if dataset really has value labels */
      else {
        local hasvl 0
      }
    }   /* end of if formats to be created from value labels */

       if "`engine'" != "xport" {
        file write sasfile  _n _n `"data out.`filen' "' ///
           `" (label= "-savasas- created dataset on %sysfunc(date(),date9.)" "'
        if "`engine'" != "v6" {
         file write sasfile `" rename=("' _n
         local i = 1
         tokenize "`sasvars'"  /* good SAS variable names */
         foreach var of varlist _all {
          file write sasfile `" `var' = ``i''"'
          if mod(`i',5) == 0 {
           file write sasfile  _n
          }
          local i = `i' + 1
         } /* end of foreach */
         file write sasfile  _n `" ));"' _n `" length "'
        } /* if not v6 engine */
        else if "`engine'" == "v6" {  /* no need to rename vars for v6 files */
         file write sasfile  _n `");"' _n `" length "'
        }
       }
       else if "`engine'" == "xport" {  /* don't need vars renamed or sort info */
        file write sasfile  _n _n `"data out.`filen' "' ///
        `" (label= "-savasas- created dataset on %sysfunc(date(),date9.)" );"' _n `" length "'
       }


     * SET VARS TO MINIMUM DATATYPE
     * ----------------------------
     compress /* so says Loren */

     local j 1
     local verror = 0
     foreach var of varlist `varlist' {
      local storage : type `var'
      if index("`storage'","str") == 0 {
       if ("`storage'" == "float") |  ("`storage'" == "double") {
        local len = 8
       }
       else if "`storage'" == "byte" {
        local len = 3
       }
       else if "`storage'" == "int" {
        local len = 4
       }
       else if "`storage'" == "long" {
        local len = 6
       }
       file write sasfile `" `var' `len'"'
      }  /* end of if not string */
      else if index("`storage'","str") == 1 {
       local len = substr("`storage'",4,length("`storage'"))
       file write sasfile `" `var' $`len'"'
      }
      if (mod(`j',8) == 0) {  /* print 8 vars per line */
       file write sasfile _n
      }
      local j = `j' + 1
     }  /* end of foreach */
     if `verror' == 1 {
      file close sasfile
      exit 499
     }
     if `c(k)' <= 9999 {
      if "`sascode'" == "" {
        file write sasfile _n `"  ;;;"' _n `" set raw.`sysjobid'; "' _n
      }
      else {
        file write sasfile _n `"  ;;;"' _n `" set raw.`xfilen'; "' _n
      }
     }
     else if `c(k)' > 9999 {
      if "`sascode'" == "" {
        file write sasfile _n `"  ;;;"' _n `" set `sysjobid';"' _n
      }
      else {
        file write sasfile _n `"  ;;;"' _n `" set `xfilen';"' _n
      }
     }

	* VARIABLE LABEL
	* --------------

	file write sasfile _n _n " LABEL "
	foreach var of varlist `varlist' {
         local varlab : variable label `var'
         // add spaces around varlab so that varlab can start with a right quote and contain a right parentheses
         local varlab = trim(`" `varlab' "')
         if `"`varlab'"' != "" {
          // add spaces around varlab so that varlab can start with a right quote and contain a right parentheses
          if index(`" `varlab' "',`"'"') {
          /* substitute 2 single quotes for one single quote */
          local varlab = subinstr(`" `varlab' "',`"'"',`"''"',.)
          }
          //  enclosing the var label in single quotes keeps macro vars or calls
          //   to macros from happening
          if index(`" `varlab' "',"'") == 2 {
           /* if varlab starts with a single right quote, add space
            * before it so that it doesn't end the left compound quote in the
            * file write of varlabel. escaping it doesn't escape it */
            file write sasfile _n (upper("`var'")) `"=' `varlab' ' "'
          }
          else if substr(`"`varlab'"',length(`"`varlab'"'),1) == `"""' {
           // add a space at the end to separate the last double quote and the right quote
           file write sasfile _n (upper("  `var'")) `"='`varlab' ' "'
          }
          else {
           file write sasfile _n (upper("  `var'")) `"='`varlab'' "'
          }
	 } /* end of if varlab exists */
        } /* end of foreach */
	file write sasfile _n " ;;;"

	* ASSIGN VALUE LABELS
	* -------------------
	if `hasvl' == 1 {
 	 file write sasfile _n _n "format "
         local j 1
         foreach var of varlist `varlist' {
          local lbl : value label `var'
          capture label list `lbl'  // check to see if exists as defined label
          // if it doesn't, then give up and move on!
          if _rc == 111  local lbl ""
          if `"`lbl'"' != "" {
	   file write sasfile " `var' `lbl'."
           if (mod(`j',5) == 0) {  /* print 5 vars per line */
            file write sasfile _n
           }
          local j = `j' + 1
          } /* end of if var has label */
         } /* end foreach */

	 file write sasfile _n " ;;;"
	}  /* end of if variables have value labels */


	* NON-USER DEFINED FORMATS
	* ------------------------

	 file write sasfile _n _n "format "

       local j 1
       foreach var of varlist `varlist' {
        local storage : type `var'
        local fmt : format `var'
        if "`formats'" != "" {
         local lbl : value label `var'
         capture label list `lbl'  // check to see if exists as defined label
         // if it doesn't give up and move on!
         if _rc == 111  local lbl ""
        }
        local format = ""
        /* only assign formats to vars with no value label */
        if !index("`storage'"',"str") & `"`fmt'"' != "" & `"`lbl'"' == ""  {

         if substr(`"`fmt'"',length(`"`fmt'"'),1) == "f" {
          local format = substr("`fmt'",2,length("`fmt'") - 2)
          if `format' > 18 {
           local format = "18."
          }
          local format = "`format'"
         }
         else if substr(`"`fmt'"',length(`"`fmt'"')-1,2) == "0g" {
          local format = substr(`"`fmt'"',2,index(`"`fmt'"',".") - 2) + "."
          if `format' > 18 {
           local format = "18."
          }
          local format = "BEST" + "`format'"
         }
         else if substr(`"`fmt'"',length(`"`fmt'"'),1) == "c" {
          local format = substr(`"`fmt'"',2,length(`"`fmt'"',".") - 3)
          if `format' > 18 {
           local format = "18."
          }
          local format = "COMMA" + "`format'"
         }
         else if inlist(`"`fmt'"',"%dDlY","%dDmY","%dDMY", "%ddlY","%ddmY","%ddMY")   {
          local format = "DATE7."
         }
         else if inlist(`"`fmt'"',"%dDlCY","%dDmCY","%dDMCY", "%ddlCY","%ddmCY","%ddMCY")   {
          local format = "DATE9."
         }
         else if `"`fmt'"' == "%dD/N/Y"  {
          local format = "DDMMYY8."
         }
         else if `"`fmt'"' == "%dD/N/CY" {
          local format = "DDMMYY10."
         }
         else if `"`fmt'"' == "%dN/D/Y"  {
          local format = "MMDDYY8."
         }
         else if `"`fmt'"' == "%dN/D/CY" {
          local format = "MMDDYY10."
         }
         else if `"`fmt'"' == "%dYND"    {
          local format = "YYMMDD6."
         }
         else if `"`fmt'"' == "%dY-N-D"  {
          local format = "YYMMDD10."
         }
         else if `"`fmt'"' == "%dCY-N-D" {
          local format = "YYMMDD10."
         }
         else if `"`fmt'"' == "%dD"      {
          local format = "DAY."
         }
         else if `"`fmt'"' == "%dl"      {
          local format = "MONTH."
         }
         else if `"`fmt'"' == "%dY"      {
          local format = "YEAR2."
         }
         else if `"`fmt'"' == "%dCY"     {
          local format = "YEAR4."
         }
         else if `"`fmt'"' == "%dM"      {
          local format = "MONNAME."
         }
         else if `"`fmt'"' == "%dlY"     {
          local format = "MONYY5."
         }
         else if `"`fmt'"' == "%dlCY"    {
          local format = "MONYY7."
         }
         else if `"`fmt'"' == "%dd"      {
          local format = "WEEKDAY."
         }
         else if `"`fmt'"' == "%d"       {
          local format = "WORDDATE."
         }
         else if `"`fmt'"' == "%dYl"     {
          local format = "YYMON5."
         }
         else if `"`fmt'"' == "%dCYl"    {
          local format = "YYMON7."
         }
         else if index(`"`fmt'"',"%d") == 1  {   // the catch-all date format
          local format = "MMDDYY10."
         }

	 file write sasfile " `var' `format'"
         if (mod(`j',5) == 0) {  /* print 5 vars per line */
          file write sasfile _n
         }
         local j = `j' + 1
        } /* end of if var has a format */
       } /* end foreach */

       file write sasfile _n "  ;;; " _n "run;" _n ///
        " %let lib_error=&syserr.; " _n _n


   * CHECK SAS DATA
   * --------------
       if "`check'" != "" {
        noi di " "
        noi di `" You have requested savasas to generate a check file from SAS. * "'
        if "`engine'" == "xport" {
         noi di `"  The file is: "{res}`macval(dir)'`filen'`middle'_SAScheck.lst" * "'
        }
        else {
         noi di `"  The file is: "{res}`macval(dir)'`filen'_SAScheck.lst" * "'
        }
        noi di " "
        if "`engine'" == "xport" {
         file write sasfile _n `"proc printto print= "`macval(dir)'`filen'`middle'_SAScheck.lst" new; "' ///
            _n _n `" title "data= `macval(dir)'`filen'`middle': Compare results with Stata output."; "'
        }
        else if "`engine'" != "xport" {
         file write sasfile _n `"proc printto print= "`macval(dir)'`filen'_SAScheck.lst" new; "' ///
            _n _n `" title "data= `macval(dir)'`filen': Compare results with Stata output."; "'
        }
        file write sasfile  _n _n `" proc means    data= out.`filen'; run;"'      ///
            _n _n `" proc contents data= out.`filen'; run;"'      ///
            _n _n `" proc print    data= out.`filen' (obs=5); run; "'  ///
            _n _n `" proc printto; run; "' _n
       } /* end of checking */

   if "`sascode'" == "" {
      local out = "out."
      if "`engine'" == "xport" {
        file write sasfile _n `"data `filen';"' _n `" set out.`filen'; "' _n "run;" _n
        local out="work."
      }

       file write sasfile _n `"data test;"' _n `"call symput("N",compress(put(___lo___,10.)));"'  ///
           _n `" stop; "' _n `"set `out'`filen' nobs=___lo___; "'  _n `" run; "' _n               ///
           _n `"proc contents data= test out= contents noprint ;"' _n `"run; "' _n                  ///
           _n `"data _null_;"' _n `"call symput("nvars",compress(put(___lo___,5.)));"'            ///
           _n `"stop;"' _n `"set contents nobs=___lo___;"' _n `"run; "' _n                        ///
           _n _n `"data _null_;"' _n `"file "`raw'_infile_report.do"; "'                          ///
           _n `" put "capture program drop sas_rep"; "'                                           ///
           _n `" put "program define sas_rep"; "'

      if "`engine'" == "`rver'" {
         local ext = ".sas7bdat"
      }
      else if "`engine'" == "v6" {
       if "`c(os)'" == "Unix" & "`c(machine_type)'" != "PC" {  /* Unix */
         local ext = ".ssd01"
        }
       if "`c(os)'" == "Unix" & "`c(machine_type)'" == "PC" {  /* Linux */
         local ext = ".ssd02"
        }
       else {
        local ext = ".sd2"  /* Windows */
       }
      } /* end of if v6 */
      else if "`engine'" == "xport" {
        local filen = "`filen'" + "`middle'"
      } /* end of if xport */

      if index("`macval(dir)'","\") == 1 {  // Universal naming is an issue here since
       // this code writes code.  Stata sees / as a dir separator no matter the OS.
       // so add / since one \ will be lost
       local cdir `"/`macval(dir)'"'
       file write sasfile _n /*
        */ _n `"put "capture confirm file ""`macval(cdir)'`filen'`ext'"" "; "'  _n
      }
      else {
       file write sasfile _n /*
       */ _n `"put "capture confirm file ""`macval(dir)'`filen'`ext'"" "; "'   _n
      }
       file write sasfile _n ///
          _n `"put " if _rc == 0 { "; "'  _n                                                           ///
          _n `"put " di ""{help savasas:savasas} {txt}successfully saved the SAS file: *"""; "'_n
      if "`saswrapper'" == "" {
         file write sasfile _n ///
          _n `"put " di ""    {res}`macval(dir)'`filen'`ext'   {txt}  *"""; "'   _n
      }
      else {
         file write sasfile _n ///
          _n `"put " di ""    {res}`saswrap_data' in the SAS WORK library """; "'   _n
      }
       file write sasfile _n ///
          _n `"put " di ""{res}SAS &sysver. {txt}reports that the dataset has {res}&N {txt}observations "' _n ///
                        `"and {res}&nvars {txt}variables.     *"" "; "'   _n                         ///
          _n `"put "capture which usagelog"; "'   _n                                                 ///
          _n `"put " if _rc == 0 {"; "'  _n                                                            ///
          _n `"put "  usagelog , type(savas) message(""&sysuserid.  Output SAS dataset has &N obs and &nvars vars"")"; "' _n ///
          _n `"put " }"; "'  _n                                                                      ///
          _n `"put "}"; "' _n


        file write sasfile _n `" put "end"; "' _n  `"run;"' _n
   }  /* end of if sascode not wanted */


  * CLOSE SASFILE
  * -------------
       file close sasfile
       if `hasvl' == 1 & "`saswrapper'" == "" {
	noi di _n "{txt}SAS formats catalog file has been created:       *"
        if "`engine'" == "`rver'" & "`shortfileext'" == "" {
         noi di " {res}`macval(dir)'`filen'.sas7bcat  *"
        }
        else if "`engine'" == "v8" & "`shortfileext'" != "" {
         noi di " {res}`macval(dir)'`filen'.sc7  *"
        }
        else if "`engine'" == "v6" & "`c(os)'" == "Windows" {
         noi di " {res}`macval(dir)'`filen'.sc2  *"
        }
        else if "`engine'" == "v6" & "`c(os)'" == "Unix" & "`c(machine_type)'" == "PC" {  /* Linux */
         noi di " {res}`macval(dir)'`filen'.sct02  *"
        }
        else if "`engine'" == "v6" & "`c(os)'" == "Unix" & "`c(machine_type)'" != "PC" {  /* Unix */
         noi di " {res}`macval(dir)'`filen'.sct01  *"
        }
	noi di "{txt}Add the following SAS statements to the SAS program that    *"
        noi di "{txt}uses {res}`macval(dir)'`filen'`ext' {txt}:  * "
	noi di `"{res} libname in `engine' "`macval(dir)'" `shortfileext';  {txt}*"'
	noi di `"{res} options fmtsearch=(in.`filen');  {txt}*"'
       }
} /* end of quietly */

end




* CHECK THAT STATA VALUE LABEL NAMES CAN BE MADE INTO SAS FORMAT NAMES
* IF SO, THEN RENAME
* --------------------------------------------------------------------

program sav_lvchk
version 8
syntax , ml(integer) vars(varlist)

        local ren 0
        local flag5 = 0
        local bad_labs `" "'
        local names `"`r(names)'"'
        local renamed ""
        local orig_names ""


        foreach var of varlist `vars' {
          local lbl : value label `var'
          local nlbl = ""
          // check if that label has not already been renamed
          if `: list posof "`lbl'" in orig_name' == 0  {
            // check if label ends in a number--illegal in SAS
            if length("`lbl'") <= `= `ml'-1' &   (           ///
                  substr("`lbl'",length("`lbl'"),1) == "1" | ///
                  substr("`lbl'",length("`lbl'"),1) == "2" | ///
                  substr("`lbl'",length("`lbl'"),1) == "3" | ///
                  substr("`lbl'",length("`lbl'"),1) == "4" | ///
                  substr("`lbl'",length("`lbl'"),1) == "5" | ///
                  substr("`lbl'",length("`lbl'"),1) == "6" | ///
                  substr("`lbl'",length("`lbl'"),1) == "7" | ///
                  substr("`lbl'",length("`lbl'"),1) == "8" | ///
                  substr("`lbl'",length("`lbl'"),1) == "9" | ///
                  substr("`lbl'",length("`lbl'"),1) == "0") {
              local nlbl = "`lbl'_"
            }
            else if length("`lbl'") == `ml'  {
              if substr("`lbl'",`ml',1) == "1" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "z"
              }
              else if substr("`lbl'",`ml',1) == "2" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "y"
              }
              else if substr("`lbl'",`ml',1) == "3" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "x"
              }
              else if substr("`lbl'",`ml',1) == "4" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "w"
              }
              else if substr("`lbl'",`ml',1) == "5" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "v"
              }
              else if substr("`lbl'",`ml',1) == "6" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "u"
              }
              else if substr("`lbl'",`ml',1) == "7" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "t"
              }
              else if substr("`lbl'",`ml',1) == "8" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "s"
              }
              else if substr("`lbl'",`ml',1) == "9" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "r"
              }
              else if substr("`lbl'",`ml',1) == "0" {
                local nlbl = substr("`lbl'",1,`= `ml' - 1') + "q"
              }
            } // end of if label `ml' characters long and ends in a number
            else if length("`lbl'") > `ml' {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            // check that defined value label not a valid SAS format
            else if inlist(lower("`lbl'"),     ///
     "best"    ,"binary"  ,"comma"   ,"commax"  ,"d"       ,"date"    ,"datetime")  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "dateampm","day"     ,"ddmmyy"  ,"dollar"  ,"dollarx" ,"downame" ,"e"       )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "eurdfdd" ,"eurdfde" ,"eurdfdn" ,"eurdfdt" ,"eurdfdwn","eurdfmn" ,"eurdfmy" )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "eurdfwdx","eurdfwkx","float"   ,"fract"   ,"hex"     ,"hhmm"    ,"hour"    )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "ib"      ,"ibr"     ,"ieee"    ,"julday"  ,"julian"  ,"percent" ,"minguo"  )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "mmddyy"  ,"mmss"    ,"mmyy"    ,"monname" ,"month"   ,"monyy"   ,"negparen")  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "nengo"   ,"numx"    ,"octal"   ,"pd"      ,"pdjulg"  ,"pdjuli"  ,"pib"     )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "pibr"    ,"pk"      ,"pvalue"  ,"qtr"     ,"qtrr"    ,"rb"      ,"roman"   )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "s370ff"  ,"s370fib" ,"s370fibu","s370fpd" ,"s370fpdu","s370fpib","s370frb" )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "s370fzd" ,"s370fzdl","s370fzds","s370fzdt","s370fzdu","ssn"     ,"time"    )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "timeampm","tod"     ,"weekdate","weekdatx","weekday" ,"worddate","worddatx")  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "wordf"   ,"words"   ,"year"    ,"yen"     ,"yymm"    ,"yymmdd"  ,"yymon"   )  {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }
            else if inlist(lower("`lbl'"),     ///
     "yyq"     ,"yyqr"    ,"z"       ,"zd", "f") {
              local nlbl = substr("`lbl'",1,`= `ml' - 1') + "_"
            }

            // re-assign value labels using SAS-ok value label names
	    if `"`nlbl'"' != "" & `"`nlbl'"' != `"`lbl'"' {
              local ren = `ren' + 1   // count ones needed to be renamed
              if `: list posof "`nlbl'" in names' > 0 {  // nlbl already an existing label
                local flag5 = 1
                // make a list of bad value label names
                if `: list posof "`nlbl'" in bad_labs' == 0 {  // add if not already in list
                  local bad_labs `"`bad_labs'`nlbl' "'
                }
              }
              else {  // label okay to be renamed
                // assign new label to variable
                label value `var' `nlbl'
                if `ren' == 1 {
                  noi di _n "{txt}NOTE: SAS format names cannot be more than `ml' characters long, *"
                  noi di "      {txt}cannot end in a number, nor be a SAS reserved format name.  *"
                  noi di "{txt}NOTE: {res}The following value label(s) will have the following *"
                  noi di "      SAS format value name: *"
                  noi di as result `"Original"' _col(20)`"Renamed *"'
                  noi di as result `"--------"' _col(20)`"------- *"'
                }
                if `: list posof "`nlbl'" in renamed' == 0 {  // if not already listed
                  noi di as result `"`lbl'"' _col(20)`"`nlbl' *"'
                  local orig_names "`orig_names'`lbl' "  // add to list
                  local renamed "`renamed'`nlbl' "  //  add to list
	          // Use Nick Cox's labvalclone command to do just that!
	          labvalclone `lbl' `nlbl'
                }
              }
            }
          }  // end of if value label has not already been renamed
          else {
            // use existing label
            local nlbl "`: word `: list posof "`lbl'" in orig_name' of `renamed''"
            label `var' `nlbl'
          }

        } /* end of foreach */
        // now that all vars have been processed, drop the labels that were cloned
        foreach lbl of local orig_names {
	  label drop `lbl'
        }
        if `flag5' == 1 {
          foreach lab of local bad_labs {
            noi di "{error}NOTE: {res}value label `lab' {error}could not be uniquely renamed.  *"
          }
          noi di "{help savasas:savasas} {error}has stopped processing. *"

          file close sasfile

          error 499
        }
end


* WRITE OUT USER-DEFINED FORMATS AS A SAS DATASET SO THAT LONG FORMATS ARE NOT A PROBLEM
* --------------------------------------------------------------------------------------

program sav_labs_data, rclass
version 8
syntax [varlist], fhandle(string) ml(integer) filen(string)  raw(string)

 // need to re-create r(names) since sav_lvchk may have renamed labels
 label dir
 if "`r(names)'" != "" {  // dataset has value labels.  the check before sav_lvchk
                          //  has assured that they are used in data

   if `ml' == 8  local maxlablen = 256
   else  local maxlablen = 32000
   local lrecl =`maxlablen' + 75

   tempfile test
   file write `fhandle' _n `"data formats;"'
   file write `fhandle' _n `"length fmtname $`ml' start end 8 label $`maxlablen';"'
   file write `fhandle' _n `"infile "`raw'_formats.txt" lrecl=`lrecl' truncover ; "'
   file write `fhandle' _n `"input fmtname 1-32 start 34-53 end 55-74 label 76-`maxlablen';"'

   file open sas_formats using "`raw'_formats.txt", replace text write
   local lab2long = 0

   local names `r(names)'
   foreach lab of local names {
     tempname lab_in
     tempfile lab_file
     label save `lab' using `"`lab_file'"', replace
     file open `lab_in' using `"`lab_file'"', r  // read-only
     file read `lab_in' lab_line  // load first line of file to local macro var lab_line
     local lvs ""
     local n_lvs = 0 // number of label values
     // read lab_file one line at a time
     //  and count how many lines there are
     while r(eof) == 0 {
       local lv : word 4 of `lab_line'
       if `lv' < .  local n_lvs = `n_lvs' + 1
       // collect label values into one macro
       local lvs `"`lvs' `lv'"'
       file read `lab_in' lab_line
     } // end of while eof loop
     file close `lab_in'
     label list `lab' // just to figure out if has special missings or not
     if `r(min)' == . &  `r(max)' == .  {   // only has special missing values
       local fora `"each lv in `c(alpha)'"'  // really: "foreach lv in `c(alpha)'"
       local fors `"fora"'
     }
     else if `r(hasemiss)' == 1   {  // has both
       local forn `"val lvn = 1/`n_lvs'"'    // really: "forval lvn = 1/`n_lvs'"
       local fora `"each lv in `c(alpha)'"'  // really: "foreach lv in `c(alpha)'"
       local fors `"forn  fora"'
     }
     else if `r(min)' != . &  `r(max)' != .  { // has no special missing values
       local forn `"val lvn = 1/`n_lvs'"'     // really: "forval lvn = 1/`n_lvs'"
       local fors `"forn"'
     }
     foreach each_val of local fors {
       local multi_l = 0
       local write_lab = 0
       // this only works if there is always a loop to process
       for``each_val'' {  // adding the "for" help Stata not freak out when this section isn't run
         if "`each_val'" == "forn" {  // for numeric lists look for ranges
           local lv : word `lvn' of `lvs'
           local label : label `lab' `lv'
           // `label' equals the number if no label assigned
           //  which shouldn't happen now that only processing label values
           if `: list local(label) == local(lv)' == 0  {  // if value has a label
             local nlv : word `= `lvn'+1' of `lvs'
             local nlabel ""  // no label by default
             if `= `lvn'+1' <= `n_lvs' {  // : word > n words of string is invalid syntax
               local nlabel : label `lab' `nlv'
             }
             local plabel ""  // no label by default
             if `lvn' != 1 {  // : word 0 of string is invalid syntax
               local plv : word `= `lvn'-1' of `lvs'
               local plabel : label `lab' `plv'
             }
             local npl = 0
             if `: list local(label) == local(nlabel)' == 1  {
               if `: list local(label) == local(plabel)' == 0  {
                 if ( "`= `lv'+1'" == "`nlv'" )  {   // nlv is in quotes since it might = " "
                   local multi_l = 1
                   local start = `lv'
                   local npl = 1
                 }
               }
             }
             if `npl' == 0 & `: list local(label) == local(nlabel)' == 0  {
               if `multi_l' == 1  {
                 local write_lab = 1
                 local multi_l = 0
               }
               else {  // no range
                 local write_lab = 1
                 local start = `lv'
               }
             }
             else if `: list local(label) == local(nlabel)' == 1  & ///  {
                ( "`= `lv'+1'" != "`nlv'" )  { // no range because not continuous values
               local write_lab = 1
               local start = `lv'
             }  // end of checking for ranges
             if `write_lab' == 1 {
               local write_lab = 0
               if `: length local label' > `maxlablen'  {
                 local lab2long = 1
               }
                                   // `macval(label)' keeps dollar signs or `something'
                                   //  from being evaluated, $ being more likely
                                              // fmtname    start   end    label
               file write sas_formats _n _col(0)`"`lab'"' _col(34)`"`start'"' _col(57)`"`lv'"' _col(81)`"`macval(label)'"'
             }
           } // end of if value has a label
         }  // end of if for is forn
         else  {  // process fora list which is only special missings
           local label : label `lab' .`lv'
           // `label' equals the special missing value if no label assigned
           // ( there is length issue here since only checking for ".a", ".b" etc
           if "`label'" != ".`lv'" {   // if value has a label
             if `: length local label' > `maxlablen'  {
               local lab2long = 1
             }
                                   // `macval(label)' keeps dollar signs or `something'
                                   //  from being evaluated, $ being more likely
                                            // fmtname    start   end   label
             file write sas_formats _n _col(0)`"`lab'"' _col(34)`".`lv'"' _col(57)`".`lv'"' _col(81)`"`macval(label)'"'
           }
         }  // end if fora loop
       }  // end of for``each_val'' loop
     } // end of fors loop
   } // end foreach lab of local names


   file write `fhandle' _n `"run; "' _n
   file write `fhandle' _n _n  `"proc format library= library.`filen' cntlin= work.formats(where= (fmtname ^= ""));"'
   file write `fhandle' _n `"run; quit;"'
   // macro tests if SAS could create new formats catalog and erases it and does it again if SAS
   //  initially is not able to due to catalog file having been created for a different OS
   file write `fhandle' _n _n  `"%macro redo;"'
   file write `fhandle' _n     `" ** Check for this error message:"'
   file write `fhandle' _n     `"  * upcase(error:) File LIBRARY.`filen'.CATALOG was created for a different operating system. **;"'
   file write `fhandle' _n     `" %if &syserr. = 3000 %then %do;"'
   file write `fhandle' _n     `"   proc datasets library= library "'
   file write `fhandle' _n     `"                 memtype= catalog "'
   file write `fhandle' _n     `"                 nodetails nolist nowarn;"'
   file write `fhandle' _n     `"     delete `filen';"'
   file write `fhandle' _n     `"   run;"'
   file write `fhandle' _n     `"   ** now try it! **;"'
   file write `fhandle' _n     `"   proc format library= library.`filen' cntlin= work.formats(where= (fmtname ^= ""));"'
   file write `fhandle' _n     `"   run; quit;"'
   file write `fhandle' _n     `" %end;"'
   file write `fhandle' _n     `"%mend redo;"'
   file write `fhandle' _n     `"%redo;"'

   if `lab2long' == 1  {
     di as error "WARNING: at least one value label was truncated because it was longer than `maxlablen' characters"
   }
   // capture file close sas_formats since "``for'' {" throws stata off but this is now fixed so not a problem?
   capture file close sas_formats
 } // end of if dataset has value labels   (condition is probably not needed)

end


*! NJC 1.1.1 3 Nov 2002
* NJC 1.1.0 1 Nov 2002
program def labvalclone
	version 7
	args old new garbage
	if "`old'" == "" | "`new'" == "" | "`garbage'" != "" {
		di as err "syntax is: " /*
		*/ as txt "labvalclone {it:vallblname newvallblname}"
		exit 198
	}
	if "`old'" == "label" | "`old'" == "define" {
		di as err "won't work if {txt:`old'} is existing value label name"
		exit 198
	}
        capture label list `new'  // check to see if exists as defined label
	if _rc == 0 {
		di as err "value labels {txt:`new'} already exist"
		exit 198
	}

	tempfile file1 file2
	tempname in out

	qui label save `old' using `"`file1'"'
	file open `in' using `"`file1'"', r
	file open `out' using `"`file2'"', w
	file read `in' line

	while r(eof) == 0 {
		local line: subinstr local line "`old'" "`new'"
		file write `out' `"`line'"' _n
		file read `in' line
	}
	file close `out'

	qui do `"`file2'"'
end

exit