*! version 1.1.13 06may2003 program define sjlog_7 version 7 local vv : di "version " _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" { `vv' LogDo `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 7.0 local vv : display "version " _caller() ":" 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 { initMacros 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' } } local rc = _rc /* close files */ file close `wf' file close `rf' removeMacros `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 program define initMacros global SJL_maxn 10 global SJL_n 0 global SJL_parity 0 end program define removeMacros args rc if "$SJL_parity" != "0" & "$SJL_parity" != "" { di as err "$SJL_parity nonempty global macros" forval i = 1/$SJL_maxn { if `"${SJL_`i'}"' != "" { di _asis as txt /* */ `"SJL_`i' is |${SJL_`i'}{reset}{text}|"' } global SJL_`i' } if ! `rc' { local rc 459 } } global SJL_parity global SJL_maxn global SJL_n exit `rc' end program define removeLine args line global `line' /* decrease number of lines read */ global SJL_parity = $SJL_parity - 1 end program define FileRead args hh c_line /* read in line */ file read `hh' rline /* increase number of lines read */ local n = mod($SJL_n,$SJL_maxn) + 1 /* increase parity index */ global SJL_parity = $SJL_parity + 1 /* escape quotes */ local qline : /* */ subinstr local rline "\`" "\\\`" , all count(local qc) /* escape dollars */ global SJL_`n' : /* */ subinstr local qline "\$" "\\\$" , all count(local dc) /* return name of global macro containing new line */ c_local `c_line' SJL_`n' /* save number of lines read */ global SJL_n `n' end program define FileWrite args hh line /* write contents of global to file */ file write `hh' `"${`line'}"' _n removeLine `line' 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 */ FileRead `rf' line1 if `"${`line1'}"' == "{smcl}" { /* skip next line too, it is part of the smcl header */ removeLine `line1' FileRead `rf' line1 removeLine `line1' } else { FileWrite `wf' `line1' } FileRead `rf' line1 FileRead `rf' line2 local break 0 while r(eof)==0 { if substr(`"${`line2'}"',-14,.) == "end of do-file" { local break 1 continue, break } FileWrite `wf' `line1' local line1 `line2' FileRead `rf' line2 } if ! `break' { FileWrite `wf' `line1' removeLine `line2' } else { removeLine `line1' removeLine `line2' } end /* Clean log produced by -sjlog using- and -sjlog close-. */ program define CleanSJLog args rf wf CleanLogUsingHeader `rf' /* skip the smcl header lines */ FileRead `rf' line1 if `"${`line1'}"' == "{smcl}" { /* skip next line too, it is part of the smcl header */ removeLine `line1' FileRead `rf' line1 removeLine `line1' } else { FileWrite `wf' `line1' } FileRead `rf' line1 FileRead `rf' line2 local break 0 while r(eof)==0 { if index(`"${`line2'}"',". sjlog close") { local break 1 continue, break } FileWrite `wf' `line1' local line1 `line2' FileRead `rf' line2 } if ! `break' { FileWrite `wf' `line1' removeLine `line2' } else { removeLine `line1' removeLine `line2' } end /* Clean log produced by Stata's -log using- and -log close- commands. */ program define CleanLog args rf wf CleanLogUsingHeader `rf' FileRead `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 } FileWrite `wf' `line' FileRead `rf' line } if `break' { removeLine `line' } end /* Clean log produced by Stata's -log using- command and -logclose-. */ program define CleanLogclose args rf wf CleanLogUsingHeader `rf' FileRead `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 } FileWrite `wf' `line' FileRead `rf' line } if `break' { removeLine `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 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 syntax anything(name=file id="filename") [, /* */ replace /* */ find /* */ path(passthru) /* */ logfile /* */ ] 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' if "`logfile'" == "logfile" { copy `"`tt'.log"' `"`dbase'.log"', `replace' } } local rc = _rc capture erase `"`tt'.smcl"' capture erase `"`tt'.log.tex"' exit `rc' end exit