/************************************************************** * STATA_WRAPPER should work for you as is, but you may need * to edit this file to set the values for the macro variables: * ustata -- if you are using STATA_WRAPPER in a UNIX or Linux environment * wstata -- if you are using STATA_WRAPPER in a Windows environment * * There are instructions further down in this file explaining where * and how to edit the settings of these macro variables. * Do a find for "let ustata" or "let wstata". **************************************************************/ run; ** Because the world needs more run statements. **; %MACRO stata_wrapper(swoptions,out_dir); run; %** Because the world needs more run statements. **; %** If an error has occurred before call to STATA_WRAPPER then fail immediately. **; %if &syserr.^=0 %then %goto nevrmind; /********************************************************************************************* ** Macro: STATA_WRAPPER ** Input: Most recently created SAS WORK dataset and some Stata code to process. ** ** Output: by default will be included in the SAS output window/.lst file. ** ** Dependency: You need to have the Stata installed on your computer and have the ** Stata command -usesas- installed for STATA_WRAPPER to load your ** SAS dataset into Stata. It would also be a good idea to have the ** Stata command -savasas- installed as well if you want to pass data ** back to your SAS session. ** ** ** Programmer: Dan Blanchette dan_blanchette@unc.edu ** The Carolina Population Center at The University of North Carolina at Chapel Hill ** Developed at: ** Research Computing, UNC-CH and ** Center for Entrepreneurship and Innovation Duke University's Fuqua School of Business ** Date: 20March2008 ** Modified: 16Apr2012 - Made it so that Stata executables in the "Program Files (x86)" directory will be found. ** Modified: 28Mar2011 - Made it so that Stata 11 Windows executables can be found since Stata ** changed the names of them in Stata 11. Also made it so that ** if SAS on Linux is not allowed to CD to the work directory it CDs to /tmp/ ** to invoke Stata so that the file: _&swtfns._stata_wrapper.log ** in /tmp/ and can be safely deleted. ** Modified: 02Dec2010 - Fixed it so that scanning for options is only done when there are options ** specified by the user. ** Modified: 24Apr2008 - Added Stata command -sas_work- that changes directory (cd's) to ** the SAS WORK library/directory. It also returns the local macro ** r(sas_work) so that it can be used if needed. ** ** Modified: 27Jun2008 - Fixed problem with NOTES being shut off after running: ** %stata_wrapper(code) datalines; ** ** Disclaimer: This program is free to use and to distribute as long as credit is given to ** Dan Blanchette ** The Carolina Population Center ** University of North Carolina at Chapel Hill ** ** There is no warranty on this software either expressed or implied. This program ** is released under the terms and conditions of GNU General Public License. ** ** Comments: ** STATA_WRAPPER SAS macro when invoked by the SAS System passes the most recently created SAS dataset ** in the WORK library to Stata and runs the Stata code written after the %stata_wrapper(code) datalines; ** line. The log of the Stata code will be included in the SAS output window or .lst file unless an ** output directory name is specified. ** ** REQUIRED INPUT TO STATA_WRAPPER: ** -- STATA_WRAPPER needs to have the most recently created dataset by SAS to be in the WORK library ** and a Stata do-file to process. ** ** LIST OF OPTIONS: ** NOTE: Options can be used in any order. You can specify as many as you want ** or none at all. ** ** -code -- Used when only using writing Stata code to be submitted by STATA_WRAPPER. You must ** use it like so (You have to have "datalines;" after the call to STATA_WAPPER) : ** %stata_wrapper(code) datalines; ** svyset myPSUvar [pweight=myWeightVar], strata(MyStratumVar) ** svy:mean income weight height, over(agegroup race) ** ;; ** You should put at least one semi-colon after all your Stata code **; ** ** Your Stata code cannot contain any semi-colons. Do not use #delimit; **; ** ** If you really want to use semi-colons in your Stata code, use "datalines4;" **; ** * and end your Stata code with 4 semi-colons starting at the very **; ** * beginning of the line (column 1 through column 4) **; ** %stata_wrapper(code) datalines4; ** svyset myPSUvar [pweight=myWeightVar], strata(MyStratumVar) ** svy:mean income weight height, over(agegroup race) ** ;;;; ** You need 4 semi-colons starting at the beginning of the line. **; ** ** -replace -- If an output directory is specified and the output files you want to output already exist, ** -replace will then overwrite them with the files generated by STATA_WRAPPER ** ** -nodata -- Indicates not to load the most recent SAS dataset in the WORK library into Stata. ** This should be used when your Stata code does not require that dataset. ** ** -noformats -- Specifies not to create value labels (which is the default) from SAS user-defined formats ** that are stored in a SAS formats catalog file that has the same name as the dataset and is ** in the WORK directory. For example: MySasData.sas7bcat . If this file doesn't exist, ** -usesas- will look for the file formats.sas7bcat in the WORK directory. ** ** -int -- (Windows only option, not for Linux/UNIX) Keep interactive Stata running. You have to ** exit/close Stata before you can return to SAS or exit/close SAS since SAS is waiting ** for Stata to stop running. ** ** -log -- Includes the Stata log in your SAS log rather than your SAS output window/.lst file. ** ** =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ** Since STATA_WRAPPER uses the Stata command -usesas- to load the most recently created SAS dataset in ** the WORK library the following are options to be used by -usesas- when called by STATA_WRAPPER: ** =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ** ** -char2lab -- Specifies to encode long SAS character variables like the Stata command -encode-. Character ** variables that are too long for a Stata string variable are maintained in value labels. ** ** -float -- Specifies that numeric variables that would otherwise be stored as numeric type double be ** stored with numeric type float. This option should only be used if you are certain you ** have no integer variables that have more than 7 digits (like an id variable). ** ** -quotes -- Specifies that double quotes that exist in string variables are to be replaced with single ** quotes. Since the data are written out to an ASCII file and then read into Stata, double ** quotes are not allowed. ** =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ** ** -messy -- Puts the files generated by STATA_WRAPPER used to create the Stata log file in the directory ** named in the pathname provided in the call to the STATA_WRAPPER macro. ** ** ** SETTING UP STATA_WRAPPER ** These are instructions to edit the stata_wrapper.sas file. ** ** NOTE: If you are setting up this macro on your computer for the first time, ** please choose which version of Stata you are going to have STATA_WRAPPER use. ** If you do not choose to set one of the following switches, STATA_WRAPPER will ** figure out what version of Stata you are running for you. This may ** add a noticeable amount of time to processing so you may want to set these ** switches to the correct version of Stata. You can easily figure out what ** version of Stata you are using by looking at the top of your results window ** in Stata or by typing in the command -about- at the Stata command line. ** One advantage of leaving STATA_WRAPPER to figure out what version of Stata is ** being used is that when you upgrade your version of Stata you will not have to ** update stata_wrapper. ** ** NOTE: ** -- If you are running STATA_WRAPPER on UNIX or Linux then ** you need to be able to start a Stata batch job by: ** stata -b do mydofile.do ** If not, then change the setting of the ustata macro variable. **********************************************************************************************/ %local ustata; /** One of these may work: ** %let ustata=stata; %let ustata=/usr/local/stata/stata; %let ustata=/usr/local/stata/stata-mp; %let ustata=/usr/local/stata/stata-se; */ %let ustata=stata; /********************************************************************************************** ** ** -- If you are running STATA_WRAPPER on Windows, you may need to tell STATA_WRAPPER where ** the Stata executable file is located if STATA_WRAPPER cannot find it. ** If you do not know where your Stata executable file is located, find your Stata ** short-cut icon, right click on it, choose "properties", and look in the "target" field. ** This will show you where the Stata executable file is located on your hard drive. ** ***********************************************************************************************/ %local wstata; %** Change what is inside the parentheses to the location of your Stata executable file **; /** One of these may work: **; %let wstata= %nrstr(C:\Stata11\statase.exe); %let wstata= %nrstr(C:\Stata11\statamp.exe); %let wstata= %nrstr(C:\Stata11\stata.exe); ** Pre-Stata 11 versions: *; %let wstata= %nrstr(C:\Stata\wsestata.exe); %let wstata= %nrstr(C:\Stata\wmpstata.exe); %let wstata= %nrstr(C:\Stata\wstata.exe); */ %let wstata= %nrstr(C:\Stata\stata.exe); /********************************************************************************************* ** ** HOW TO USE THE STATA_WRAPPER MACRO: ** Using the STATA_WRAPPER macro requires that you understand how to use the "%include" statement ** and that you know how to call a SAS macro. ** ** %include'LOCATION AND NAME OF A FILE THAT CONTAINS SAS CODE'; ** ** For example, if you have copied this file to "C:\SASmacros", then you tell SAS ** about this macro by adding the following line to your SAS program: ** ** %include 'C:\SASmacros\stata_wrapper.sas'; ** ** This statement makes SAS aware of the STATA_WRAPPER macro which is in the file stata_wrapper.sas. ** To use the macro you have to make a call to it. To do that you add a line like the ** following to your SAS program: ** ** %stata_wrapper([options], "[folder to save Stata output]"); ** But you don't really have to specify anything if you want to use the defaults: ** %stata_wrapper; ** ** ** ** create data set that contains only the observations and variable(s) needed for the Stata command ** * to be run: **; ** data test; ** set my_data (keep=math cses one school ** where=(gender=1)); ** run; ** ** ** write some Stata code to be submitted by STATA_WRAPPER: **; ** %stata_wrapper(code) datalines; ** eq cses: cses ** eq one: one ** gllamm math cses, i(school) eqs(one cses) diff adapt nrf(2) ** ;;;; ** end Stata code with at least one semi-colon **; ** ** ** Have STATA_WRAPPER submit the above Stata code to Stata **; ** %stata_wrapper; ** ** ** Or you can submit a Stata do-file saved in some other directory: ** %stata_wrapper(code) datalines; ** do "C:\my_project\my_stata_code.do" ** ;;;; ** ** ** Have STATA_WRAPPER submit the above Stata code to Stata **; ** %stata_wrapper; ** ** ** The information inside the parentheses is passed on to the STATA_WRAPPER macro. The first ** string of information is any/all STATA_WRAPPER options. The second string ** of information is the location you want to save your Stata log file if you do not want it ** included in the SAS output window/.lst file. This is somewhat like a LIBNAME statement. ** ** ** EXAMPLE USE OF THE STATA_WRAPPER MACRO: ** %include "C:\SASmacros\stata_wrapper.sas"; ** Include macro once in a SAS session and call it **; ** * as many times as you like in that session. **; ** ** data work.ToBeStata; ** This makes a copy of the SAS dataset in the in the work library. **; ** set in.mySASfile (keep= math school ** where=(gender=2)); ** run; ** ** ** write some Stata code to be submitted to Stata by STATA_WRAPPER **; ** %stata_wrapper(code) datalines; ** matrix b1 = [12, 2, 8] ** gllamm math , i(school) from(b1) copy ** ;;;; ** ** ** now submit the above code to Stata **; ** %stata_wrapper; ** ** ** OTHER EXAMPLE CALLS: ** ** ** Save the Stata log file "_[some_big_number]_stata_code.log **; ** ** in C:\MyData\, overwriting it if it already exists. **; ** %stata_wrapper(-replace,"C:\MyData\"); ** ** ** Run the Stata do-file "my_stata_code.do in C:\MyProject\ and **; ** * save the Stata log file "_[some_big_number]_stata_code.log **; ** * in C:\MyData\, overwriting the log file if it already exists. **; ** %stata_wrapper(code); ** do "C:\MyProject\my_stata_code.do" ** ;;;; ** %stata_wrapper(-replace,"C:\MyData\"); ** ** ** This example is like a USESTATA SAS macro. ** ** %stata_wrapper(code) datalines; ** use "C:\My Project\Data\some_data.dta" ** savasas using "some_data.sas7bdat" ** ;;;; ** ** * specify not to use the most recently created SAS dataset in WORK **; ** * since your Stata code does not need it. **; ** %stata_wrapper(-nodata); ** ** ** now you can access this data set from your WORK library/directory because **; ** * no directory name was specified in the call to -savasas- above. **; ** proc contents work.some_data; ** run; ** ** The above example assumes that Stata is not set up to cd to some other directory when ** Stata is started up. If you are not in the SAS WORK library/directory at the moment ** when -savasas- is invoked you can use the Stata command -sas_work- to cd you to that ** directory. This command is only available while running STATA_WRAPPER. ** Here is an example using -sas_work- ** ** %stata_wrapper(code) datalines; ** use "C:\My Project\Data\some_data.dta" ** sas_work ** return list // this is optional but shows that the local macro r(sas_work) exists now ** savasas using "some_data.sas7bdat" ** ;;;; ** ** %stata_wrapper(-nodata); ** ** proc contents work.some_data; ** run; ** ***********************************************************************************************/ %local usagelog; %** SET LOCATION OF USAGE LOG FILE **; %let usagelog="specify what file name and location you want here"; %if "&sysscp."="WIN" %then %do; %let usagelog="x:\software\temp\stata_wrapper_usage.log"; %* windoze *; %end; %else %if "&sysscp."="RS6000" %then %do; %let usagelog="/afs/isis.unc.edu/home/d/a/danb/usage/stata_wrapper_usage.log"; %* AIX nodes *; %end; %else %if "&sysscp."="AIX 64" %then %do; %let usagelog="/afs/isis.unc.edu/home/d/a/danb/usage/stata_wrapper_usage.log"; %* AIX nodes *; %end; %else %if "&sysscp."="LINUX" %then %do; %* linux boxes *; %let usagelog="/afs/isis.unc.edu/home/d/a/danb/usage/stata_wrapper_usage.log"; %end; /***************************************************************************/ /****** !NO MORE EDITS TO THE MACRO SHOULD BE MADE BEYOND THIS POINT! ******/ /***************************************************************************/ %** local macro vars used in stata_wrapper: **; %local char2lab code decpos diffhour diffmin diffsec drive dset fail fail7 fdset float formats exe10 exe11 http i ii int isysver j jj k kk ldset lst_name messy newname no_out_dir nocd notes obs pwdir pwdrive quotes replace slash sw_dsn sw_last swtartdat swtfns swlog temp_dir unix u_sysrc w_sysrc work_dir ;;; %** make sure sas version is an integer so it can be properly evaluated **; %let isysver = %sysevalf(&sysver.,integer); %** Save option settings so they can be restored at the end of this macro. **; %let notes=%sysfunc(getoption(notes)); %let obs=%sysfunc(getoption(obs)); options obs=MAX; %*** Reason for maximizing it is because user could have **; %* set it lower than the number of variables in the dataset. **; options nonotes; %** Shut off notes while program is running in order to reduce log size. **; %** Time how long STATA_WRAPPER takes to run **; %let swtartdat=%sysfunc(datetime()); %let sprog=stata_wrapper; %let http=%nrstr(http://www.cpc.unc.edu/research/tools/data_analysis/sas_to_stata/)&sprog..html; %** initialize macro vars **; %let diffhour=0; %let diffmin=0; %let diffsec=0; %let fail=0; %let no_out_dir=0; %if %length(%nrbquote(&out_dir.)) = 0 %then %let no_out_dir = 1; %if %nrbquote(%index(%nrbquote(&out_dir.),%str(%")))=1 /** " end quote */ or %nrbquote(%index(%nrbquote(&out_dir.),%str(%')))=1 /** ' end quote */ %then %let out_dir=%nrbquote(%substr(%nrbquote(&out_dir.),2,%length(%nrbquote(&out_dir.))-2)); %let code=0; %** create stata_code.do in the WORK library: **; %if %index(%lowcase(%nrbquote(&swoptions.)),code) %then %do; %let code=1; data _null_; file "%nrbquote(%sysfunc(pathname(work)))/stata_code.do"; infile datalines truncover; input @1 sw $2. ; put _infile_; %end; options obs=&obs. ¬es. ; %** Restore options. **; %if &code.=1 %then %goto nevrmind; %** Find out what directory SAS currently is using as the present working directory **; %* so that it can be restored at end of macro. **; options nonotes; libname ________ " "; %** ________ is a very unlikely libname **; options ¬es. ; %** Restore notes. **; %let pwdir=%nrbquote(%sysfunc(pathname(________)))/; %let pwdrive= ; %if %index(%nrbquote(&pwdir.),\) %then %do; %let pwdrive= %qsubstr(%nrbquote(&pwdir.),1,2); %** get drive info eg. "D:" **; %end; %** use the work directory to store the temporary SAS files that this program creates ***; %let temp_dir = %nrbquote(%sysfunc(pathname(work))); %let work_dir = %nrbquote(%sysfunc(pathname(work))); %** this is first time program goes to a fail label **; %** Work directory cannot start with a back slash because stata_wrapper needs to cd to it. **; %if %index(%nrbquote(&work_dir.),\)=1 %then %goto fail1; %* if out_dir not specified then make it the work_dir **; %if &no_out_dir. = 1 %then %let out_dir=%nrbquote(&work_dir.); %** initialize var **; %let newname=; %** check to see if new log file name provided in %nrbquote(&out_dir.) **; %if %nrbquote(%length(&out_dir.)) > 0 %then %do; %if %nrbquote(%index(%qlowcase(&out_dir.),.log)) %then %do; %** if Stata dataset name provided with directory info **; %if "%qlowcase(%substr(%nrbquote(&out_dir.),%length(%nrbquote(&out_dir.))-3,4))"=".log" %then %do; %** if no backslash provided: savstata(D:mydata.log) then add in the backslash **; %if "&sysscp."="WIN" and %nrbquote(%index(%nrbquote(&out_dir.),:)) = 2 and %nrbquote(%index(%nrbquote(&out_dir.),\)) ^= 3 %then %let out_dir = %nrbquote(%substr(%nrbquote(&out_dir.),1,2)\%substr(%nrbquote(&out_dir.),3,%length(%nrbquote(&out_dir.))-2)); %let newname=%nrbquote(%substr(%nrbquote(&out_dir.),1,%length(%nrbquote(&out_dir.))-4)); %if %index(%nrbquote(&newname.),\) %then %do; %do %while(%nrbquote(%index(%nrbquote(&newname.),\))); %let newname=%nrbquote(%substr(%nrbquote(&newname.),%index(%nrbquote(&newname.),\)+1,%length(&newname.)-(%index(%nrbquote(&newname.),\)))); %end; %let out_dir=%nrbquote(%substr(%nrbquote(&out_dir.),1,%index(%nrbquote(&out_dir.),%nrbquote(&newname.))-1)); %end; %else %if %index(%nrbquote(&newname.),/) %then %do; %do %while(%nrbquote(%index(%nrbquote(&newname.),/))); %let newname=%nrbquote(%substr(%nrbquote(&newname.),%index(%nrbquote(&newname.),/)+1,%length(&newname.)-(%index(%nrbquote(&newname.),/)))); %end; %let out_dir=%nrbquote(%substr(%nrbquote(&out_dir.),1,%index(%nrbquote(&out_dir.),%nrbquote(&newname.))-1)); %end; %else %let out_dir=; %** only new name provided **; %end; %end; %** end of if %index(%nrbquote(&out_dir.),.log) do loop **; %end; %** end of if length(%nrbquote(&out_dir.)) = 0 do loop **; %let swoptions=%lowcase(%nrbquote(&swoptions.)); %let sw_dsn=&sysdsn.; %** preserve these to restore after setting up usagelog **; %** log usage of stata_wrapper if usage log file exists **; %if %sysfunc(fileexist(&usagelog.)) %then %do; options nonotes; data _null_; file &usagelog. mod; put " "; date=datetime() ; put " stata_wrapper macro " date dateampm. ; put " &sysuserid. stata_wrapper(&swoptions., &out_dir.)"; run; options ¬es. ; %** Restore notes. **; %end; %let sysdsn=&sw_dsn.; %** restore after setting up usagelog **; %** Initialize macro vars for stata_wrapper options **; %let int=0; %let nodata=0; %let replace= ; %let swlog=0; %let char2lab= ; %let formats=formats; %let float= ; %let quotes= ; %let messy=0; %** need to remove dashes from options as SAS thinks they are minus signs and wants to evaluate stuff **; %* need to do this in a data step so that the double quotes around options do not get added to the *; %* options macro variable *; data _null_; call symput('swoptions',translate("&swoptions."," ","-")); run; %if %str(&swoptions.) ^= %str() %then %do; %** Find out what options were specified **; %if %index(&swoptions.,rep) %then %let replace= replace; %** set replace option **; %if %index(&swoptions.,nod) %then %let nodata= 1; %** set nodata option **; %if %index(&swoptions.,int) %then %let int= 1; %** set int option **; %if %index(&swoptions.,log) %then %let swlog= 1; %** set log option **; %if %index(&swoptions.,fl) %then %let float= float; %** set float option **; %if %index(&swoptions.,nofor) %then %let formats=; %** set noformats option **; %if %index(&swoptions.,qu) %then %let quotes= quotes; %** set quote option **; %if %index(&swoptions.,cha) %then %let char2lab= char2lab; %** set char2lab option **; %if %index(&swoptions.,mes) %then %let messy= 1; %** set messy option **; %end; %if &nodata. = 0 %then %do; %*** Use the most recently created SAS work dataset. ***; %let sw_last=&syslast.; %let ldset=%length(&syslast.); %let decpos=%index(&syslast.,.); %let dset=%substr(&syslast.,&decpos.+1,&ldset.-&decpos.); %end; %** Figure out whether the operating system uses forward slashes or back slashes in **; %* directory paths and make sure that out_dir has the appropriate slash at the end. **; %let unix= 0; %let drive= ; %IF %index(%nrbquote(&temp_dir.),\) %THEN %do; %let unix=0; %** unix=0 implies windows platform **; %let drive= %qsubstr("&work_dir.",2,2); %** get drive info eg. "d:" **; %let temp_dir = %nrbquote(&temp_dir.)\; %** tack on a back slash **; %if "&out_dir."="" %then %goto fail3; %else %if "&out_dir."=" " %then %goto fail3; %else %if "&out_dir."="." %then %goto fail3; %let slash= %qsubstr("&out_dir.",%length("&out_dir.")-1,1); %** check if back slash at end **; %if "&slash."^="\" %THEN %do; /* " end quote */ %let out_dir= %nrbquote(&out_dir.)\; %** add a back slash at end if it is not there already **; %end; %let slash= %qsubstr("&work_dir.",%length("&work_dir.")-1,1); %** check if back slash at end **; %if "&slash."^="\" %THEN %do; /* " end quote */ %let work_dir= %nrbquote(&work_dir.)\; %** add a back slash at end if it is not there already **; %end; %end; %ELSE %IF %index(%nrbquote(&temp_dir.),/) %THEN %do; %let unix= 1; %** unix or unix-like platform **; %let temp_dir= %nrbquote(&temp_dir.)/; %** tack on a forward slash **; %** make sure that out_dir is not a relative directory name like: ../mydata/ **; options nonotes; libname ________ "&out_dir."; %** ________ is a very unlikely libname **; options ¬es. ; %** Restore notes. **; %let out_dir=%nrbquote(%sysfunc(pathname(________))); %let slash= %qsubstr("&out_dir.",%length("&out_dir.")-1,1); %** check if back slash at end **; %if "&slash."^="/" %THEN %do; %let out_dir= %nrbquote(&out_dir.)/; %** add a forward slash at end if it is not there already **; %end; %let slash= %qsubstr("&work_dir.",%length("&work_dir.")-1,1); %** check if back slash at end **; %if "&slash."^="/" %THEN %do; %let work_dir= %nrbquote(&work_dir.)/; %** add a forward slash at end if it is not there already **; %end; %END; %** ELSE IF index("temp_dir",/) THEN do loop **; %if &int. = 1 and &unix. = 1 %then %do; options notes; %put NOTE: The "-int" option is for Windows only. Stata will be run in batch.; options nonotes; %end; %** Make sure the dataset name and any option passed to stata_wrapper is in lower case. **; %let dset=%lowcase(%nrbquote(&dset.)); %if %length(&newname.)>0 %then %let fdset=%nrbquote(&newname.); %else %let fdset=%lowcase(%nrbquote(&dset.)); %if &nodata.=0 %then %do; %if %index(&syslast.,WORK)^=1 %then %goto fail2; %end; %** if obs are set to zero, error in program previous to stata_wrapper **; %if &obs. = 0 %then %goto fail6; %** check to see if user has set up Windows Stata correctly. **; %** if not then check other likely places the Stata executable would be. **; %let fail7= 0; %if &unix. = 0 and %sysfunc(fileexist("&wstata.")) = 0 %then %do %while(&fail7. = 0); %let drives= C D Y; %let exe10= wsestata wmpstata wstata wsmstata; %let exe11= statase statamp stata smstata; %** in version 11 Stata changed the names **; %if %sysfunc(substr(&SYSSCPL.,1,3)) = X64 %then %do; %** Windows X64 has different names starting in Stata 11 **; %* and it can run normal Stata executables *; %let exe11= statase-64 statamp-64 stata-64 statase statamp stata; %end; %else %if %sysfunc(substr(&SYSSCPL.,1,3)) = W64 %then %do; %** Windows Itanium has different names starting in Stata 11 **; %* and it can run normal Stata executables *; %let exe11= statase-ia statamp-ia stata-ia statase statamp stata; %end; %let versions= 14 13 12 11 10 9 8 7 6; %do i= 1 %to %sysfunc(countw(&drives.)); %** one for each drive **; %let ii =%scan(&drives.,&i.,%nrstr( )); %do j= 1 %to %sysfunc(countw(&exe11.)); %** one for each exe of stata **; %do k= 1 %to %sysfunc(countw(&versions.)); %** one for each version of stata **; %let kk= %scan(&versions.,&k.,%nrstr( )); %if %eval(&kk. < 11 ) %then %do; %let jj= %scan(&exe10.,&j.,%nrstr( )); %end; %else %do; %let jj= %scan(&exe11.,&j.,%nrstr( )); %end; %let wstata=%str(&ii.:\Stata&kk.\&jj..exe); %if %sysfunc(fileexist("&wstata."))=0 %then %do; %let wstata=%str(&ii.:\Program Files\Stata-&kk.\&jj..exe); %** Stata-9 **; %end; %else %goto exist; %** file exists **; %if %sysfunc(fileexist("&wstata."))=0 %then %do; %let wstata=%str(&ii.:\Program Files (x86)\Stata-&kk.\&jj..exe); %** Stata-9 **; %end; %else %goto exist; %** file exists **; %if %sysfunc(fileexist("&wstata"))=0 %then %do; %let wstata=%str(&ii.:\Program Files\Stata&kk.\&jj..exe); %** Stata9 **; %end; %else %goto exist; %** file exists **; %if %sysfunc(fileexist("&wstata"))=0 %then %do; %let wstata=%str(&ii.:\Program Files (x86)\Stata&kk.\&jj..exe); %** Stata9 **; %end; %else %goto exist; %** file exists **; %if %sysfunc(fileexist("&wstata."))=0 %then %do; %let wstata=%str(&ii.:\Stata-&kk.\&jj..exe); %** Stata-9 **; %end; %else %goto exist; %** file exists **; %if %sysfunc(fileexist("&wstata."))=0 %then %do; %let wstata=%str(&ii.:\Stata&kk.\&jj..exe); %** Stata9 **; %end; %else %goto exist; %** file exists **; %if %sysfunc(fileexist("&wstata."))=0 %then %do; %let wstata=%str(&ii.:\Stata\&jj..exe); %end; %else %goto exist; %** file exists **; %if %sysfunc(fileexist("&wstata."))=0 %then %do; %** nothing **; %end; %else %goto exist; %** file exists **; %end; %** of k loop **; %end; %** of j loop **; %end; %** of i loop **; %do; %** check path for Stata executable **; %let i= 1; %let delim= %str(;); %do %until (%qscan(%sysget(PATH),&i.,%str(&delim.)) = ); %do j= 1 %to %sysfunc(countw(&exe11.)); %** one for each exe of Stata **; %let jj= %scan(&exe11.,&j.,%nrstr( )); %let wstata= "%qscan(%sysget(PATH),&i.,%str(&delim.))\&jj..exe"; %if %sysfunc(fileexist("&wstata.")) %then %do; %let fail7= 2; %let i= 200000; %** break loop if found it **; %end; %end; %** of j loop **; %let i= %eval(&i.+1); %end; %** of until loop **; %if &fail7. = 2 %then %goto exist; %** file exists **; %end; %** of checking path for Stata executable **; %if %sysfunc(fileexist("&wstata.")) = 0 %then %do; %let fail7= 1; %** give up **; %end; %exist: ; %if &fail7. = 0 %then %let fail7= 2; %** found file so break while loop **; %end; %** end of if unix = 0 then do while loop **; %if &fail7. = 1 %then %goto fail7; %put STATA_WRAPPER is going to use this Stata executable:; %if &unix. = 0 %then %do; %put " %nrbquote(&wstata.)"; %put ; %end; %else %do; %put " %nrbquote(&ustata.)"; %put ; %end; options nonotes; libname ________ "&out_dir."; %** ________ is a very unlikely libname **; options ¬es. ; %** Restore notes. **; %if &syslibrc.^=0 %then %do; libname ________ clear; %** do away with it now **; %goto fail4; %** exit if not a valid pathname **; %end; options nonotes; libname ________ clear; %** do away with it now **; options ¬es. ; %** Restore notes. **; %if &messy. = 1 %then %do; %if &no_out_dir. = 1 %then %let out_dir=%nrbquote(&pwdir.); %** Use the output directory to store the SAS program files that this macro creates. ***; %let temp_dir= %nrbquote(&out_dir.); %if &unix. = 0 %then %do; %let windrive= %qsubstr("&out_dir.",2,2); %** get drive info eg. "d:" **; %sysexec &windrive.; ** change to whatever drive files are going **; %end; %** sysexec requires no quotes even when changing to dirs with spaces in windows or unix **; %sysexec cd %nrbquote(&out_dir.) ; %** change to the drive and directory where the Stata do-files are. **; %end; %* temporary file name...make it unique *; %let swtfns = &sysjobid.&sysindex.; %if %sysfunc(fileexist("&out_dir._&swtfns._stata_code.log")) %then %do; %if &replace.^=replace %then %do; %goto fail5; %end; %end; options nonotes; data _null_; file "&temp_dir._&swtfns._stata_wrapper.do" ls=2000; put "program define sas_work, rclass"; put "display as text `""cd `""&work_dir.""'""' "; put "quietly cd `""&work_dir.""' "; put " return local sas_work `""&work_dir.""'"; put "end "; %if &int. = 1 and &unix. = 0 %then %do; put "program define swexitnote"; put "di as res _n _dup(`c(linesize)') ""-"" "; %** create a horizontal line **; put "di as res ""NOTE: You have to exit Stata before you can return to SAS or exit/close SAS. "" "; put "di as res _dup(`c(linesize)') ""-"" "; put "end "; %end; %if &nodata.=0 %then %do; put "capture program drop swvtest"; put "program define swvtest"; put "if _caller() <=8 { "; put " di as text ""You need Stata 8.1 or newer to use -usesas-""" ; put "} "; put "end"; %end; put "log using ""&out_dir._&swtfns._stata_code.log"", &replace. "; %if &int. = 0 and &unix. = 0 %then %do; put "set more off"; %end; %if &nodata.=0 %then %do; put "swvtest"; put "usesas using ""&work_dir.&fdset..sas7bdat"", &formats. &char2lab. "es. &float. "; %end; put "do ""&work_dir.stata_code.do"" "; %if &int. = 0 %then %do; put "exit, clear STATA"; %end; %else %if &unix. = 0 %then %do; put "swexitnote"; %end; run; options ¬es. ; %** Restore notes. **; %** initialize macro vars for system return codes **; %let u_sysrc=0; %let w_sysrc=0; %if &unix. = 1 %then %do; %** This submits the Stata do-file stata_code . ***; %** sysexec requires no quotes even when changing to dirs with spaces in windows or unix **; %sysexec cd %nrbquote(&temp_dir.) ; %** change to the drive and directory where the Stata do-files are. **; %** test if able to cd to the work directory **; %sysexec echo $PWD > %nrbquote(&work_dir./_&swtfns._tdir.txt); data _null_; infile "%nrbquote(&work_dir./_&swtfns._tdir.txt)" lrecl= 32767 truncover; input test $200.; call symput('tdir',_infile_); run; %if %nrbquote(&tdir.) ne %nrbquote(&work_dir.) %then %do; %let nocd= cd; %sysexec cd /tmp/ ; %end; %** Run Stata in batch from within the directory where the temp files are. **; %if &nocd. = cd %then %do; %sysexec %nrbquote(&ustata.) -b do "&temp_dir._&swtfns._stata_wrapper.do"; %end; %else %do; %sysexec %nrbquote(&ustata.) -b do "_&swtfns._stata_wrapper.do"; %end; %let u_sysrc= &sysrc.; %** store value of sysrc until after loop **; %if &nocd. = cd and &messy. = 0 %then %do; %if %sysfunc(fileexist("_&swtfns._stata_wrapper_.log")) %then %do; %sysexec rm _&swtfns._stata_wrapper.log ; %end; %end; %end; %** if unix = 1 then do loop **; %if &unix. = 0 %then %do; %sysexec &drive.; %** sysexec requires no quotes even when changing to dirs with spaces in windows or unix **; %sysexec cd %nrbquote(&work_dir.) ; %** Run Stata interactively. **; %sysexec "&wstata." do "&temp_dir._&swtfns._stata_wrapper.do"; %let w_sysrc= &sysrc.; %** store value of sysrc until after loop **; %end; %** if unix = 0 then do loop **; %if &u_sysrc. ^= 0 %then %goto fail8; %if &w_sysrc. ^= 0 %then %goto fail7; %* only include Stata output to SAS lst if out_dir not specified **; %if %nrbquote(&out_dir.) = %nrbquote(&work_dir.) %then %do; %if %sysfunc(fileexist(%nrbquote(&out_dir._&swtfns._stata_code.log))) %then %do; data _null_; %if &swlog. = 0 %then %do; file print; %end; %else %do; file log; %end; %* probably only need to set lrecl to 256 since that is the max linesize for Stata *; infile "%nrbquote(&out_dir._&swtfns._stata_code.log)" lrecl= 32767 truncover; input @1 results $char1.; %** this line is basically irrelevant **; put _infile_; %** this is magic **; run; %end; %end; %else %if %nrbquote(&out_dir.) ^= %nrbquote(&work_dir.) %then %do; %* user specified to save results separately *; %if %sysfunc(fileexist(%nrbquote(&out_dir._&swtfns._stata_code.log))) %then %do; options notes; %put * ; %put NOTE: STATA_WRAPPER has created the Stata log file: * ; %put %nrbquote(&out_dir._&swtfns._stata_code.log) * ; %put * ; %end; %end; options nonotes; %** Make sure notes are shut off while deleting temp files and figuring out run time. **; %goto okay; %fail1: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put The work directory cannot start with a forward slash ( \ ) because * ; %put STATA_WRAPPER needs to cd to it. * ; %put Is it possible to reassign your work directory to a drive like C: or D: ? * ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=1; %goto okay; %** The following are all the failure messages returned to the user when the macro **; %* is unable to process the input SAS dataset. **; %fail2: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %if "%lowcase(&dset.)"="_null_" %then %do; %put You do not have a SAS dataset in the WORK library for * ; %put STATA_WRAPPER to load into Stata. * ; %end; %else %put The input dataset &dset. has to be in the work library. * ; %put For more help check here: &http. * ; %** SAS 8 will put a note at the end of the log stating what page errors **; %* occurred but earlier versions do not. So insert bad code to generate an error. **; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=2; %goto okay; %fail3: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put You did not tell STATA_WRAPPER what directory you want to save the Stata log file. * ; %put Your call to STATA_WRAPPER should look something like this: * ; %put %nrstr(%%)stata_wrapper(,"C:\mydata",-replace) * ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=3; %goto okay; %fail4: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put The directory %nrbquote(&out_dir.) does not exist. * ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=4; %goto okay; %fail5: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put The log file %nrbquote(&out_dir.)_&swtfns._stata_code.log already exists. * ; %put If you want to overwrite this file, then use the STATA_WRAPPER option "-replace". * ; %put Like: %nrstr(%%)stata_wrapper(%nrbquote(&out_dir.),-replace &swoptions.)%nrstr(;) ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=5; %goto okay; %fail6: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put The input dataset &dset. has no observations. * ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=6; %goto okay; %fail7: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put STATA_WRAPPER was not able to get Stata to execute. * ; %put This is not where your Stata executable file is located: * ; %put &wstata. * ; %put There are instructions in the top section of the stata_wrapper.sas file * ; %put that explain how to edit the stata_wrapper.sas file to set the * ; %put macro variable wstata to the correct location of your Stata executable file. * ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=7; %goto okay; %fail8: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put STATA_WRAPPER was not able to get Stata to execute. * ; %put This is not how to call Stata: * ; %put &ustata. *; %put There are instructions in the top section of the stata_wrapper.sas file * ; %put that explain how to edit the stata_wrapper.sas file to set the * ; %put macro variable ustata to the correct way to call Stata. * ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=8; %goto okay; %fail9: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put For reasons unknown STATA_WRAPPER was not able to get Stata to execute. * ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=9; %goto okay; %fail10: %put * ; %put ERROR: STATA_WRAPPER did not successfully run your Stata do-file * ; %put * ; %put For more help check here: &http. * ; %if &isysver.<8 %then STATA_WRAPPER did not successfully run your Stata do-file %put * ; %let fail=10; %goto okay; %okay: %put ; %if &messy.=1 %then %do; options notes; %put * ; %put NOTE: STATA_WRAPPER has created its intermediary files in: * ; %put %nrbquote(&out_dir.) * ; %put * ; %end; options nonotes; %** Make sure notes are shut off while deleting temp files and figuring out run time. **; %** Figure out how much time stata_wrapper took to process the Stata do-file. **; %** initialize macro vars **; %let diffhour=%sysfunc(compress(%sysfunc(hour(%sysfunc(datetime())-&swtartdat.)))); %let diffmin=%sysfunc(compress(%sysfunc(minute(%sysfunc(datetime())-&swtartdat.)))); %let diffsec=%sysfunc(compress(%sysfunc(second(%sysfunc(datetime())-&swtartdat.)))); options notes; %if &diffhour.>0 %then %put NOTE: STATA_WRAPPER took about &diffhour. hours and &dffmin. minutes to run. * ; %else %if &diffmin.=0 %then %put NOTE: STATA_WRAPPER took less than a minute to run. * ; %else %put NOTE: STATA_WRAPPER took about &diffmin. mins to run. * ; options nonotes; %if %sysfunc(fileexist(&usagelog.)) %then %do; data _null_; difftime=compress("&diffhour."||":"||"&diffmin."||":"||round(&diffsec.,0.1)); file &usagelog. mod; put " SAS dataset name: &dset. pwd=&pwdir. "; put " Elapsed time for STATA_WRAPPER macro is " difftime; put " fail=&fail. "; run; %end; options obs=&obs. ¬es. ; %** Restore options. **; %** Make sure that the last dataset created in work is the users dataset. **; %let sysdsn=&sw_dsn.; %let syslast=&sw_last.; %if &unix.=0 %then %do; %sysexec &pwdrive. ; %** change to the drive that SAS started out in. **; %end; %** end of if unix=0 do loop **; %** sysexec requires no quotes even when changing to dirs with spaces in windows or unix **; %sysexec cd &pwdir. ; %** change to the directory that SAS started out in. **; %nevrmind: ; %** Go to here if an error occurred before stata_wrapper started **; %MEND stata_wrapper;