Je me souviens
Everything here is my opinion. I do not speak for your employer.
February 2004
March 2004

2004-02-13 »

Curses Sucks, and there's No Excuse!

Okay, so I finally did it. As part of a project I was working on at work for the last few days, I decided to ignore curses entirely (for various reasons, most of them bad; leave me alone), and in the process, the library I wrote solved two problems:

  • regardless of your TERM setting, it displays correctly (and I mean perfectly, modulo the lack of colour in win9x telnet) in the Linux console, xterm, rxvt, putty, minicom, Win2k telnet.exe, and - yes, really! - in Win9x telnet.exe.

  • regardless of your TERM setting, in all of the above programs, my HOME, END, PGUP, PGDN, and INSERT keys work as they should (except for programs which happy refuse to send those codes at all - notably the Win2k/Win9x telnet programs).

How did I do it? I did what curses and ncurses never did. I followed the first and most important law of successful communication, attributed to Jon Postel: Be liberal in what you accept, and conservative in what you send.

My program sends only the most basic VT100 codes: gotoxy, change colours, change-to-wacko-line-drawing-font. We could be fancier, but then my output wouldn't work everywhere. Be conservative!

On the other hand, it accepts any of several possible codes for HOME, END, etc. Every stupid bloody terminal does it differently, and I don't care; I'll take them all. Nobody who says ESC[7~ doesn't mean HOME, even if not everybody who means HOME says ESC[7~. Be liberal!

Of course, I don't support non-basically-vt100-compatible terminals. Now first of all, I don't care, because (hello, join the 1980's!) there aren't any. Secondly, nothing stops curses from doing my basic-vt100 thing by default, and different things if you do set your TERM specifically. You're the weirdo, you go suffer. Unfortunately, curses stupidly tries to do something optimal by default. Well, this is to cut down on wasted output, you'll say. Remember 2400 baud users, you'll say. I want my email reader app to be legible in this crappy terminal emulator without spending three hours trying to guess which of the 5 million 'xterm-*' terminfo settings is the right one! ARGH!, I'll say. This isn't so hard. Be conservative by default, and if I'm a weirdo with a 2400 baud modem, I can set TERM to something more efficient. Easy. The "output conservativeness" problem is only a fault of the people who write terminfo databases, so technically we won't blame curses for that.

Unfortunately, for input, curses made a fatal mistake: the terminfo format itself has a one-to-one mapping between escape sequences and input codes. There cannot be more than one HOME. That means, basically, there is no way to "be liberal in what you accept". This is a fundamental design flaw in the terminfo file format, and AFAIK you can't fix it in a backwards-compatible way. But you can still fix ncurses. I'd be more than happy if someone would just finally do so.

There are two flaws, however, that I haven't solved: the ridiculous "ESC is a key and also an automatic sequence", bug, that means pressing ESC to cancel a dialog is essentially never going to work right. And there's the ridiculous "nobody knows what code backspace is" bug, that originally (ie. in a VT10x/VT220) was never a problem, but eventually someone (I think it was the X Consortium) mangled completely by sending ASCII 127 for the keypad DEL key. There's no saving people with that keyboard mapping (backspace->8, DEL->127), and unfortunately there are a lot of those people. But I can save everyone else, because CTRL-H is backspace (shut up, emacs users), 127 is backspace, and several things like ESC[3~ are DEL.

There. I'm glad I got that off my chest. (I think I followed pphaneuf's rules for flaming because I went and implemented something better before I flamed the crappy library we poor losers have been suffering with for decades.)

I'm CEO at Tailscale, where we make network problems disappear.

Why would you follow me on twitter? Use RSS.

apenwarr on