Porting ABC to new systems

Most of the ABC implementation consists of machine and operating-system independent code. Most of the ABC system is written to be maximally portable, and it even configures itself to the word-length, and similar, via mkmach.c

For the greater part we use routines that are found in most C libraries, and have tried to make the amount of rewriting necessary as small as possible (though it could probably be made smaller).

The non-portable parts, which must be adapted for each port are concentrated in one directory for each port. The directory 'generic' is a skeleton version of the routines that have to be written if you port ABC to another machine.

When porting, as a matter of style, please try to keep to the same programming style as used in the rest of the system, for instance marking functions with Visible or Hidden. We particularly try to avoid constructs of the form #ifdef <machine type>: we prefer either to find a solution valid for all machines, or an #ifdef based on the property that is different, rather than machine. Similarly, machine dependencies must be restricted to the one portability directory for the port. All other directories are identical for the other implementations, and we would be reluctant to lose that property.

Contact us in difficult cases.

*************************************************************************

Please be sure that you send us the files you create and change so that we can merge them back into our originals, and make them available to others. Let us know your experiences with porting, and above all don't be afraid to contact us for help (email address abc@cwi.nl).

*************************************************************************

Files

The following are the files in the generic directory, the visible functions, types and constants that have to be defined, and their purpose.

comp.h

C compiler dependencies.

dir.c

Reading directories

opendir, readdir, closedir

This file defines 3 functions for reading directories. There are public-domain versions available for many machines already. If you can't find one for your machine, then you'll have to write one, but that isn't too hard a task. It's even easier for ABC, since we guarantee never to open more than one directory at a time. See bio/i4fil.c for the sole use of readdir.

dir.h

This header file belongs with dir.c, so you have a lot of freedom. However, it must define:

edit.c

Users can choose to use a different editor than the standard ABC editor for editing how-tos. You still get the ABC editor for immediate commands. This file determines how such foreign editors are invoked.

See file main.c for how to communicate to the rest of the system that a different editor is to be used, and which one it should be.

feat.h

Features of the ABC system.

A few of these are there for historical reasons, and you don't need to worry about them. The ones that you may need to change are:

The following are the historical features and don't need to be changed.

file.c

There are a number of standard directories and files that ABC needs. This file locates them. For some of them you may have to search in a number of places (for instance, on MS-DOS we search for the messfile in the current directory, then in \ABC, then in all directories in $PATH, and then in the root directory).

The things that get searched for are:

keys.c

This file is used both by abc proper, and the program abckeys which allows the user to change the bindings of keys to operations.

The parts enclosed in #ifdef KEYS is only for abckeys.

mach.h

This file contains the machine constants and is the output from the program mkmach. Compile and run mkmach.c, check the (self-explanatory) output, and put it in this file.

Amongst the numbers produced is the maximum double. A buggy compiler might not be able to cope with this, and you may have to fiddle with the value (for instance, dropping the last digit of the fraction) until the compiler doesn't complain.

main.c

This file is for starting up ABC: for reading arguments passed to the program, and acting on them, and calling different parts of the system accordingly. Try to keep your choice of arguments compatible with other ABC implementations.

According to the arguments, you may set any of the following global variables, which change the system's defaults:

main.h

In this file you can put your external definitions of functions, which are only used in this directory.

os.c

This file is the place to put things which the ABC system expects to be in the C library, aren't there, and need to be put somewhere. The following is a list of the library functions used by the Unix implementation, so you have an idea of what to expect. Some of these are optional (like signal). The ones enclosed in brackets are only used in some ports.

os.h

Operating system features; header file to go with os.c. Much of what is here is only used by os.c or other files in the portability directory. Only the externally visible things are marked with arrows.

The following is only used by abckeys:

sig.c

This file is for signal handling. Different machines differ widely here, and the consequences are subtle.

Normally, abc is used interactively, and interrupt signals are switched off (see trm.c). However, when abc is run non-interactively, the system must catch interrupt signals that come in. (Actually, even when running interactively, there is a possibility of getting interrupt signals on some systems).

If your system can generate interrupt signals, you have to write a signal handler to catch them. The handler must set the flag 'intrptd' to Yes, and return (on some systems the signal handler must be reinstated too). ABC periodically polls the flag to see if an interrupt has occurred.

trm.c

This file defines a machine-independent interface to a 'virtual' terminal for input and output. A current restriction that will only be solved in later versions is that window resize is not handled. It is only used for writing to the screen (and is not used for instance in non-interactive calls of ABC). Therefore, you should ensure that output is sent to the screen and not just to stdout regardless, which may have been redirected. For instance, on Unix you could write to /dev/tty, on a PC you could use direct calls to write to the screen.

The module consists of an upper level that you hopefully won't have to change, and a machine-dependent lower level where all functions begin with low_ . These are the routines you need to implement.

The version in this directory is a simple version to get you going, based on a VT100 terminal. If your terminal is a fast one, then it will probably be sufficient, but if you will be working over slow lines, you may have to consider doing some optimisations. See the Unix version that does this.

If your machine only has one sort of 'terminal' (such as an MS-DOS machine), then your work is simplified, but do not make any assumptions about the number of lines and columns: someone eventually will have a different-sized screen, and then won't be able to use ABC. Try if possible to determine the size of the screen automatically: the ABC philosophy is to do it right, and not bother the user with having to explicitely give this sort of details. (See low_get_screen_env() in this file for one way to do it.)

If your machine has several different interfaces, then there may be a termcap implementation for your machine, in which case you can just use the Unix version of vterm, which uses termcap.

Dealing with mouse clicks

Mouse-click style cursor moves are done by the [mouse] operation in the editor, which must be bound to some character sequence. Therefore a mouse-click must be converted to some suitable character or character-sequence that can be bound to [mouse].

If ABC gets a [mouse] operation, it then calls trmsense (see below) to find out where the click occurred, passing to it the strings contained in the bindings for [mouse-sense] and [mouse-format]. This is to allow two possible modes of operations: 1) that a mouse click sends a sequence of characters that includes the position information, and 2) that a mouse click sends a fixed sequence, and the terminal then has to be asked where the click occurred.

For 1) [mouse] must be bound to the initial sequence that the mouse click sends, [mouse-sense] should be empty, and [mouse-format] should describe the rest of the sequence.

For 2) [mouse] should be set to the fixed sequence the mouse click sends, [mouse-sense] to the string that should be sent to the terminal to ask for the click position, and [mouse-format] to the format that describes the reply.

If your mouse doesn't send character sequences, but must be handled in some other way, you should convert the clicks into a character sequence, by polling in trminput and trmavail

Mouse click formats

A format that describes the mouse click sequences, has the following possibilities (based on the cursor-setting format of termcap):

All characters in the string must literally match the corresponding character in the reply, except a % followed by other characters, which have the following meaning:

The following two do not match anything in the input, but affect the way numbers are interpreted:

Examples:

An xterm window sends a mouse click as "ESC [ M c x y" where c is a single character <space>, ! or ", depending on which button is pressed, and x and y are single graphic characters starting at "!". So, [mouse] can be bound to "ESC [ M" and the format would be "%.%r%+!%+!". Another possibility is to bind [mouse] to "ESC [ M <space>", "ESC [ M !", and "ESC [ M <">", and set the format to "%r%+!%+!". (To get xterm to send mouse clicks, you have to initially send the string "ESC [ ? 9 h" which you should put in your [term-init] binding.)

A uw window sends a mouse click as a mouse-down sequence and a mouse-up sequence, of the style "ESC m y x 0 ESC m y x @", where x and y are single characters of the same style as xterm. So you can bind [mouse] to "ESC m", and the format to "%+!%+!0\033m%+!%+!@", or "%+!%+!%." (in the second case, [mouse] gets called twice in quick succession).

By the way: for simple cases, the program abckeys is smart enough to work out the mouse format for itself.

Interrupt handling

Whenever the system is in a state where it's not looking at input (i.e. when it is computing), it periodically calls pollinterrupt() in bed/e1getc.c, which looks ahead in the input queue, via trmavail() and trminput(), to see if an [interrupt] has been typed. (If it has, it discards all input before that point and calls the interrupt handler, int_signal() in bint3/i3err.c. If no [interrupt] has been typed, no input is discarded.)

If you can't look ahead, and so can't implement trmavail(), you then have to enable keyboard interrupts in low_setraw(), write an interrupt handler which sets a flag, and test that flag in trmavail() and trminput() [see the code in trm.c guided by CATCHINTR].

If your system can't look ahead and doesn't generate signals, computations are uninterruptable. This is of course extremely undesirable, but presumably such systems don't exist.

The virtual terminal

For completeness, here is a description of what each routine does. In most cases, the high-level version first updates its internal administration, and then calls a low-level version.

The lines and columns of the virtual terminal are numbered

y = {0...lines-1} from top to bottom, and

x = {0...cols-1} from left to right,

respectively.

Visible Procedures

You may call these as one or more cycles of:

Trmend may be called even in the middle of trmstart; this is necessary to make it possible to write an interrupt handler that resets the tty state before exiting the program.

Character Input

Low-level routines

trm.h

This file belongs with trm.c. You shouldn't need to change anything in it.

usage.c

In this file are the messages that will be printed if there is something wrong when calling abc.

The error message strings don't get used in the program, only the number (see the definition of macro MESS in b.h).

The error messages themselves are collected by a program ('Collect' in directory 'scripts'), and stored in the abc.msg file, which is then used at run-time to print the error messages out. Each error message is given a number consisting of one or two digits for the file, and two digits for the message number within that file. The file abc.msg is then sorted numerically. The error numbers are assigned by the program Change (also in scripts), but you can always do it by hand. Error messages are stored this way, so that they can be translated without having to provide a different executable for a different language.