*! saswrapper Version 1.1 dan.blanchette@duke.edu  08Jul2009
*! Center for Entrepreneurship and Innovation Duke University's Fuqua School of Business
* -removed stray carriage return characters
*  saswrapper Version 1.1 dan.blanchette@duke.edu  04May2009
* -made it fail more gracefully when usesas option specified and sas code had an error in it 
*  saswrapper Version 1.0 dan.blanchette@duke.edu  26Feb2009

program define saswrapper, rclass
version 8
syntax [varlist] [using/ ] [if] [in]  [, PRE_sas_prog(string) POST_sas_prog(string)  MEssy savasas(string) ///
                          usesas NODATA clear QUotes CHeck float char2lab NOFORMATS rename ] 

/* log usage of saswrapper */
capture which usagelog
if _rc == 0 {
  usagelog , start type(savas) message(`"saswrapper using `using', `messy' `savasas' `usesas' `nodata' `clear' `quotes' `check' `float' `char2lab' `noformats' `rename' "') 
}


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

if "`nodata'" != ""  & `"`savasas'"' != "" {
  di as err "cannot specify both nodata and savasas" _n
  capture which usagelog
  if _rc == 0 {
    usagelog , type(savas) uerror(8) etime
  }
  exit  499
}

if `c(N)' == 0 & "`nodata'" == "" {
  local nodata = "nodata"
}

if `"`usesas'"' != ""  & `c(N)' != 0 & "`clear'" == "" {
  di "{error} no, data in memory would be lost " 
  di "{error} use the {res}clear {error}option"
  /* log usage of saswrapper */
  capture which usagelog
  if _rc == 0 {
    usagelog , type(savas) uerror(1) etime
  }
  exit  4
}

local formats = "formats"
if "`noformats'" != ""  {
  local formats = ""
}


* CAPTURE USER'S LOG  
* ------------------
quietly log query
local usrlog  `r(filename)' 

* FIGURE OUT WHERE THE SAS EXECUTABLE IS
* --------------------------------------
sasexe saswrapper

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


local dirsep = "`c(dirsep)'"
if "`c(os)'" == "Windows" {
  local dirsep = "\"
}

local dir = "`c(pwd)'`dirsep'" 
if `"`using'"' != "" {
  // see if there is even one double quote in using
  local subtest : subinstr local using `"""' `""' , count(local cnt)
  if `cnt' != 0 {
    di `"{help saswrapper:saswrapper} {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 filename is given with directory info too, 
   *  strip to just file name and to dir location */
  if "`c(os)'" == "Windows" {
    if index("`using'","/") {
      local using : subinstr local using "/" "\" , all
    }
  }
  if index("`using'","`dirsep'") { 
    local filen=substr("`using'",index("`using'","`dirsep'")+1,length("`using'"))
    while index("`filen'","`dirsep'") !=0 {
      local filen = substr("`filen'",index("`filen'","`dirsep'")+1,length("`filen'"))
    }
    local dir = substr("`using'",1,index("`using'","`filen'")-1)
  }
  else if index("`using'","\\\") == 1 {   /* Universal naming convention */
    local filen = substr("`using'",index("`using'","\\\")+2,length("`using'"))
    while index("`filen'","\") !=0 {
      local filen = substr("`filen'",index("`filen'","\")+1,length("`filen'"))
    }
    local dir = substr("`using'",1,index("`using'","`filen'")-1)
  }
  else {  /* no directory given */
    local filen = "`using'"
    local dir = "`c(pwd)'`dirsep'" 
  }


  /** extract file extension if there is one **/
  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'"
    local filen = substr("`filen'",1,index("`filen'",".")-1)
  }
 
  if lower("`ext'") == "" { // guess that the user is wanting to use a .sas file
    local using1 `"`using'.sas"'
    local ext ".sas"
    capture confirm file `"`using1'"'
    if _rc == 0 {
      capture confirm file `"`using'"'
      if _rc == 0 {
        di `"{error}The SAS file: "`using'" does exist, but so does the SAS file: "`using1'" '"'
        di as text `"SAS will choose to run "`using1'" since it has the file extension ".sas" "'
        /* log usage of saswrapper */
        capture which usagelog
        if _rc == 0 {
          usagelog , type(savas) uerror(3) etime
        }
        exit 601
      }
    }
    // only here if this file does exist
    local using `"`using'.sas"'
  }
  else if lower("`ext'") != ".sas" {
    di as error `" "`ext'" is an invalid file extension  "'
    di as error `"{help saswrapper:saswrapper} can only run SAS program files which have the file extension ".sas" "'
    /* log usage of saswrapper */
    capture which usagelog
    if _rc == 0 {
      usagelog , type(savas) uerror(3) etime
    }
    exit 601
  }
 
 
  capture confirm file `"`using'"'
  if _rc != 0 {
    di `"{error}The SAS file: `using' does not exist."'
    /* log usage of saswrapper */
    capture which usagelog
    if _rc == 0 {
      usagelog , type(savas) uerror(3) etime
    }
    exit 601
  }
} // end of if "using" != ""

local usasprog "`using'"

if "`usasprog'" == "" & `"`pre_sas_prog'"' == "" & `"`post_sas_prog'"' == "" {
  di as err `"no SAS code to run "' _n
  /* log usage of saswrapper */
  capture which usagelog
  if _rc == 0 {
    usagelog , type(savas) uerror(3) etime
  }
  exit 601
}

/* 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 temp `"`macval(tmpdir)'_`sysjobid'"'


if "`nodata'" == "" {
  if `"`savasas'"' == "" {
    local stata_data  `"`c(filename)'"'
    if `: length local stata_data' != 0 {
      capture _getfilename `"`stata_data'"'  // get error message if only dir in using
      local stata_data `"`r(filename)'"'  // make using just the filename
      local stata_data : subinstr local stata_data ".dta" ""  // drop file extension
      valid_dset_name, dset(`stata_data') `rename'
      local stata_data = "`r(valid_dset_name)'"
    }
    else if `: length local stata_data' == 0 {
      local stata_data = "stata_data"
    }
  }
  else if `"`savasas'"' != "" {
    valid_dset_name, dset(`savasas') `rename'
    local stata_data = "`r(valid_dset_name)'"
  }

  if "`stata_data'" == ""   local stata_data = "stata_data"

  if "`check'" != "" {
    di as result _n `"Compare results with SAS output that will be printed next "' 
    // no reason to set more off because if user quits no temp files have been written yet
    local five_n = 5
    if _N < 5 {
      local five_n = _N
    }
    summarize `varlist' `if' `in'
    describe `varlist'
    list `varlist' in 1/`five_n'
  }
  
  di as result _n "now running {help savasas:savasas} to save the dataset `stata_data' to the SAS WORK library "
  savasas `varlist' using "`temp'_statadata.sas7bdat" `if' `in' , `formats' `rename' `messy' ///
                                saswrapper saswrap_data(`stata_data') sysjobid(`sysjobid')  
}


* WRITE SASWPAPPER SAS PROGRAM
* ----------------------------
saswrapper_sas , dirsep("`dirsep'") dir("`dir'") tmpdir("`tmpdir'") temp("`temp'") filen(`filen') sysjobid(`sysjobid') ///
                 usasprog("`usasprog'") pre_sas_prog(`" `pre_sas_prog' "') post_sas_prog(`" `post_sas_prog' "')        ///
                 rver(`rver') savastata("`savastata'") `quotes' `check' `float' `char2lab' char2fmt("`char2fmt'")      /// 
                 stata_data(`stata_data') `usesas' `nodata'
              

* RUN SAS
* -------
if "`c(os)'" == "Unix" /* or Linux */ {
  shell "`usas'" "`temp'_saswrapper.sas" -log "`temp'_saswrapper.log" -print "`temp'_saswrapper.lst"
} /* end of if Unix */
else if "`c(os)'" == "Windows" /* Windows */ {
  shell `wsas' "`temp'_saswrapper.sas" -nologo -log "`temp'_saswrapper.log" -print "`temp'_saswrapper.lst"
} /* end of if Windows */

capture confirm file `"`temp'_sascoderr.sas7bdat"'
if _rc == 0 {
  tempfile saswrapper_output
  copy `"`temp'_saswrapper.txt"' `"`saswrapper_output'"', text
 
  capture confirm file `"`saswrapper_output'"'
  if _rc == 0 {
    di as error _n "the submitted SAS code has an error in it " _n
  }
  // set usesas to missing so that saswrapper will fail gracefully
  local usesas 
}
 
* LOOK AT ANY REPORT FROM SAS  
* ---------------------------
capture confirm file `"`temp'_report.log"'
if _rc == 0 {
  type `"`temp'_report.log"'
  if "`messy'" == "" {
    erase `"`temp'_report.log"'
  }
}


if "`usesas'" != "" {
  * CLEAR DATA OUT OF MEMORY 
  * ------------------------
  if "`clear'" != "" {
    drop _all
    label drop _all
  }

  * LOAD STATA DATASET INTO MEMORY  
  * ------------------------------
  capture confirm file `"`temp'_infile.do"'
  if _rc == 0 {
    di as result _n "now loading the most recently created SAS dataset in submitted SAS program "
    di as result " savastata SAS macro saved this dataset to Stata " _n
    if `"`usrlog'"' != "" {
      quietly log close 
    }
    local cwd "`c(pwd)'"
    ** cd to where infile.do is **
    quietly cd "`tmpdir'"
    run `"_`sysjobid'_infile.do"'
    if `"`usrlog'"' != "" {
      quietly log using `"`usrlog'"' , append
    }

    * SET DATASET NAME 
    * ----------------
    if index("$S_FN","`dirsep'") == 1 {
      global S_FN : subinstr global S_FN "`dirsep'" ""
    }
    global S_FN `"`macval(dir)'$S_FN"' 

    // run savastata_report to see if SAS and Stata agree how many obs and vars there are
    savastata_report 
    di " " _n  // insert a blank space
  
    ** cd back to where you were **
    quietly cd "`cwd'"   
  } /* if infile.do file exists */
  else {
    di `"{error}{help saswrapper:saswrapper} failed."'
    capture confirm file `"`temp'_knerror.txt"'
    if _rc == 0 { 
      // savastata failed with a known error so just let report.log show the error 
      if "`c(os)'" != "Windows" {
        usesasdel `"`tmpdir'"' _`sysjobid'
      }
      if "`c(os)'" == "Windows" {
        local usesasdeldir : subinstr local tmpdir `":"' `"\\\`= char(58)'"', all
        usesasdel `"`usesasdeldir'"' _`sysjobid'
      }
    }
    else {
      di `"{error}If no error message above this one, then check out the SAS log file to see why. "'
      di `"  {view "`temp'_saswrapper.log"} "'
      di `"  and {view "`temp'_saswrapper.txt"} "'
      di `"{inp}Erase these temporary files created by {help saswrapper:saswrapper} when done with them:"'
      di `"{res}(files located in "`tmpdir'") "'
      ls "`temp'_*"   
      if "`c(console)'" != "console" {
        if "`c(os)'" != "Windows" {
          di `"{res} {stata usesasdel `"`tmpdir'"' _`sysjobid':Click here to erase them all.} "'
        }
        if "`c(os)'" == "Windows" {
          local usesasdeldir : subinstr local tmpdir `":"' `"\\\`= char(58)'"', all
          di `"{res} {stata usesasdel `"`usesasdeldir'"' _`sysjobid':Click here to erase them all.} "'
        }
      }
    }
  
    if "`usasprog'" != "" {
      di `""'
      if "`c(console)'" != "console" {
        di `"{inp}Click here to edit your SAS program and try it again. "'
        di `" {stata `"doedit "`usasprog'""':`usasprog'} "'
      }
      else di `"Edit your SAS program: "`usasprog'" and try it again."' _n
    }
    capture which usagelog
    if _rc == 0 {
      usagelog , type(savas) uerror(6) etime
    }
    exit 499
  }
} //end of if usesas


capture confirm file `"`temp'_saswrapper.txt"' 
if _rc == 0 {
  tempfile saswrapper_output
  copy `"`temp'_saswrapper.txt"' `"`saswrapper_output'"', text
}


* CLEAN UP TEMP FILES
* -------------------
if "`messy'"=="" {
  if "`c(os)'" != "Windows" {
    usesasdel `"`tmpdir'"' _`sysjobid'
  }
  if "`c(os)'" == "Windows" {
    local usesasdeldir : subinstr local tmpdir `":"' `"\\\`= char(58)'"', all
    usesasdel `"`usesasdeldir'"' _`sysjobid'
  }
} /* end of messy */
else {
  di "{res}You have requested {help saswrapper:saswrapper} not to delete the intermediary files" ///
      " created by {help saswrapper:saswrapper}:"
  dir "`temp'_*"
  di "{input}Files located here: "
  di `"{input}"`tmpdir'" "'

  if "`c(console)'" != "console" {
    if "`c(os)'" != "Windows" { 
      di `"{res} {stata usesasdel `"`tmpdir'"' _`sysjobid':Click here to erase them all.} "'
    }
    if "`c(os)'" == "Windows" { 
      local usesasdeldir : subinstr local tmpdir `":"' `"\\\`= char(58)'"', all 
      di `"{res} {stata usesasdel `"`usesasdeldir'"' _`sysjobid':Click here to erase them all.} "'
    }
  }
} // of if else if messy


// this is 2nd to last since user may break -more- which cancels saswrapper 
capture confirm file `"`saswrapper_output'"'
if _rc == 0 {
  di as result "the following is the results of the SAS program: " _n
  type `"`saswrapper_output'"'
}

// this is last since user may break -more- which cancels saswrapper 
if "`usesas'" != "" {  
  if "`check'" != "" {
    local gsfn : subinstr global S_FN ".dta" ""
    display as res _n " Compare these results with the results provided by SAS "
    display as res    " in the file `gsfn'_SAScheck.lst. " _n
    local five_n = 5
    if _N < 5 {
      local five_n = _N
    }
    summarize 
    describe 
    list in 1/`five_n'

    di _n "You have requested to have savastata provide a check file:"
    di `""`gsfn'_SAScheck.lst" "' _n 
  }
}

end /* end of saswrapper */


program define saswrapper_sas, nclass
syntax  [, dirsep(string) dir(string) tmpdir(string) temp(string) filen(string) sysjobid(string)  ///
           usasprog(string) pre_sas_prog(string) post_sas_prog(string)                            /// 
           rver(string) savastata(string) quotes check float char2lab char2fmt(string)            ///
           stata_data(string) usesas NODATA]
version 8   


quietly {
       file open sasfile using `"`temp'_saswrapper.sas"', replace text write

       file write sasfile `"* saswrapper SAS program *;                    "' _n _n ///
          `" options nonotes nofmterr nocenter linesize=`c(linesize)' source2;"' _n _n ///
            `"   ** need to create this file now as may only be able to *"' _n ///
            `"    *  erase it later. **;                                 "' _n ///
            `" libname _saswrap "`tmpdir'";                              "' 

       file write sasfile `"* sas error test *;                          "' _n _n ///
            `"   data _saswrap._`sysjobid'_sascoderr;                    "' _n ///
            `"    do i = 1 to 1;                                         "' _n ///
            `"      message="submitted SAS code has an error";           "' _n ///
            `"    end;                                                   "' _n ///
            `"   run;                                                    "' _n ///
            `"   %let syslast=;                                          "' _n


       if "`stata_data'" != "" { // put data (and formats catalog file) into WORK library
         capture confirm file `"`temp'_statadata.sas7bdat"'
         if _rc == 0 {
           file write sasfile `" proc datasets library= _saswrap; "'   _n ///
              `"   copy in= _saswrap out= work move;              "'   _n ///
              `"   select _`sysjobid'_statadata (memtype= data);  "'   _n ///
              `" run;                                             "'   _n _n 
           file write sasfile `" proc datasets library= work; "'                      _n ///
              `"   change _`sysjobid'_statadata = `stata_data' / memtype= data;   "'  _n ///
              `" run;                                                             "'  _n ///
              `" quit;                                                            "'  _n _n ///
              `" %let syslast=work.`stata_data';                                  "'  _n _n 
         }
         capture confirm file `"`temp'_statadata.sas7bcat"'
         if _rc == 0 {
           file write sasfile `" proc datasets library= _saswrap;   "' _n ///
              `"   copy in= _saswrap out= work move;                "' _n ///
              `"   select _`sysjobid'_statadata (memtype= catalog); "' _n ///
              `" run;                                               "' _n _n 

           file write sasfile `" proc datasets library= work;                      "' _n ///
              `"   change _`sysjobid'_statadata = formats / memtype= catalog;      "' _n ///
              `" run;                                                              "' _n ///
              `" quit;                                                             "' _n _n 
         }
       }

       file write sasfile `" proc printto print="`temp'_saswrapper.txt" log="`temp'_saswrapper.txt"; "' _n ///
          `" run;                                                                                    "' _n _n ///
          `" options notes;                                                                          "' _n _n

       if "`check'" != "" & "`nodata'" == "" {
         file write sasfile `"                                                           "' _n ///
            `" /****** THE FOLLOWING IS THE DATA CHECK YOU REQUESTED ******/             "' _n  

         file write sasfile  `"                                                          "' _n ///
            `" proc means    data=work.`stata_data';                                     "' _n ///
            `" run;                                                                      "' _n _n ///
            `" proc contents data=work.`stata_data';                                     "' _n ///
            `" run;                                                                      "' _n _n ///
            `" proc print    data=work.`stata_data' (obs=5);                             "' _n /// 
            `" run;                                                                      "' _n 

         file write sasfile `"                                                           "' _n ///
            `" /************ END OF THE DATA CHECK YOU REQUESTED **********/             "' _n  
       }

       if `"`pre_sas_prog'"' != "  " {   // two spaces because pre_sas_prog(`" `pre_sas_prog' "')
         file write sasfile `"                                                           "' _n _n ///
            `" /********* THE FOLLOWING IS YOUR pre_sas_prog CODE *********/             "' _n _n 

         local len_pre_sas_prog : length local pre_sas_prog
         if `len_pre_sas_prog' < 256 { // 256 is the max but there is a space at beginning and end 
           file write sasfile `" `pre_sas_prog' "' _n _n 
         } 
         else {
           tokenize `" `pre_sas_prog' "', parse(";")
           local orig_length : length local pre_sas_prog
           local nosemis : subinstr local pre_sas_prog ";" "", all
           local s_length : length local nosemis
           // tokenize puts the semicolons in the even numbered macro vars
           local n_semis = (`orig_length' - `s_length' ) * 2
  
           local odd = 1
           forval line = 1/`n_semis' {
             if `odd' == 3 {
               local odd = 1
             }
             if `odd' == 1  { // tokenize puts the semicolons in the even numbered macro vars
               file write sasfile `" ``line''; "' _n _n 
             }
             local odd = `odd' + 1
           }
         }
         //     the following semi-colon is there in case user forgot to end their code with one. 
         file write sasfile `" ;                                                         "' _n _n ///
            `" /************** END OF YOUR pre_sas_prog CODE **************/             "' _n _n 
       }

       if "`usasprog'" != "" {  /* user submitted a SAS program */
         file write sasfile `"                                                     "' _n _n ///
            `" /********* THE FOLLOWING IS YOUR SAS PROGRAM *********/             "' _n _n ///
            `"  %include"`usasprog'";                                              "' _n _n ///
            `" /************** END OF YOUR SAS PROGRAM **************/             "' _n _n 
       }

       if `"`post_sas_prog'"' != "  " { // two spaces because pre_sas_prog(`" `post_sas_prog' "')
         file write sasfile `"                                                            "' _n _n ///
            `" /********* THE FOLLOWING IS YOUR post_sas_prog CODE *********/             "' _n _n 
         local len_post_sas_prog : length local post_sas_prog
         if `len_post_sas_prog' < 256 {  // 256 is the max but there is a space at beginning and end
           file write sasfile `" `post_sas_prog' "' _n _n 
         } 
         else {
           tokenize `" `post_sas_prog' "', parse(";")
           local orig_length : length local post_sas_prog
           local nosemis : subinstr local post_sas_prog ";" "", all
           local s_length : length local nosemis
           // tokenize puts the semicolons in the even numbered macro vars
           local n_semis = (`orig_length' - `s_length' ) * 2
           local odd = 1
           forval line = 1/`n_semis' {
             if `odd' == 3 {
               local odd = 1
             }
             if `odd' == 1 { // tokenize puts the semicolons in the even numbered macro vars
               file write sasfile `" ``line''; "' _n _n
             }
             local odd = `odd' + 1
           }
         }
         file write sasfile `"                                                            "' _n _n ///
            `" /************** END OF YOUR post_sas_prog CODE **************/             "' _n _n 
       }

       //     the following semi-colon is there in case user forgot to end their code with one. 
       file write sasfile `" ; proc printto;                            "' _n  ///
          `" run;                                                       "' _n  ///
          `" quit;  ** close up anything they might have left going **; "' _n _n 

       if `"`usesas'"' != "" {
         file write sasfile `" %let sortedby=; ** leave in for now **;   "' _n _n ///
            `"%macro makework;                                           "' _n ///
            `"   run;                                                    "' _n ///
            `" %let nobs=%sysfunc(getoption(obs));                           "' _n ///
            `" %if &syserr.^=0 or &nobs.=0 or "&syslast."="_NULL_" %then %do;"' _n ///
            `"   %goto nevrmind;                                             "' _n ///
            `" %end;                                                         "' _n ///
            `" %let syslast1=&syslast.;                                      "' _n _n
         file write sasfile `" proc datasets library= _saswrap;            "' _n ///
            `"   copy in= _saswrap out= work move;                         "' _n ///
            `"   select _`sysjobid'_sascoderr (memtype= data);             "' _n ///
            `" run;                                                        "' _n _n ///
            `" quit;                                                       "' _n _n ///
            `" %let syslast=&syslast1.;                                    "' _n _n

         file write sasfile `"%if "&syslast." ^= "_NULL_" %then %do;       "' _n ///
            `"   %let ldset=%length(&syslast.);                            "' _n ///
            `"   %let decpos=%index(&syslast.,.);                          "' _n ///
            `"   %let llib=%substr(&syslast.,1,&decpos.-1);                "' _n ///
            `"   %let dset=%substr(&syslast.,&decpos.+1,&ldset.-&decpos.); "' _n ///
            `"   %let dset=%sysfunc(lowcase(%nrbquote(&dset.)));           "' _n _n
         file write sasfile  `"   data _null_;                             "' _n ///
            `"    dsid=open("&syslast.",'i');"' _n  `"    sortedby=attrc(dsid,'SORTEDBY'); "' _n   ///
            `"    call symput('sortedby',trim(sortedby));"' _n `"    rc=close(dsid);"' _n `"   run;"' _n _n 
         file write sasfile  `"   %if %index(%upcase(&sortedby.),DESCENDING) %then %do;  "' _n ///
            `"      %* this is how Stata treats descending sortedby  *;    "' _n ///
            `"      %let sortedby= %substr(&sortedby.,1,%index(%upcase(&sortedby.),DESCENDING)-1); "' _n ///
            `"   %end;"' _n _n 
         file write sasfile  `"   ** if not in work make it be in work **; "' _n ///
            `"   %if %index(%upcase(&syslast.),WORK)^=1 %then %do;         "' _n ///
            `"     data work.&dset.;                                       "' _n ///
            `"      set &syslast.;"' _n  `"     run;                       "' _n ///
            `"   %end; ** end of if syslast is not in WORK **;             "' _n _n ///
            `" %end; ** end of if syslast is _NULL_ **;                    "' _n _n


         file write sasfile `" %nevrmind: ;                             "' _n ///
           `"%mend makework;                                            "' _n ///
           `"%makework;                                                 "'
 
         if `c(stata_version)' < 9 & "`char2lab'" != "" {
           noisily {
             di as error `"option char2lab is not allowed prior to Stata 9."'
             di as error `"option will be ignored."'
             local char2lab ""  
           }
         }
         file write sasfile  _n _n ///
           `"%macro runit;                                                     "' _n _n ///
            `" %let nobs=%sysfunc(getoption(obs));                             "' _n ///
            `" %if &syserr.^=0 or &nobs.=0 or "&syslast." = "_NULL_" %then %do;"' _n ///
            `" proc printto log="`temp'_saswrapper.txt";                       "' _n ///
            `"      run;                                                       "' _n ///
            `"      %put %upcase(error:) no dataset in SAS to load into Stata; "' _n ///
            `"   %goto nevrmind;                                               "' _n ///
            `" %end;                                                           "' _n
            // need to put c(SE) and c(MP) in quotes since c(MP) doesn't exist in Stata 8
            // need to pass a zero or a one to savastata for SE or MP
         file write sasfile `" options nomprint nosource2;  "' _n _n  
         file write sasfile `" %include "`savastata'"; "' _n   ///            
            `" libname ___dir__ "`dir'" ; %* directory where _SAScheck.lst is saved to *;       "' _n  ///
            `" %let _dir=%nrbquote(%sysfunc(pathname(___dir__)));                               "' _n  ///
            `" /* &sortedby. is global because of:  call symput creates it */                   "' _n  ///
            `" %savastata("`tmpdir'",`quotes' `char2lab' `check' messy `float',&sortedby.,      "'     ///
            `"  `sysjobid',nosave,"&_dir.`dirsep'",`= ("`c(SE)'" == "1") + ("`c(MP)'" == "1")', "'     ///
            `"  version=`c(stata_version)');                                                    "' _n  ///
            `" %nevrmind: ;                                                                     "' _n  ///
           `"%mend runit;"' _n  `"%runit;"' _n
       } // end of if usesas
  
       file close sasfile
      
} /* end of quietly */
end


program valid_dset_name, rclass
syntax , dset(string) [rename]
 version 8   

local filen `dset'
    
local fc = substr("`filen'",1,1)

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 */

return local valid_dset_name `filen'

end
