windowsmonitor: display macval() cannot handle single quotes
On windowsmonitor.ado there are several lines with this form:
dis as result `"`macval(line)'"'
This will fail if line has single quotes or other characters that conflict with the Stata quotes. For instance, this happened when using statacpp:
. loc line '"myprog.exe"' is not recognized as an internal or external command,
. dis as result `"`macval(line)'"'
'"myprog.exeis not found
r(111);
This occurs because you have to double quote myprog.exe (to handle spaces in folder names), and then cmd.exe quotes that with single quotes so you end up with ...myprog.exe"'
A simple fix would be to replace the macval() line with:
mata: printf("{res}" + st_local("line"))
Because it's done with Mata, it should prevent this problem altogether.
Great, that could solve problems in stan.ado too. I know nothing of Mata, having c++ instead and not enough brain space to double up. Do want to clone this or just email the .ado to me and I'll credit you?
I find Mata seems to allow finer control over file I/O. I'd like to chip in on this, sharing a Mata version of windowsmonitor.do that I worked on before. It would avoid the single quotes problem, and unlike windowsmonitor.do no -sleep- is invoked and so it doesn't pause.
The temporary file is created before winexec, remove the first -sleep- in windowsmonitor.do. Putting the fopen() and fclose() within the while-loop and opening the file for read-only removes the second -sleep-.
program define win_stream
mata win_stream(`"`0'"')
end
mata:
void win_stream(string scalar cmd) {
tf = st_tempfilename()
stata(sprintf("shell echo --begin-- > %s", tf))
tf_bat = st_tempfilename() + ".bat"
fh_cmd = fopen(tf_bat, "rw")
fput(fh_cmd, sprintf("%s\necho --end--", cmd))
fclose(fh_cmd)
stata(sprintf("winexec %s >> %s 2>&1", tf_bat, tf))
pos = 0
thisl = ""
while (thisl != "--end--") {
fh = fopen(tf, "r") // "r": read-only
fseek(fh, pos, -1) // go to position pos with respect to -1,
thisl = fget(fh); thisl // i.e. beginning of the file
pos = ftell(fh) // store the new position
fclose(fh)
}
}
end
An example of usage: win_stream echo "test "this"".
Another: win_stream dir "C:\Program Files (x86)".
What do you guys think?
Sounds good. I can't judge the mata itself but I'll try it out when I get back to Windowsland on Monday. I'd be interested to understand the quotes-within-macro problem because that reappears in stan.
Also +1 but I think adding a bit of a wait is better, as it otherwise would be constantly seeking and using a lot of resources (CPU and disk) that would otherwise be used to complete the call to stan or whatever program is running on the background.
I also found a nice way to write the external code (stan or c++) that will add in an issue separately, in case you find it useful
@robertgrant Cool, thanks.
@sergiocorreia Then maybe read twice every second, i.e. sleep 500ms? Does that sound about right?
If yes, then perhaps could add a stata("sleep 500") after fclose(fh).
May I ask how would you write the external code?
@felixleungsc I made the post on the external code here.
About the sleep, you can even be more aggressive and poll every 100ms or so, as long as you are adding some delay it should be fine.