Terminal Handler

Download from http://www.nyangau.org/th/th.zip.

This a peice of public domain code designed to handle simple character oriented screen access.

You can consider it like curses, only without the swearing.

It has been implemented for DOS, DOS32 (32 bit DOS with CauseWay DOS Extender), 16 bit OS/2, 32 bit OS/2, Win32, various UNIXes (including Linux, AIX, HP-UX, Solaris, MacOSX and iPhone 1.x), Novell NetWare, EFI, and the Amiga.

It has been used by Andys Source Code Folding Editor, Andys Binary Folding Editor, and various other test tools.

Initialisation

Prior to using this code, be sure to call th_init. This specifies the desired screen mode and size. It returns 0 if it failed, or a non-0 value if it worked.

Afterwards, the x_size and y_size variables reflect the screen size.

th_deinit should be called to terminate use of this module. In fact this call can be made even if no preceeding initialise call has been done.

The screen mode MODE_NORMAL is defined on all platforms. This should be used, unless you have a very specific requirement.

On DOS, DOS32, OS/2 and Win32, TH attempts to save the existing screen mode and contents, so that it can restore them afterwards. On UNIXes, and the Amiga, this isn't possible. On NetWare this isn't worth doing as NetWare NLMs tend to be loaded into their own screen anyway. On EFI, there is no mechanism for this.

Screen size

When initialising, the screen size desired is specified. Zeroes may be supplied, meaning whatever the current size is.

If you are requesting a screen size that cannot be supported, then th_init will return 0 and fail.

On DOS and DOS32, a wide variety of screen sizes are supported, by recognising CGA, EGA, VGA and SVGA adapters of various types. There is a document which explains exactly what is supported.

On OS/2, TH is implemented in terms of the VioXxxx and KbdXxxx APIs, and so any size you can set with the MODE command, TH can also support. This includes 40 column, 132 column, 60 line etc..

On Win32, TH also supports assorted screen sizes. This can show up problems in Windows 95.

On EFI, a variety of screen modes are supported.

On the Amiga and UNIXes, TH will only run in the current screen size. It will fail any initialisation attempt with a different screen size.

It is very common for programs to simply initialise using the current screen size, and then check to see if the current size is acceptable. They can then fail if the screen is too small or too big. Some programs also give the user the option of invoking them with a desired screen size.

Cursor shape

The th_setcsr function can be used to set the cursor shape to one of CSR_BLOCK, CSR_ULINE, CSR_ALT (typically half height), and CSR_OFF (ie: invisible). This call is fully supported under DOS, DOS32, OS/2, and Win32. Under UNIX, CSR_OFF positions the cursor at the bottom right of the screen, and any of the others leave the cursor where it should be. Under UNIX and EFI we have no control over the shape of the cursor.

Colours

th_setcol may be used to set the text colour for subsequent text output.

How colours are constructed varies from platform to platform :-

#define ERROR_COLOUR COL(COL_YELLOW,COL_RED,TRUE,FALSE)
  /* Produces yellow on red, bright yellow, and not flashing.
     Works for DOS, DOS32, OS/2 and NetWare. */

#define ERROR_COLOUR COL(COL_YELLOW,COL_RED,TRUE,FALSE)
  /* Produces yellow on red, bright yellow, not bright red.
     Works on Win32.
     There are no flashing colours in the Windows Console API. */

#define ERROR_COLOUR COL(COL_YELLOW,COL_RED,COL_STAND)
  /* Under UNIX says, use yellow on red if the version of curses
     and the current terminal type supports it.
     Failing that, revert to using standout mode. */

#define ERROR_COLOUR COL(COL_YELLOW,COL_RED,TRUE)
  /* Produces yellow on red, bright yellow.
     Works for EFI. */

#define ERROR_COLOUR COL_3
  /* Selects colour 3.
     Works on Amiga running under Intuition.
     The Amiga simply provides 4 arbitrary colours. */

th.h defines COL_RED etc. on any platform that supports colour.

It defines COL_NORM, COL_STAND, COL_ULINE and COL_ALT on UNIX systems. These mean normal, standout, underlined and alternate-character-set. On many systems, underline and alternate-character-set do not work.

Keyboard

On all systems K_CTRL is defined, and provides a common way of describing the control keys. Typically K_BS, K_TAB. K_CR, K_LF and K_ESC are also defined.

On all platforms, K_LEFT, K_RIGHT, K_UP, K_DOWN and K_HOME are defined. K_Fn are defined for the function keys.

On DOS, DOS32, OS/2, Win32 and UNIX, K_SHIFT_Fn, K_CTRL_Fn, K_ALT_Fn, K_ALT_n, K_ALT_c are supported. Also K_PGUP, K_PGDN, K_INSERT, K_DELETE and K_END are supported, along with some K_CTRL_ and K_ALT_ variants of them.

Keys can be read using th_key_read, which blocks until a key is pressed.

TH for UNIX maps Esc followed by a key into the Alt+key combination.

TH for EFI also maps Esc followed by a key into the Alt+Key combination, as there is no way to actually receive real Alt+Key keystrokes.

On DOS, DOS32, OS/2, Win32, NetWare and EFI, th_key_status is provided. This is also supported on Linux, AIX and HP/UX. This takes a peek at the keyboard buffer and returns 0 if no key is available. It returns a non-0 value otherwise, th_key_read can be used to retreive the value. Programmers should avoid polling the keyboard by repeatedly calling th_key_status, as this can swallow up large quantities of CPU.

th_key_break tests to see if 'break' has been pressed since the last call to th_key_break, and resets the flag ready for the next call. This is Ctrl+Break on DOS, DOS32, OS/2 and Win32. On UNIX and NetWare, it is caused by a signal. EFI does not support this call. If not supported, this function will always return 0, which means no. A non-0 value is returned if a 'break' has occurred. An application might periodically call th_key_break during some long interruptable processing.

Output

General text output is acheived using the following routines :-

void th_beep(void);
void th_cls(void);
void th_cxy(int x, int y);
void th_cy(int y);
void th_chome(void);
void th_inslin(void);
void th_dellin(void);
void th_deleol(void);
void th_isprint(int c);
void th_p_raw_chr(int c);
void th_p_raw_str(const char *s);
void th_p_chr(int c);
void th_p_str(const char *s);
void th_sync_screen(void);

th_inslin and th_dellin insert and delete a line at the current cursor position.

The raw print functions are fastest and don't understand things like carriage return and line feed.

th_isprint is fed a character value, in the range 0 to 255, and it returns non-0 if the character is 'printable'. Only standard ASCII printable characters (codes 32 to 126) are guaranteed to be 'printable'. With other characters, you take operating system specific pot luck.

Printable characters may be output using the raw print routines.

Printable characters and also '\n', '\r', '\t' and '\b' may be output using the non-raw print routines. '\n' moves to a new line, '\r' moves to the start of the current line, '\t' outputs spaces until the next 8 character tab stop is reached and '\b' backspaces. None of these special characters cause their glyph to be displayed - to do that they must be printable, and you must the raw print routines.

The th_sync_screen entrypoint ensures the screen data recently written is flushed and is therefore visible on the screen. This call is rarely necessary, as a call to th_key_read or th_key_status implicitly causes this to happen also.

On UNIXes it is often the case that the bottom right hand character cannot be written to (because this would cause an unwanted screen scroll).

On EFI, the bottom right hand character cannot be written to.

Saving and restoring

When writing simple windowing layers using TH, it becomes necessary to save an area of the screen for later restore. Under DOS, DOS32, OS/2, Win32, NetWare and EFI, support for this has been implemented.

Support for saving and restoring is currently only present in the AIX Extended Curses variant of UNIX.

If the symbol TH_SAVE_RESTORE_CELL is defined, it states how many bytes are needed per character when saving a part of the screen.

th_save can be used to save some characters on display.

The format of data saved is platform specific, and may only be used to restored to an area of the screen of the same length.

th_restore is used to restore the screen.

Some imaginary, simplified, sample code :-

#ifdef TH_SAVE_RESTORE_CELL
  char *buf = malloc(21*TH_SAVE_RESTORE_CELL);
  th_save(5,4,21,buf);
  th_cxy(5,4); th_p_raw_str("This won't last long!");
  th_restore(5,4,21,buf);
  free(buf);
#else
  #error Can't support saving and restoring on this platform - yet
#endif

Implementation

The DOS versions set screen modes using BIOS Int-16h calls, and do direct screen memory access. Keyboard access is done via BIOS Int-10h calls. The 16 bit real mode DOS version supports VESA modes, but the 32 bit protected mode DOS32 version does not.

The OS/2 versions use the OS/2 VioXxxx and KbdXxxx APIs.

The Win32 version uses the Win32 Console API. It works around a number of bugs present only in the Windows 95 version of this API.

The NetWare version uses the windowing API provided by the NetWare conio.h header.

The EFI version uses the simple text input and output protocols, and they certainly live down to their name.

The Linux version uses ncurses.

The AIX version of TH can be compiled to use AIX Extended Curses which is is supported on AIX 4.x and AIX 5.x (32 bit compilation mode only). Or, it can be compiled using AIX Curses (which is now much in line with other UNIXes implementation of Curses) which is supported on AIX 4.3 and later, including AIX 5.x in both 32 bit and 64 bit modes.

The HP-UX version uses Color Curses.

Other UNIXes just use vanilla curses.

The iPhone or iPod Touch use MacOSX Mobile, which is a kind of stripped down MacOSX, which is derived from Darwin, which in turn comes from BSD. On this platform TERM is set to network. If you change this, you can cause programs to crash, or even the whole iPhone to hang so badly a power-off/on isneeded. This is thought to be because the iPhone doesn't deliver a terminfo database or library. The curses implementation appears to have a hard coded understanding of the network terminal type. As a consequence, despite the Terminal application running on the iPhone supporting ANSI color escape sequences, applications using TH (which uses curses) will not use color. This is also true when someone using a local terminal with color support uses ssh to enter an iPhone, and runs a program there.

Using

A program simply includes th.h, and links to the TH library.

Operating System C compiler flags TH Library name, link flags
DOS -DxxDOS LTHR.LIB
DOS32 -DDOS32 TH.LIB
16 bit OS/2 -DO16 LTHP.LIB
32 bit OS/2 -DOS2 TH.LIB
Win32 -DWIN32 TH.LIB
NetWare -DNW TH.LIB
EFI -DEFI th.o
Linux -DUNIX -DLINUX th.a, -lncurses
AIX Extended Curses-DUNIX -DAIX -DAIX_EXTENDED_CURSESth.a, -lcur -lcurses
AIX Curses -DUNIX -DAIX -DAIX_CURSES th.a, -lcurses
HP-UX -DUNIX -DHP th.a, -lcur_colr
Solaris -DUNIX -DSUN th.a, -lcurses -ltermcap
Xenix -DUNIX -DXNX th.a, -ltermcap

Note that the compiler flags are used both when compiling TH, and programs that use it.


This documentation was written by the Terminal Handler author, Andy Key
andy.z.key@googlemail.com