Archive for the 'Programming' Category

Note: I've reorganized this site to use tags; the category archive remains to support old links. Only posts prior to April, 2006 are categorized. Tag Archive »

Senseless Acts of Perl

At work I spend alot of time working on one of our Solaris dev servers via xterm. Via many xterms simultaneously, most of the time. Since I run a local X client on my PC under cygwin, I have a shell script that I run locally that connects to the dev box and launches three xterms in pre-determined screen locations, setting DISPLAY along the way.

Over the course of a busy morning, this number can grow. Since I’m still on a Windows PC, however, I do tend to use my task bar to find windows. Having six or more taskbar buttons that all say “xterm” isn’t very helpful. For a while I tried setting my titles to reflect what I’m doing in each xterm, but this futile. Partially because I often create, destroy, or repurpose xterms on a whim; but largely because I’m lazy.

A while ago, I updated my launch script to label my initial three windows Alpha, Beta, and Gamma. While the names aren’t very descriptive, it does differentiate the windows, and I can usually remember what each window is being used for. When I start launching additional xterms, things can get confusing; I try to remember to add a -title and pick a Greek letter not in use, but I did mention I’m lazy, right? So today, I decided to do something about it.

The result is addterm, one of the more senseless perl scripts I’ve ever bothered with. When run, it creates a new xterm with the title set to the name of the first greek letter not currently in use. If all 24 greek letters are in use, and error message is printed and no xterm is launched. This is a feature, not a bug. Close some windows! The version below is my OS X port. :

#!/usr/bin/perl -w

my $user = `whoami`;
my @ps = split("\n", `ps -o command -U $user`);
my @alpha = qw/Alpha Beta Gamma Delta Epsilon
               Zeta Eta Theta Iota Kappa Lambda
               Mu Nu Xi Omicron Pi Rho Sigma
               Tau Upsilon Phi Chi Psi Omega/;
my $k=0;
my %greek = map {$_=>$k++} @alpha;

for(@ps) {
    my ($title) = /^xterm\s+-title\s+([^\s]+)/ or next;
    $alpha[$greek{$title}]=) {
        $next = $_;
        last;
    }
}

if (defined $next) {
    open STDERR, '>/dev/null'; #discard xterm's whining
    system("xterm -title $next & ");
} else {
    print STDERR "ERROR: No greek letters free!\n";
}

This required a port from the original Solaris version because the script uses ps to look for running xterms. The Solaris version uses ps -o args -u $user. The command should list (only) the full command + args for every process for the username $user. If you want to use this on another *nix, just test your ps command first and adjust accordingly. You could also change the Greek letters to another finite set, just remember to update the error message.

Of dubious interest is that fact that I used an array to keep the letters in order and a hash to allow quick indexing into the array. I dislike having to store the letters twice, but this seemed the best solution. I have a vague sense that some kind of tied vars may do this more elegantly, but my perl-fu isn’t quite that strong without cracking the Camel; did I mention I’m lazy? Perhaps tommorow. Improvements welcomed.

UrlGetPart, and the Parts it Won’t Get

This is a narrow post. If you don’t understand or don’t care, do skip it (you won’t be missing much). For the rest, and for the search engines, here’s some trivia.

There are a bunch of handy functions in the Win32 Shell API for handling file paths and URLs, provided by SHLWAPI.DLL. One of these, UrlGetPart, is described thusly:

Accepts a [sic] URL string and returns a specified part of that URL.

Very handy function, until you realize that the one part of an URL you can’t specify to be returned is the path. For example, in the (fictitious) url:

http://bond:007@example.com/topsecret/martini.cgi?method=shaken+not+stirredcode>http://bond:007@example.com/topsecret/martini.cgi?method=shaken+not+stirred</code

I can use UrlGetPart to retrieve the scheme (http:), the username (bond), the password (007), the host (example.com), and the query (?method=shaken+not+stirred), but I cannot retrieve the path (/topsecret/martini.cgi).

So, How do extract the path from an URL using UrlGetPart? You don’t. Instead, use InternetCrackUrl, in wininet.dll. If you need to do this from VB6 (and this may work with VB5, but I’ve not tried it), take a look at this helper class, which also supports a few other handy URL-handling functions.

I have now officially seen it all

Pac-man, written in Microsoft Excel. (via 0xDECAFBAD)

There are no words.

And Now For Something Completely Different…

Just becuase I don’t have enough diverse (and conflicting) interests, I’m currently learning Python. So far I like what I see. My only gripe is that the version of Python 2.3 Apple shipped with Panther does not support command line editing. In other words, in interactive Python, you can’t use up-arrow to access a command history (you have no history, except cut-and-paste, which means hands off the keyboard/on to the mouse), or use left-arrow to edit the current line (delete ’em and weep). I’m pretty sure that this can be compiled into Python, I don’t understand why Apple didn’t.

Also of note, I’m learning Python via Learning Python (go figure), which I’m reading via Safari Bookshelf. Although I really like dead tree editions, and generally prefer reading hardcopy to electronic copy, I have to admit that it’s working out pretty well. It’s especially a good choice for this book, for two reasons. The second edition is due out next month… no sense spending the money for a hardcopy of the current edition. Also, I’m working through many of the exercises in the book, so I’m at the keyboard anyway. I originally signed up for Bookshelf as a way to keep reference books at hand and audition books to buy, but so far reading a whole book online is working well.

Worst. Bugfix. Ever.

I hope that none of you ever, ever have to deal with Sybase ASE ODBC/ADO drivers. Nevertheless, I’m going to document a bug (and a fix/workaround) for using Sybase with Microsoft ADO, because I still can’t believe it.

I first used ADO against a Sybase server about 6 years ago, on a major website project. Over the years, I (and other members of my team) have found that every version of the ADO/ODBC drivers has various issues when used with MSADO. Each new release of ADO and/or Sybase Drivers seems to change subtle behaviors in ADO. We did identify a single version (11.004, I think) that work exactly as it should. Subsequent versions had bugs, so we stuck with what worked.

We recently deployed all new webserver hardware for that original website project. It’s an important website, it processes $12-$15 Billion (yes, that’s a B) in transactions monthly. Needless to say, I spent alot of time installing and testing. Now, the server admins put a new version of the Sybase drivers on ther servers. I was hesitant, but was told that this version worked correctly. And in my testing, it did.

Until we deployed. Seems there was one function I didn’t test, which used ADO‘s .UpdateBatch() against a Recordset opened with a client-side cursor. Shame on me for not testing it; nevertheless, the .UpdateBatch() was failing. Remembering similar issues from the bad-old days of driver shuffling, I tried switching to a server-side cursor. This fixed the problem. Unfortunately, it introduced another… the Sybase server side cursor doesn’t support Recordset filtering (and of course, the Client-side cursor library does).

So now, I was officially damned-if-I-do, damned-if-I-don’t. I immediately (well, right after some choice words) did what any good developer would do… I Googled. And lo, Google was good to me, for I found what I needed immediately. And I was shocked.

The post I found said that you could correct the ‘UpdateBatch failing on client-side cursors’ issue by adding the following line to your data source’s section of your ODBC.ini file:

WorkArounds2=24

Now, I don’t know if this affects the Sybase software or the Microsoft ADO software, but what we have here is a hack. An undocumented hack at that. Why this isn’t a configurable option on the ADO library or the OLEDB/ODBC driver is beyond me. But that’s not the worst part. The person who posted this nugget was in fact posting a solution to a problem they had themselves posted… and they found this answer in a newsgroup post from 1998. Why is this nasty hack still needed, five years later?

So, for the search engines, the above hack will fix and ADO failure cause when trying to run .UpdateBatch against a client-side (adUseClient) Recordset with Sybase ASE drivers. The error message is:

Run-time error '2147467259 (80004005)';
Data provider or other service returned an E-FAIL status.

You may also see a message that the error was raised by the Microsoft Cursor Engine. Also note, ODBC.ini now lives in the registry, at HKLM/Software/ODBC.ini.