You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1968 lines
74 KiB
Plaintext

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