*! version 1.2.11 18feb2010 program define sjlog if _caller() < 8.0 { sjlog_7 `0' exit } version 8.0 local vv : display _caller() gettoken cmd 0 : 0, parse(" ,") local l = length(`"`cmd'"') if `"`cmd'"' == "using" | `"`cmd'"' == "open" { LogOpen `0' } else if `"`cmd'"' == "close" { LogClose `0' } else if `"`cmd'"' == "do" { LogDo `vv' `0' } else if `"`cmd'"' == "clean" { LogClean `0' } else if `"`cmd'"' == "type" { LogType `0' } else if `"`cmd'"' == substr("basename",1,`l') { LogBaseName `0' } else if `"`cmd'"' == "" { log } else { di as err "`cmd' invalid" exit 198 } end program define LogSetup syntax [, clear ] if "`clear'" != "" { clear program drop _all } capture log close set rmsg off set more off set trace off end program define StripQuotes syntax anything(name=name id="name") [, string(string) ] c_local `name' `"`string'"' end /* basename *****************************************************************/ program define LogBaseName, rclass syntax anything(name=file id="filename") [, Display ] StripQuotes file , string(`file') local dirsep "/" /* strip off the directory path */ gettoken dir rest : file, parse("/\:") while `"`rest'"' != "" { if `"`dir'"' == "\" { local dir `"`dirsep'"' } local dirname `"`dirname'`dir'"' gettoken dir rest : rest , parse("\/:") } if `"`dirname'"' == "" { local dirname .`dirsep' } /* strip off the extension */ gettoken ext rest : dir, parse(".") while `"`rest'"' != "" { local basename `basename'`ext' gettoken ext rest : rest , parse(".") } if `"`basename'"' == "" { local basename `ext' local ext } else { /* remove the last "." from `basename' */ local l = length(`"`basename'"') - 1 local basename = substr(`"`basename'"',1,`l') } /* saved results */ return local ext = cond(`"`ext'"'=="","",".") + `"`ext'"' return local base `"`basename'"' return local dir `"`dirname'"' return local fn `"`file'"' if `"`display'"' != "" { display as txt `"fn: `return(fn)'"' display as txt `"dir: `return(dir)'"' display as txt `"base: `return(base)'"' display as txt `"ext: `return(ext)'"' } end /* using/close/do: subroutines **********************************************/ program define LogOpen syntax anything(name=file id="filename") [, append replace ] LogSetup LogBaseName `file' local ext `"`r(ext)'"' if `"`ext'"' != ".smcl" { local file `"`r(fn)'.smcl"' } quietly log using `"`file'"', smcl `append' `replace' end program define LogClose, rclass syntax [, /* */ book /* */ replace /* */ noCLEAN /* */ noLOGfile /* */ sjlogdo /* internal only, NOT documented */ ] if `"`sjlogdo'"' == "" { local logtype sjlog } else local logtype `sjlogdo' quietly log LogBaseName `"`r(filename)'"' local dir `"`r(dir)'"' local base `"`r(base)'"' local ext `"`r(ext)'"' local file `"`r(fn)'"' local dbase `"`dir'`base'"' quietly log close /* log assumed to be a smcl file */ if `"`ext'"' != ".smcl" { di in red "assumption failed -- log file not smcl" exit 198 } if `"`clean'"' == "" { LogClean `"`file'"', `logtype' erase `"`r(fnbak)'"' } /* get TeX version of log */ qui log texman `"`file'"' `"`dbase'.log.tex"', `replace' `book' if `"`logfile'"' == "" { /* get plain text version of log */ qui translate `"`file'"' `"`dbase'.log"', `replace' } /* saved results */ if `"`logfile'"' == "" { return local fn_log `"`dbase'.log"' } return local fn_tex `"`dbase'.log.tex"' return local fn_smcl `"`dbase'.smcl"' end program define LogDo version 8.0 gettoken vv 0 : 0 local vv "version `vv':" syntax anything(name=file id="filename") [, /// clear /// replace /// book /// nostop /// SAVing(string) /// ] if "`saving'" != "" { capture confirm name `saving' if _rc { di as err /// "'`saving'' found where saving() option requires a valid name" exit 198 } } LogSetup, `clear' LogBaseName `file' local base = cond("`saving'"=="","`r(base)'","`saving'") local dbase `"`r(dir)'`base'"' local ext `"`r(ext)'"' local file `"`r(fn)'"' if `"`ext'"' != ".do" { local dbase `"`dbase'`ext'"' } LogOpen `dbase', `replace' capture noisily `vv' do `file', `stop' local rc = _rc if `rc' { local cap capture } `cap' LogClose, `replace' sjlogdo `book' exit `rc' end /* clean: subroutines *******************************************************/ program define LogClean, rclass syntax anything(name=file id="filename") [, /* */ log /* */ logclose /* */ sjlog /* */ sjlogdo /* */ ] /* validate arguments and options */ local logsrc `log' `logclose' `sjlog' `sjlogdo' local wc : word count `logsrc' if `wc' > 1 { di as err "options `logsrc' may not be combined" exit 198 } StripQuotes file , string(`file') confirm file `"`file'"' /* open files */ tempname rf wf tempfile newfile file open `rf' using `"`file'"', read text file open `wf' using `"`newfile'"', write text /* clean file */ capture noisily { if `"`logsrc'"' == "logclose" { CleanLogclose `rf' `wf' } else if `"`logsrc'"' == "sjlog" { CleanSJLog `rf' `wf' } else if `"`logsrc'"' == "sjlogdo" { CleanSJLogDo `rf' `wf' } else { /* Default: `"`logsrc'"' == "log" */ CleanLog `rf' `wf' } } // capture noisily local rc = _rc /* close files */ file close `wf' file close `rf' if (`rc') exit `rc' /* make a backup copy of the input file (rf) and save the output file * (wf) using the given filename */ local backup `file'.bak copy `"`file'"' `"`backup'"', replace copy `"`newfile'"' `"`file'"', replace /* saved results */ return local fnbak `"`backup'"' return local fn `"`file'"' end /* Clean log produced by -sjlog do-. * * This subroutine has a 3 line buffer; the end of a log from -sjlog do- will * always have: * * 1. a blank line * 2. a line with the text: "." * 3. a line with the text: "end of do-file" * * This subroutine also works with smcl files, and TeX files generated from * smcl files using -log texman- (its original purpose). */ program define CleanSJLogDo args rf wf /* skip the smcl header lines */ file read `rf' line1 if `"`line1'"' == "{smcl}" { file read `rf' line1 /* skip next line too, if is part of the smcl header */ if `"`line1'"' == "{com}{sf}{ul off}{txt}" { file read `rf' line1 } file read `rf' line2 } else { file read `rf' line2 } file read `rf' line3 local break 0 while r(eof)==0 { if substr(`"`line3'"',-14,.) == "end of do-file" { local break 1 continue, break } file write `wf' `"`macval(line1)'"' _n local line1 `"`macval(line2)'"' local line2 `"`macval(line3)'"' file read `rf' line3 } if ! `break' { file write `wf' `"`macval(line1)'"' _n file write `wf' `"`macval(line2)'"' _n } else { if !inlist(`"`macval(line1)'"',"{txt}","{res}{txt}") { file write `wf' `"`macval(line1)'"' _n } } end /* Clean log produced by -sjlog using- and -sjlog close-. */ program define CleanSJLog args rf wf CleanLogUsingHeader `rf' /* skip the smcl header lines */ file read `rf' line1 if `"`line1'"' == "{smcl}" { file read `rf' line1 /* skip next line too, if is part of the smcl header */ if `"`line1'"' == "{com}{sf}{ul off}{txt}" { file read `rf' line1 } file read `rf' line2 } else { file read `rf' line2 } local break 0 while r(eof)==0 { if index(`"`line2'"',". sjlog close") { local break 1 continue, break } file write `wf' `"`macval(line1)'"' _n local line1 `"`macval(line2)'"' file read `rf' line2 } if ! `break' | !inlist(`"`macval(line1)'"', "", "{res}{txt}") { file write `wf' `"`macval(line1)'"' _n } end /* Clean log produced by Stata's -log using- and -log close- commands. */ program define CleanLog args rf wf CleanLogUsingHeader `rf' file read `rf' line local break 0 while r(eof)==0 { /* stop when we encounter the -log close- command. */ if substr(`"`line'"',-11,.) == ". log close" { local break 1 continue, break } file write `wf' `"`macval(line)'"' _n file read `rf' line } end /* Clean log produced by Stata's -log using- command and -logclose-. */ program define CleanLogclose args rf wf CleanLogUsingHeader `rf' file read `rf' line local break 0 while r(eof)==0 { /* stop when we encounter the -log close- command. */ if substr(`"`line'"',-10,.) == ". logclose" { local break 1 continue, break } file write `wf' `"`macval(line)'"' _n file read `rf' line } end /* Skip first 5 lines comprising the header output from -log using-. */ program define CleanLogUsingHeader args rf /* hline */ file read `rf' line if `"`line'"' == "{smcl}" { file read `rf' line file read `rf' line } else if index(`"`line'"', "-----") { file read `rf' line } if ! index(`"`line'"', "log:") { file seek `rf' tof exit } file read `rf' line if ! index(`"`line'"', "log type:") { file seek `rf' tof exit } file read `rf' line if ! index(`"`line'"', "opened on:") { file seek `rf' tof exit } /* blank line */ file read `rf' line end /* type: subroutines ********************************************************/ program define LogType, rclass syntax anything(name=file id="filename") [, /* */ replace /* */ find /* */ path(passthru) /* */ LOGfile /* */ SMCLfile /* */ ] LogSetup if "`logfile'" == "" { local logfile nologfile } StripQuotes file , string(`file') if `"`find'"' != "" { capture which findfile if _rc { di as err "option find requires Stata 8 or later" exit 111 } quietly findfile `"`file'"', `path' local file `r(fn)' } LogBaseName `file' local file `"`r(fn)'"' local dbase `"`r(dir)'`r(base)'"' local ext `"`r(ext)'"' if ! inlist(`"`ext'"',".smcl",".hlp") { local dbase `"`dbase'`ext'"' } capture noisily { tempfile tt LogOpen `tt' type `"`file'"' LogClose, noclean `logfile' copy `"`tt'.log.tex"' `"`dbase'.log.tex"', `replace' return local fn_tex `"`dbase'.log.tex"' if "`logfile'" == "logfile" { copy `"`tt'.log"' `"`dbase'.log"', `replace' return local fn_log `"`dbase'.log"' } } local rc = _rc if "`smclfile'" != "" { copy `"`tt'.smcl"' `"`dbase'.smcl"', `replace' return local fn_smcl `"`dbase'.smcl"' } capture erase `"`tt'.smcl"' capture erase `"`tt'.log.tex"' exit `rc' end exit