Scripting the windows commandline with Spidermonkey made easy

I frequently have to automate really simple tasks, like moving files with a certain filename to another directory and the Spidermonkey shell that now comes with XULRunner (thank you for that Mozilla, building it yourself was time-consuming and annoying) has become an invaluable tool.

Few people know how easy it is to use any Mozilla-JS based program (yes, that includes XULRunner and Firefox) to work with commandline programs. As with any other programming environment you just need to be able to call the popen function of the OS, which runs any command and returns the output as a stream.

Mozilla-JS does not include POPEN. However it does support CTYPES, a system for calling libraries. On Windows POPEN and everything else you need is in MSVCRT.

Opening MSVCRT with CTYPES is easy:

var msvcrt = ctypes.open("msvcrt");

Now you just need to declare what functions you need (_popen, _pclose, feof and fgetc in our case) and what types these require (first parameter is the name, second the interface type, third is the return type and everything else is the type of each argument):

var popen=msvcrt.declare("_popen",ctypes.winapi_abi,
    ctypes.void_t.ptr,ctypes.char.ptr,ctypes.char.ptr);
var pclose=msvcrt.declare("_pclose",ctypes.winapi_abi,
    ctypes.int,ctypes.void_t.ptr);
var feof=msvcrt.declare("feof",ctypes.winapi_abi,
    ctypes.int,ctypes.void_t.ptr);
var fgetc=msvcrt.declare("fgetc",ctypes.winapi_abi,
    ctypes.jschar,ctypes.void_t.ptr);

With this you can very easily build something like C’s SYSTEM call, just with the difference that it will return everything the program outputs through STDOUT:

function system(cmd,raw){
/* Open the program (Windows automatically
   uses cmd.exe for that), use raw mode
   if requested. */
    var file=popen(cmd,"r"+(raw?"b":""));

    var o=""; // STDOUT content
    var end=false; // End of STDOUT reached

/* Loop trying to get a character from STDOUT
   until feof informs us that the end of the
   stream has been reached */
    do{
        var c=fgetc(file);
        if(!(end=feof(file))) 
             o+=c; //Append current char
    }while(!end);

    pclose(file); // Close pipe
    return o; // Return 
}

And that’s really all you need (in this case to call DIR, split by newline and output the first result):

var dirs=system('DIR /B /S');
dirs=dirs.split("\n");

if(dirs.length)
	print(dirs[0].trim());

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.