statastan icon indicating copy to clipboard operation
statastan copied to clipboard

windowsmonitor: display macval() cannot handle single quotes

Open sergiocorreia opened this issue 9 years ago • 6 comments

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.

sergiocorreia avatar Oct 06 '16 18:10 sergiocorreia

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?

robertgrant avatar Oct 07 '16 08:10 robertgrant

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?

ghost avatar Oct 07 '16 09:10 ghost

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.

robertgrant avatar Oct 07 '16 18:10 robertgrant

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

sergiocorreia avatar Oct 07 '16 18:10 sergiocorreia

@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?

ghost avatar Oct 09 '16 06:10 ghost

@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.

sergiocorreia avatar Oct 09 '16 08:10 sergiocorreia