Wednesday, December 30, 2009

"Python Trick" % locals()

I just learned this python trick for string formatting. Here's an example:
def compileCommand(sourcePath, outputPath):
switches = "-O0 -g"
return "gcc -c %(switches)s %(sourcePath)s -o %(outputPath)" % locals()
This trick uses the dict locals() to supply the values for formatting the string with the '%' signs in it. The names inside the parens are resolved with the local variable names in the function.

Example usage of the above function:
cmd = compileCommand("hello.c", "hello.o")
assert cmd == "gcc -c -O0 -g hello.c -o hello.o"

Wednesday, December 23, 2009

Someone Doesn't Know How make Works

I tried to look up documentation on makefile macro modifiers, and the first result gave the syntax as this:
$(name,modifier[,modifier ...])
I don't know what kind of 'make' this author was using, but that syntax doesn't work at all in mine. I sought out the real make documentation, and the concept of a macro modifier doesn't even seem to exist. The closest we get is a Substitution Reference, which uses a colon, not a comma, and has limited functionality.

In the end, the $(subst from,to,text) function solved my original problem.

Friday, December 18, 2009

cygwin make Hates Windows

I installed 'make' from cygwin's package manager and it doesn't work with windows absolute paths. Here is my Makefile:
C:/TEMP/asdf.txt:
touch C:/TEMP/asdf.txt
(that's a tab)

Invoking 'make' from cygwin gives the following error:
Makefile:1: *** target pattern contains no `%'.  Stop.
The workaround is redoing the paths that 'make' cares about to use the '/cygdrive/c/' path:
/cygdrive/c/TEMP/asdf.txt:
touch C:/TEMP/asdf.txt
(that's a tab)

This works. 'touch' knows how to read windows absolute paths and 'make' doesn't.

Python's eval Function Hates Windows

(Python 2.4) I'm loading options from a file that's just a big python dict literal:
options = eval(open(argv[1]).read())
The eval function always worked when I gave it a literal string (like with """), but every time I gave it a string that was read out of a file, it would give me a syntax error on the first newline. The problem is that python's eval function can't stand '\r' characters. My line endings were windows-style, and the python interpreter didn't have a problem with them, just the eval function. Here's the solution:
options = eval(open(argv[1], "rU").read())
UPDATE: python admits this limitation for the exec function, telling you to use universal newline mode "U" when opening files for reading. However, there is no mention of this limitation in the documentation for the eval function.

Sunday, December 13, 2009

My Favorite Runtime.exec Wrapper

If you want to run another process in java (like a python script), the internet should lead you to Runtime.exec. This method doesn't block, so you might be tempted to call Process.waitFor to make sure it's done. However, sometimes this method will hang forever when the process writes to stderr or returns != 0. That seems like a bug to me, so the wrapper below works around that by catching exceptions from Process.exitValue instead of asking sun to do the waiting for us. Furthermore, the wrapper below reports stdout and stderr to you via StringBuffer arguments.
/**
* Executes a command and waits for the process to exit.
* The process is queried every 100 milliseconds for completion.
* stdoutBuffer and stderrBuffer can be the same object.
*
* @param cmd the command to be passed to {@link Runtime#exec(String[])}.
* @param stdoutBuffer buffer to which the process's stdout will be written. can be null.
* @param stderrBuffer buffer to which the process's stderr will be written. can be null.
* @return the exit value of the process
* @throws RuntimeException IOException and InterruptedException are wrapped in RuntimeException and thrown
*/
public static int exec(String[] cmd, StringBuffer stdoutBuffer, StringBuffer stderrBuffer)
{
if (stdoutBuffer == null)
stdoutBuffer = new StringBuffer();
if (stderrBuffer == null)
stderrBuffer = new StringBuffer();
try {
Process p = Runtime.getRuntime().exec(cmd);
InputStreamReader stdout = new InputStreamReader(p.getInputStream());
InputStreamReader stderr = new InputStreamReader(p.getErrorStream());
while (true) {
int exitValue = -1;
boolean done;
try {
exitValue = p.exitValue();
done = true;
} catch (IllegalThreadStateException e) {
done = false;
}
while (stdout.ready())
stdoutBuffer.append((char)stdout.read());
while (stderr.ready())
stderrBuffer.append((char)stderr.read());
if (done)
return exitValue;
Thread.sleep(100);
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

Wednesday, December 2, 2009

Keyboard Manufacturers Are All Slackers

Have you ever tried to press more than 3 buttons at once on your keyboard?
Modern keyboards ... [block] the 3rd key in certain key combinations, [which] means that when two keys are depressed simultaneously, many of the other keys on the keyboard will not respond until one of the two depressed keys is lifted. With better keyboards designs, this seldom happens in office programs, but it remains a problem in games even on expensive keyboards, due to wildly different and/or configurable key/command layouts in different games

-wikipedia
Am I missing something here? Why is it so hard to design a keyboard that actually does what it's supposed to do. It's 2009 and I can't play Metroid III on my snes emulator because I have to choose between charging my gun and jumping while pressing the run button.