• No results found

libast : The ast Base

In document prus-1995 (Page 63-68)

Glenn Fowler, David Korn, Stephen North, Herman Rao, and Kiem-Phong Vo

2.2 The ast Libraries

2.2.2 libast : The ast Base

libast is the base library for the ast tools. It provides a common header and function interface for many UNIX systems and C compilers. Imple- mentation specic details are conned to libast, with the eect that most ast tools are programmed without architecture-specic #ifdefs. While

encouraging clean tool design, libast also provides a convenient frame- work for portability. Many interface issues are addressed and these are categorized below.

2.2.2.1 Header Interface

Determining the set of #include headers to use for a given system is

one of the hardest portability challenges. Missing headers can be han- dled with simple feature testing (see Section 3.2). More dicult are sys- tem headers that omit information or dene constructs that conict with other headers. This is especially true with the introduction of function

Libraries and File System Architecture 37

prototypes in ANSI C and C++ compiler headers. Traveling along the

migration path between K&R and ANSI C adds more complications. The header ast std.h provides a union of the following ANSI and

POSIX headers:

stdarg.h, stddef.h, stdlib.h, string.h, locale.h, limits.h, sys/types.h, unistd.h, fcntl.h

ast std.his self-consistent across UNIX system and compiler variants.

Consistency is attained by supplying omitted headers, providing defaults for omitted denitions, and xing up botched constructs in existing local headers. For example, the type size t is typically dened in stddef.h

for ANSI C and sys/types.h for UNIX systems. In the latter case, it

is sometimes not dened. As size t is a symbol dened by the ANSI

C standard, the header ast std.h guarantees that this type is always

dened.

ast std.h includes local headers whenever possible (thus, it may de-

ne nonstandard symbols). Others are generated as necessary for the compiler that installs libast using ie probes (Section 3.2). Theast std.h

header can be safely used with the C compiler used to generate it. It can also be used with other C compilers if the libpp C preprocessor (the de- fault preprocessor for nmake users) is used.

2.2.2.2 Missing Functions

libast provides implementations for common system calls not supported by the local system. Some calls, likerename(), are emulated usinglink()

andunlink(). Others, likesymlink(), cannot be emulated, so the library

provides a stub that always fails witherrnoset toENOSYS. Nonfunctional

stubs allow applications to be written against a single system call model.

2.2.2.3 Replacement Functions

Many of the functions in libc have changed little since their introduc- tion in the late 1970s. Since then, better algorithms and optimizations may have been discovered. libast provides interface-compatible replace- ments for the best of these. getcwd() takes advantage of the PWD envi-

38 Fowler, Korn, and Vo

ing the value of PWD with \.", the more complex search algorithm can

be almost always avoided. Another example illustrating the dark side of standard headers and function prototypes is getgroups(). The POSIX

function prototype is int getgroups(int size, gid t* groups), but

the library implementation on most current systems follows the tradi- tional BSD int getgroups(int size, int* groups). This is unten-

able on systems where sizeof(gid t)!=sizeof(int) (most implemen-

tations dene gid t as short). libast solves this by providing a macro

getgroups that calls ast getgroups() with the proper gid t* proto-

type. ast getgroups() then handles the gid t*/int* inconsistency.

2.2.2.4 New Functions

libast is also a common repository for new functions that are shared among the ast tools. Application specic functions, like the coshell in- terface described below, generally warrant their own library. There are over 200 public functions in libast. All are used by at least two of the ast tools. Some, like so, are used by all of the ast tools. There are too many functions to list, but one particular class should give a avor of library. Thestr*routines convertchar* strings to other C types.struid() con-

verts a string to a uid t, and strperm() converts a chmod le mode

expression to a mode t. For each of these there is an inverse conversion

routine.fmtuid()converts auid tinto achar*, andfmtperm()converts

a mode tto a chmod expression string.

2.2.3

libcmd: Enhanced UNIX Commands

To enhance eciency and to test the libraries, we have rewritten many common commands in the IEEE POSIX 1003.2 Standard for shell and utilities. Each command is implemented as a self-contained library func- tion whose name is b name, where name is the name of the command.

For example,b cat() is the function corresponding to the command cat.

Then, an actual command is just a simple main() that passes on its

arguments to the respective function. For convenience, these functions are grouped together in the libcmd library. An advantage of libcmd is that such functions can be directly built into applications to avoid the

Libraries and File System Architecture 39

fork/execoverhead of running commands. Recent versions of ksh support dynamic linking of built-ins. By building libcmd as a shared library, any or all of these commands can be made built-ins to the shell as desired. Since the built-in version uses the same code as the command version, they are always compatible.

libcmd contains many of the simple commands that take more time to invoke than to run, such as basename, dirname, logname, mkdir,

pathchk, andtty. It also contains commands that descend the le hierar-

chy, such as chmod,chgrp, and chown. Finally, to enhance I/O eciency,

libcmd contains commands, such ascut,join,paste,wc, and other util-

ities.

2.2.4

screen: Character Screen Management

The screen library is a collection of functions to manipulate character terminals. It can be used as a replacement for the curses library [Arn84, Hor82] (because of this, screen does not follow the standard ast naming conventions.) The original curses library was distributed with the BSD4.1 UNIX system. This version suered from many serious bugs (such as memory violations), rendering it virtually unusable.

The library was based on the termcap terminal description language and database used in the vi editor [Joy80], but it did not make full use of terminal capabilities, such as hardware scrolling and line/character in- sert/delete. A later version released with the System V Release 2 UNIX system xed many of these problems. This version of curses was based on the terminfo language and database for terminal description. In terms of functionality, this version was relatively complete, but it suered from performance both in terms of space requirement and time. There were a few idiosyncrasies in the interface, such as the distinction between win- dows that t a screen and windows that extended beyond screen bound- aries (these were called pads).

When the Easel system (Chapter 4) was developed in 1982, neither of the existing curses versions was adequate. This was not just a matter of performance or portability but also because many key features were lack- ing. The screen library was built to deal with such problems. An early version of the library was used as a base for more modern versions of

40 Fowler, Korn, and Vo

curses starting from UNIX System V Release 3.2. Beyond curses func- tionality, below are the key contributions of screen.

2.2.4.1 Logical Window Hierarchy Model

The library handles windows and derived windows consistently so that any change in the image of a window in the hierarchy is accurately re- ected in the others. New functions, such aswsyncup()andwsyncdown(),

allow applications exible and ecient manipulations of window images and screen updates.

2.2.4.2 Ecient Screen Update Algorithm

The library implements an ecient screen update algorithm that uses all dened terminal capabilities, including scrolling and character/line insert/delete. The algorithm also correctly deals with variations in video attribute handling, including various types of magic cookies [Hor82]. The line update part of the algorithm is based on the Minimum Distance Longest Common Subsequence algorithm [JV92], which minimizes visual disturbance due to line jumpings.

2.2.4.3 Internationalization

The library can deal with a wide range of character code sets, includ- ing ASCII, 8-bit European code sets, and other multibyte character sets commonly used in the Orient. There are many dierent code sets for multibyte characters dened by dierent vendors. The screen library is still the only implementation of curses that can deal with most existing code sets.

2.2.4.4 Terminal Handling

In contrast to other curses implementations that can use only one of the termcap and terminfo databases, the screen library can use either database or even both in the same process if necessary. On modern work- stations with pointer devices, such as the mouse, the library supports their use for interactive screen manipulations.

Libraries and File System Architecture 41

2.2.4.5 New Functions

The library adds many new functions to perform higher-level data ma- nipulations. Examples are wmenu()to interact with matrices of menu op-

tions, wview() and wunview() to create textual descriptions of window

images, and wedit(), which denes a virtual screen editor.

Below is an example of editing a string in a small window. The example is prototypical of how a form package would create form elds using screen. Lines 2 to 17 dene the keyboard interface for editing. Here, arrow keys are used for cursor motion, the control-D character ends editing, and any other alphabetic keyboard input is inserted in front the cursor. The full set of editor commands supplied by wedit() is rich enough to

simulate all screen interactions of editors, such as vi or emacs. Lines 18 to 20 create a window with 1 line and 10 columns, turn it to inverse video, and enable function key interactions. Line 18 invokes the editor with the string "abcd" as the initial text. wedit() returns the edited string.

1: #include <curses.h>

2: static kbf(WINDOW* win, EDIT_ARG* arg) 3: { int ch; 4: while(1) 5: { switch((ch = wgetch(win)) ) 6: { default : if(isalpha(ch)) 7: return ch; 8: else continue;

9: case KEY_LEFT : return EDIT_LEFT; 10: case KEY_RIGHT: return EDIT_RIGHT; 11: case KEY_DOWN : return EDIT_DOWN; 12: case KEY_UP : return EDIT_UP;

13: case ERR :

14: case CTRL(D) : return EDIT_DONE;

15: } 16: } 17: } ... 18: win = newwin(1,10,10,10); 19: wbkgd(win,A_REVERSE); 20: keypad(win,TRUE); 21: str = wedit(win,0,kbf,"abcd",0,0,0,0,0,0,0);

In document prus-1995 (Page 63-68)