Portable Windowed Applications:
Pollsters, Onlookers, and Others

Leonard J. Harding

Copyright © 1999 OG Software, Inc. All rights reserved.

Abridged Edition (19 pages)

This monograph, including the software contained in it, is provided AS IS with no warranties of any kind, either express or implied. The liability of OG Software, Inc., is limited to the replacement of defective distribution media returned to OG Software, Inc., within ninety (90) days of purchase together with a receipt evidencing such purchase. The purchaser of this monograph is authorized to distribute executables of his/her POO applications that contain object code of the POO software. All other rights are reserved to OG Software, Inc.

Internal Links: [ TOC | Intro | Using... | Writing... | Examples | Source ]

PREFACE

I wrote this monograph for people who program, people whose real business is not programming but who are not spectators. There was a time when our numbers were legion, but complex circumstances have thinned our ranks. There are lots of programmers, of course, but this monograph is for people who program. The advances that moved computers onto every desktop, e.g., windowing technology, served to disenfranchise many people who program because the advances require that they invest more knowledge and effort in their programming than they can afford. Consequently, many people who program were cast up on the shore amongst a flotsam of xterms and DOS windows.

This monograph contains the minimal, basic software that I regard as essential. Using the POO software, you can write applications that use multiple, windowed, text I/O streams based on an interface consistent with the basic I/O capabilities of the ANSI C and Fortran languages. In short, you can open and close windowed text streams, can append text to an output stream, and can obtain text from an input stream. As the user of a POO application, you can manage the attributes of its windows, the strings assigned to the function keys, the relationships between the output and input streams associated with its windows and the underlying file system, and the execution of the application itself. To manage the windows created by the application, you can interact with the windowing system directly or through the POO software. You can open windows to view files or directories in the file system. Scrolling, input editing, typeahead input, and line re-entry are supported.

There are, of course, some limitations. First, this monograph contains versions of the POO software only for the X Window System commonly supported in Unix, Microsoft's Windows, and IBM's OS/2 Presentation Manager. Thus your POO applications will be portable only among these systems. Second, you will need a C compiler that supports the development of windowed applications; if you write Fortran applications, you will need to learn how to build mixed-language applications. The versions of the POO software contained in this monograph are written in C, and you must compile the appropriate version. Third, you will need to learn how to tell your C compiler that your applications are both windowed and multithreaded. The POO software can be run single threaded in any of the supported environments but may not be satisfactory; the X version is predicated on the POSIX threads standard. Finally, you may need to install the X development system, e.g., include files, which many people omit to install in their Unix system.

This monograph consists of five files: a text file, a C source file containing the example applications, and a C source file for each of the supported windowing systems. The pure text in this monograph is relatively short; most of the text is contained in the source files. Much of the source code is the same in all versions and has been successfully compiled by nine or more C compilers and run successfully in three windowing systems.

Having spent many years writing anonymous documents in the third person and now being retired and free to exercise my First Amendment rights, I have chosen to write this monograph in the first person, perhaps with some backsliding. I have tried to limit the text to the necessary and sufficient information you need to start using the software and have relegated much of the documentation to the comments in the source code, which you should consult for detailed information. If you're reading this monograph, you're probably more interested in exploiting the software than reading my prose anyway.

Leonard J. Harding
August 1998

Internal Links: [ Preface | Intro | Using... | Writing... | Examples | Source ]

TABLE OF CONTENTS

INTRODUCTION

Introduction
The Windowing Systems
The Virtual Memory File Facility
The Memory File Facility
Portability Considerations
Other Design Considerations

USING A POO APPLICATION

Introduction
Keyboard Input
Mouse Input
Command Overview
Window Attribute Commands
Scrolling Commands: COLUMN and POSITION
Function Key Commands: Fn
I/O Direction Commands: CD, <, <<, >, and >>
Window Creation Commands: POLLSTER, ONLOOKER, and VMF
Termination Commands: EXIT, STOP, and MEMORY
NB Command: Inserting Notes
FIND Command: Word/String Search
CF Command: File Comparison

WRITING A POO APPLICATION

Introduction
The Initialization/Termination Function
The Open Function
The Close Function
The Put Function
The Get Function
A Noncommittal C I/O Model
A Fortran I/O Model

REFERENCES

EXAMPLE APPLICATIONS C/C++ SOURCE

Introduction
Pollster
Onlooker
Pseudorandom Number Generators
Floating-Point Mapping
Polish Notation Calculator
Convergence Map for Newton's Iteration
Nonsymmetric Eigenproblems

X WINDOW SYSTEM C/C++ SOURCE
MICROSOFT WINDOWS C/C++ SOURCE
OS/2 PRESENTATION MANAGER C/C++ SOURCE

Introduction
   Headers and Associated Additions
   System-Dependent Defined Constants
   Memory Management Macros
   System-Dependent Thread Management Macros
Data Structures and Associated Defined Constants
   The API Function Event Struct
   The VM File Struct
   The Window Struct
Function Prototypes and Macros
   Miscellaneous Macro Functions
   Windowing System Macros
Internal Variables and Tables
   Key and Button Tables
   Variables and Tables Associated with Command Processing
POO Main Program, API Functions, and Threads
   The POO Main Program
   cappl, copen, cclose, cgets, and cputs
   nappl, nopen, nclose, ngets, and nputs
   WaitEvent and WindThread
API Co-conspirators
   Open, Put, Get and Ctrl
Windowing System Interface
   CreateWND, SetAttribute, GetFontSize, Activate,
   EventProc, KeyFcn, ButtonFcn, LineBefore, LineAfter,
   DrawWindow, HexDump, DrawInput, and InputMgr
Command Processing
   Command, Annotate, ParseCommand, and ParseGeometry
Virtual Memory File Facility
   CreateVMF, DestroyVMF, LoadVMF, StoreVMF,
   ExpandVMF, AppendVMF, and AssociateVMF
Memory File Facility
   MemoryLoad, MemoryStore,
   MemoryCmd, MemoryKey, and MemoryVMF

Internal Links: [ Preface | TOC | Using... | Writing... | Examples | Source ]

INTRODUCTION

This monograph is intended for people who program in conjunction with their professional or leisure activities and would like to write portable windowed applications in C/C++ or Fortran for the X Window System commonly available in Unix, Microsoft's Windows, or IBM's OS/2 Presentation Manager. I assume that you would find delving into windowing technology for a period of several weeks or months to expand your computing skills an interesting but unwelcome diversion from your principal interests. I further assume that portability is an important consideration for your colleagues, if not for yourself. If you have experience programming in nonwindowed environments, such as xterms and DOS windows, and using windowed environments but have no background in constructing windowed applications, the software contained in this monograph may enable you to write windowed applications that are portable among the supported windowing environments. The POO software has been designed to build on your familiarity with the I/O functionality of C and Fortran so that you can write windowed applications with little more effort than you now invest in writing your nonwindowed applications.

The software contained in this monograph is an outgrowth of an effort to provide the full capabilities of today's windowed environments to people who program, which includes myself, but is limited to supporting text windows. Windowing systems involve some unusual elements, at least in comparison to those common in numerical applications, and the knowledge necessary to construct even simple windowed applications is neither easily acquired nor retained. People who program, people whose principal interests lie elsewhere, are unlikely to have either the time to acquire the requisite knowledge of one or more windowing systems or to require it often enough to retain it. The POO software is designed to allow you to construct windowed applications but does not require that you know much about windowing systems let alone be able to write windowing software.

The three versions of the POO software are very similar. The POO Application Programming Interface (API) does not depend on the windowing system so that a properly written POO application can be ported among these systems without change; the examples in this monograph are portable among these systems. The POO User Interface (UI) is almost independent of the windowing system so that users of POO applications are quite portable. Indeed, many aspects of the user interface were designed to encourage user portability.

The ability of an application to provide textual output to its user and to obtain textual input from its user are fundamental, and you may view the I/O capabilities provided by your C/C++ or Fortran compiler as sufficient. Even if your applications require only one I/O stream however, running your applications in an xterm or DOS window or some window created by the compiler for handling standard I/O likely falls far short of providing convenient access to the actual capabilities of your computer system. The real issue is not whether the I/O streams are windowed but rather the environment that is provided to the user while running an application.

The components of an appropriate solution are clear: a portable interface for the application itself, a simple and familiar programming interface, a familiar user interface, a command interface with the appropriate capabilities, and an interface to the underlying file system. The first objective is achieved by embedding the actual main program in the POO software so that a portable interface that is consistent with the C and Fortran standards could be provided for POO applications. The second led to an API that is consistent and, in most cases, compatible with the C and Fortran standards, namely the ANSI C stream I/O functions fopen, fclose, fputs, and fgets and the Fortran OPEN, CLOSE, WRITE, and READ statements when used to transmit textual data. The user interface supports an admixture of the usual keyboard and mouse controls: some may be very familiar because all of the supported windowing systems have many in common, but some may be unusual when viewed in the context of just one of the supported windowing systems. The command interface provides the user many of the capabilities of command windows as well as the ability to manage window attributes and the function keys. The virtual memory file facility embedded in the POO software is adept at dealing with both Unix and PC text files, binary files, and directories and can be exploited by the user to obtain windowed access to the underlying file system. Finally, for the user's convenience, the memory file facility automatically retains window attributes, function key string assignments, and other data between invocations of a POO application.

The POO API is small and easy to use. It is data oriented and contains no suggestion that the corresponding I/O streams are windowed. It employs only standard C data types that can also be represented in Fortran and contains only five functions, none of which take more than three arguments. The API functions provide only for the transmission of data; it is assumed that you will use the standard I/O formatting capabilities of the language to produce output text and to convert input text. You probably write your applications using the integrated I/O capabilities of C or Fortran that combine the formatting and transmission in a single function or statement. I would have preferred to support these integrated capabilities, but doing so would have sundered portability.

The POO UI is driven by the keyboard and mouse just as for any windowed application. Keyboard input will likely elicit the responses you expect, but many keyboard functions are duplicated to foster portability of the user among the supported environments. Mouse input may or may not elicit the responses that you expect because there is minimal standardization. Scrolling, typeahead, line re-entry, and many input editing features are supported. The UI includes a command interface so that you can change window attributes, manage the strings assigned to the function keys, manage the disposition of a window's output stream to a file, establish a file or portion thereof as a window's input stream, open pollsters to update logs and open onlookers to view files and directories, create virtual memory files, create or change files in the file system, and suspend or terminate the application.

Although you may view the focus of the POO software as supporting multiple, windowed I/O streams, the real issue is the user environment it provides when running an application. The POO software acts as an intermediary among the various active and passive participants: the application, the user, the windowing system, the file system, and the operating system. An application's responsibilities and prerogatives are quite limited and necessarily independent of the windowing system; an application should be concerned only with its I/O streams, which is reflected in the API. The user is expected to take an active role in the management of the execution of the application by managing the windows and their associated I/O streams. The remaining participants are passive or dictatorial.

Although all POO windows are alike as far as the windowing system is concerned, the POO software classifies them as either pollsters, onlookers, or others.

The size of the VM file associated with a pollster or onlooker is expanded as necessary. The size of the VM file created for an other and the management strategy, expansion or truncation, are determined by the application when the other is opened.

The Windowing System

The windowing systems in Windows and OS/2 are thoroughly integrated into the underlying operating systems, but the X Window System is simply a product that runs on top of an operating system, typically Unix. The X Window System is based on a client-server model; the X application need not be running on the same computer on which it opens its windows.

Both Windows and OS/2 contain the thread support required by the POO software, but you can choose to run your application single threaded. The system in which you run X may or may not support the POSIX threads standard on which the POO software is based; it is a relatively new standard so that many installed Unix systems do not support so-called Pthreads.

The Virtual Memory File Facility

A mechanism for managing the data displayed in the windows created by the application and user as well as an appropriate interface to the underlying file system are essential. The virtual memory file facility embedded in the POO software contains the requisite data management capabilities and handles all interactions with the underlying file system.

The VM file facility includes a couple features designed to enhance user portability. First, it accepts either a slash (/) or backslash (\) as the path name separation character. Second, it processes environmental variables that are specified in the form commonly supported by either Windows and OS/2 or Unix, specifically, %...% or ${...}. The VM file facility treats path names as case sensitive but can be changed to ignore case in file names, i.e., convert to uppercase.

The lines in a Unix text file are terminated by a new line character (\n), while Windows and OS/2 use the two-character sequence \r\n. The POO software adapts to whatever line termination is encountered. By default, new files are created to be consistent with the underlying file system.

The Memory File Facility

Over the years, I have come to appreciate software that can at least remember if not learn from experience. The memory file facility embedded in the POO software provides the required bidirectional capability: dynamic data that is retained between invocations. It retains function key string assignments and window attributes between invocations of a POO application and provides a record of all file references during execution. The memory file is implemented as a plain text file for the user's convenience and uses an abbreviated version of the syntax employed in the X resource manager.

Portability Considerations

Software is portable if it can be moved between systems with little or no change, which generally requires that it contain no significant system dependencies and be predicated on pertinent standards. A POO application that is itself portable can be ported among the supported environments: the X Window System, Microsoft's Windows, and IBM's OS/2 Presentation Manager. Portability in the broadest sense played a pervasive role in the design and development of this software.

Other Design Considerations

Issues arising from the desire to support both C and Fortran also had some impact on the overall design. For example, when a POO I/O stream is opened, the application can elect to treat it as either C stream I/O or Fortran record I/O. The POO software contains very few prohibitions and is not very paternalistic. This software is not designed to protect either itself or its data; there are no terminal errors. The POO software is a tool for people in search of reliable and effective tools. From the application's perspective, it is a very simply tool; from the user's, a perhaps overly permissive and flexible one.

You may find that windowed applications are somewhat more delicate than nonwindowed ones: errors in a windowed application may have bizarre consequences. Some windowed environments are delicate, while others are of sturdier stock.

Internal Links: [ Preface | TOC | Intro | Writing... | Examples | Source ]

USING A POO APPLICATION

You, the user of a POO application, can interact directly with the windowing system or can use the POO User Interface (UI) to interact with the windowing system, file system, or system. You can set and display the colors, font, and geometry of a window, which are your prerogative, indeed, they are your responsibility. You can set, display, and unset the strings assigned to the function keys. You can set and display each window's current directory, issue I/O direction commands to save output in a file or to establish input from a file, establish input from a subfile of an existing file, open additional windows to view directories or files in the file system, or create files in the file system. You can suspend or terminate the application. You can use the keyboard and mouse for scrolling and data entry and editing; both typeahead and line re-entry are supported.

All windows created by the application, whether at your request or the application's, are standard, top-level windows as provided by the window manager. As top-level windows, your desktop is the parent of each window, and all windows are independent of each other. As standard windows, each likely has a system menu box, title bar, a maximize, minimize, and/or restore box, and a sizing border.

The application opens one or more windows and appends text to the output streams that are associated with them. As text is added, the windows are updated to show the most recent output, normally with the last line of the output stream at the bottom of the window. You can scroll the text displayed in a window by using the usual scrolling keys, by dragging the text around the window with the mouse, by using the implicit vertical scroll bar, or by issuing COLUMN or POSITION commands.

For some windows, the application may solicit input. All input through a window is done in the input rectangle in reverse video, but the input rectangle is not drawn unless you are being solicited for input or entering unsolicited input. Input is terminated when you press Enter. Enter and Shift+Enter terminate your input normally, while Ctrl+Enter and Shift+Ctrl+Enter cause your input to be interpreted as a command. Line re-entry is provided by the right mouse button. The cut/copy/paste capability for input is implemented by both the usual Windows and OS/2 keys.

Keyboard Input

The keys are quadrupled based on the states of the Shift and Ctrl keys. The extended keys generally follow common usage, e.g., Insert toggles between insert and overstrike modes, and Delete and Backspace do so. Some of the scrolling keys are context dependent: they either scroll the window or move the input caret. To provide complete functionality while entering input, the scrolling keys in combination with Shift always provide the usual scrolling function.

Ctrl+ Function
A deletes the input after the caret OR the file after the bottom line.
B deletes the input before the caret OR the file before the top line.
C copies the input to the cut/copy/paste input buffer.
D terminates the application.
H the same as Backspace.
I ignored (Tab character).
M the same as Enter.
O toggles between text and hex dump format.
Q resumes application execution.
S suspends application execution.
U deletes all input OR restores the whole file.
V pastes the cut/copy/paste input buffer into the input.
X cuts the input to the cut/copy/paste input buffer.
Z generates an EOF.

The function keys are quadrupled based on the states of the Shift and Ctrl keys so that Shift+F5 is F17, Ctrl+F5 is F29, and Shift+Ctrl+F5 is F41. The commands F1,...,F48 can be used to set, display, or delete a string assignment to the function keys. The function keys F5, F6, and F7 and their progeny are assigned built-in functions; built-in functions have lower precedence than strings you assign.

Key Built-In Function
F5 pastes into the input stream or to the end of the file.
F6 toggles the window update mode (others only).
F7 copies the VM file associated with the window.

Because key processing is table driven, the functions delineated in the tables above can be modified by changing table entries in the POO source.

Mouse Input

Mouse input is processed when you press a button or, in one case, when you drag with the button pressed; your release of a button is ignored. The mouse buttons are quadrupled based on the Shift and Ctrl keys. You can drag the text around the window. In effect, when you press the left mouse button, the software attaches the pointer to the character under it, and the text is moved to maintain this attachment.

Button Function
Left drags text around the window.
Shift+Left scroll bar regardless of pointer location.
Right enter line as input or same as pressing Enter.

Because button processing is table driven, the functions noted here can be modified by changing table entries in the POO source.

Command Overview

You enter commands to manage the window attributes, function keys, current directory, I/O direction, and the updating of the memory file; there are also commands for setting the window position and displaying the status of the application or a file. The usual set and display commands are not provided; rather, each value that you can manage is represented as a command. If you provide no operand, the current value is displayed; otherwise, the value is changed. Commands can be abbreviated by truncation on the right provided the abbreviation is unique.

Command Word(s) Operand(s)
BACKGROUND aka BG color name
FOREGROUND aka FG color name
FONT aka FN font face name [[ width ]x[ height ]]
GEOMETRY [=](width)x(height){+|-}(x-org){+|-}(y-org)
MODE [+|-](flag-word){+|-}...
F1...F48 text[ \n | ^M ] | -
COLUMN integer
POSITION integer | fraction

Window Attribute Commands

The BACKGROUND, FOREGROUND, FONT, GEOMETRY, and MODE commands provide control over the obvious attributes of the window; the usual X abbreviations BG, FG, and FN are accepted. If successfully executed, these commands update the memory file.

Scrolling Commands

The COLUMN and POSITION commands provide no new functionality but do provide more precise mechanisms and the ability to display the current values.

Function Key Commands

The commands F1,...,F48 set, display, or delete string assignments to the 48 function keys. If you assign a string that ends with the the two-character sequence "\n" ("^M"), it has the same effect as if you pressed Enter (Ctrl+Enter) after pressing the function key.

Command Word(s) Operand
CD pathname
< aka LOAD filename | -
<< aka CONTINUE filename | -
> aka STORE filename | -
>> aka APPEND filename | -

I/O Direction Commands

Canceling output direction can be done with impunity, but canceling input direction should be done carefully. CD and I/O direction commands are not saved in the memory file; but, if qualified by the window name, they are processed when creating others. Unqualified CD commands in the memory file set the application's current directory.

Window Creation Commands

Command Word(s) Operand(s)
POLLSTER poll file name
ONLOOKER file or directory name
VMF (size)[ K | B | P ] [ pc | unix | binary ]
MEMORY none opens an onlooker for the memory file.
YO [ filename | none ]

Termination Commands

Both the EXIT and STOP commands terminate the application: the former updates the memory file based on the memory status, while the latter does not update the memory file. In general, MEMORY is on so that attribute commands are recorded automatically and the memory file is updated.

Command Word(s) Operand(s)
MEMORY [ off | on ]
EXIT aka XIT aka QUIT none
STOP none
CLOSE none
? none, displays application and window status.
NB none, inserts N.B.'s in others.
CF integer
FIND [?]string[?] [b]

The NB Command

The NB command may seem a bit cryptic, but N.B. is the standard abbreviation of "nota bene" and the NB command inserts an N.B. with a date and time stamp and your input in an other. For pollsters, the NB command is implicit. For onlookers, your input is appended to the VM file but not the disk file associated with the onlooker.

The FIND Command

The FIND command moves the window so that the line containing the next occurrence of the string is at the top of the window. In processing the first operand, an initial or terminal question mark is discarded but not ignored. If present, an initial question mark indicates that you are indifferent to the character preceding the first character of the string; otherwise, the character preceding the first character of the string must be unlike the first character of the string. A terminal question mark has an analogous effect. In this context, 'unlike' means that the two characters in question cannot both be alphanumeric, punctuation characters, or white space characters.

The CF Command

The CF command compares two files starting with the second line in each window. When a mismatch is found, a message indicating the outcome of the comparison is appended to the command, and each window is moved to show the line containing the mismatch at the top of the window. Before resuming the comparison, you may position the windows to resync the files or to skip sections as desired.

Internal Links: [ Preface | TOC | Intro | Using... | Examples | Source ]

WRITING A POO APPLICATION

You, as the writer of a POO application, must be familiar with the POO Application Programming Interface (API) and aware of the rules that must be followed when writing and compiling a POO application. The POO API is very primitive: your application can open and close windowed I/O streams, append data to an output stream, and obtain data from an input stream. Your application starts with a function named 'appl' that accepts no arguments and returns an integer. Your application is responsible for providing its name and the names of its I/O streams, all of which should be unique for the user's sake.

int cappl (char *application_name)
void *copen (char *name_title, int size, int extra_size)
int cclose (void *id)
int cputs (void *id, char *text, int length)
int cgets (void *id, char *buffer, int length)

The Initialization/Termination Function

This API function, cappl or nappl, has two roles: to initialize your application by loading the memory file and to terminate it gracefully. The single argument to this function is a character string. If the argument begins with an alphanumeric character, it is the name of the application and its memory file is loaded; otherwise, the application is terminated. If you do not initialize your application, it runs without a memory file and will be quite forgetful.

The Open Function

The open function, copen or nopen, takes three arguments:

  1. a string of the form "[modifiers][window name]:[window title];"
  2. the initial size in bytes of the VM file to be created for retaining the output stream, and
  3. the extra size in bytes.
The open function creates a window and an associated VM file for an output stream and returns the I/O identifier that is required as the first argument to the other API functions. If unsuccessful, NULL (zero) is returned. A POO identifier is a void * pointer in C and a 32-bit integer in Fortran.

The Close Function

The close function, cclose or nclose, closes the window identified by its only argument, a POO I/O identifier, and returns 0 (zero) if successful and -2 otherwise, e.g., the I/O identifier is invalid.

The Put Function

The put function, cputs or nputs, takes three arguments:

  1. an I/O identifier for an other,
  2. a text pointer, and
  3. the length of the text (computed if not positive).
The put function appends your text to the output stream associated with the identified window, updates the window to show the end of the output stream unless requested otherwise, and returns a non-negative integer if successful or -2 if the identifier is invalid or corresponds to a pollster or onlooker.

In general, the descriptions of these control characters in the ANSI standard (5.2.2) are legacies from the era of teletypes and are processed by the POO software in this spirit. The phrases enclosed in quotes are from the ANSI C standard.

\a "produces an audible...alert."
\r "moves the active position to the initial position of the current line" or deletes the previous line.
\b "moves the active position to the previous position on the current line" or deletes the previous character.
\f updates the window to show the text being appended at the top of the window.
\v skips the automatic window update.
\0 empties the VM file used to retain the output stream.

The implementations of \b and \r are not compatible with the ANSI standard and may not be faithful in that the output stream viewable in the window may not be consistent with the file created by output direction. A mischievous application can elicit mischief. If used judiciously, the output stream and file should be consistent. Clearly, the processing of \f and \v, which are described as a form feed and a vertical tab, respectively, do not embody much of the ANSI spirit.

The Get Function

The get function, cgets or ngets, takes three arguments:

  1. an I/O identifier for an other,
  2. a buffer pointer, and
  3. the length of the buffer
and returns the number of characters placed in the buffer, -1 if the user responded with an EOF, or -2 if the I/O identifier is invalid or corresponds to a pollster or onlooker. If a negative value is returned and the buffer exists, the null string (0) is returned in the buffer.

A Noncommittal C I/O Model

The noncommittal I/O model is based on macros such as those illustrated in the table. These definitions assume that the various arguments are global variables that have been defined appropriately, e.g., char buf[256]. When using C stream I/O, id has the type FILE * and is set by calling fopen; when using the POO software, it has type void * and is set by calling copen. These macros are used by simply enclosing the format and I/O list appropriately, e.g., "BFO "%i\n", n EFO".

Macro POO Definition Standard C Definition
#define BFO cputs(id,buf,sprintf(buf, fprintf(id,
#define EFO )); );
#define BFI cgets(id,buf,buflen); sscanf(buf, fgets(buf,buflen,id); sscanf(buf,
#define EFO ); );

The principal advantage of this model is that it vests in code only the format and I/O list and leaves the transmission issues to be resolved by the above macros, which can be easily changed. In this respect, this model could also be described as portable but is more aptly termed noncommittal.

A Fortran I/O Model

A convenient model for writing POO applications in Fortran is somewhat more elusive and must overcome a number of minor issues, e.g., formatted output does not generate new line characters because it is record oriented and knows nothing about null terminated strings. About the only feature of Fortran that can be exploited is the inherent structure of the Fortran WRITE and READ statements. Specifically, the structural similarities of WRITEs and READs with a unit and with a buffer allow the same code to be used for standard Fortran I/O and with the POO software, or any other transmission service. For example, I would normally write

for standard Fortran input from a unit but write to use ngets for data transmission and the READ statement only for its formatting capability. The only real difference between these two READ statements, however, is the type of the first variable, which is either an INTEGER variable or constant or a CHARACTER variable of appropriate length. Thus, by changing the type of a single variable, the meaning of all WRITE and READ statements in a program can be changed. The data transmission can be handled by the POO API functions, some other transmission functions, or dummies that do nothing.

Internal Links: [ Preface | TOC | Intro | Using... | Writing... | Source ]

EXAMPLE APPLICATIONS C/C++ SOURCE

Building an Example Application in Windows or OS/2

To build an example application, you will need this file and the appropriate POO source file. In some Windows environments, a .DEF file is required, but a .RC file is not needed. For some C compilers, you must specify the 'windowed' and the 'multithreaded' options, which vary from obvious to obscure depending on your C compiler. The Windows and OS/2 versions of the software run multithreaded unless you change the source code.

Building an Example Application in Unix/X

You will need this file and the POO source file for the X Window System. You will need an ANSI C compiler; a Kernighan and Ritchie C compiler will NOT compile the POO software. Unix/C compilers generally support the POSIX I/O library, and hopefully you installed the X development system, e.g., the include files required for compiling X applications. When you compile, you must specify the "-lX11" option because the X library is required. The X version of the POO software runs single threaded because the variable POO_MULTITHREADED is undef'd but includes multithreading support based on the POSIX standard, Pthreads. If you elect to try multithreading, you must specify the "-lpthreads" option.

Pollster

Pollster was designed to keep a reliable log consisting of entries provided by the user. Its progenitor automated an accurate log of my computer activity. Each entry starts with a header containing the date and time and a unique integer. The header is followed by the user's input, indented two spaces for visual separation.

The unique integer in the header is the displacement of the first character of the entry within the file and can be used to position the file in the window or to make internal references. Further, they provide a basis for assessing the integrity of the file since manual editing of the file invalidates them unless it is done very carefully.

Onlooker

Onlooker was designed to provide a safe and convenient mechanism for rummaging or browsing through a file system which is the first thing I want to do whenever I fire up a new system. It's aptly named because it's not allowed to change files unless you give the secret password even though onlookers are not restricted in other POO applications.

Pseudorandom Number Generators

At the beginning of the POO source code, there is a #define or #undef for POO_MULTITHREADED, which determines whether the POO software is compiled to run single or multithreaded. You want to use the multithreaded version, and the purpose of Random is to illustrate why in a safe setting.

Simply generating random integers and printing the frequencies is not much of a task for a self-respecting computer, particularly when run using a full-cycle pseudorandom number generator, but it is precisely what this example does. Since Random runs for the full cycle and time is doubling between each output line, Random starts quickly but becomes processor intensive and, depending on your processor, may take up to an hour. You can terminate (Ctrl+D or Esc) or suspend (Ctrl+S or Pause) if you can get its attention, which is what makes threads pertinent.

Windowing Systems and Threads

When running windowed applications, you may have noticed that the pointer often changes from the familiar arrow to an hourglass or clock and that, when this happens, some or all of the windows on your display may be unresponsive until the arrow is restored. The lack of response stems from the fact that one or more applications is ignoring its event queue, a feature common to windowing systems. Threads is an answer, i.e., an application can start a thread, in effect another task, to handle its event queue automatically. There are other ways of handling the event queue, but multiple threads is by far the easiest.

The POO software can be compiled to run either multithreaded or single threaded but should be run multithreaded unless your system does not support threads. When multithreaded, your application runs as one thread, and the POO software creates another thread to service the event queue so that the application remains responsive even though it may be processor intensive. Further, if you are so inclined, your application can be multithreaded if the POO software is running multithreaded, i.e., you can create additional threads. When single threaded, you are responsible for ensuring that your application calls a POO API function frequently enough to remain responsive. When single threaded, each POO API function processes all queued events, then performs its function, and then checks for events again before returning. If you run single threaded and fail to call an API function frequently enough, the underlying system may complain, perhaps bitterly, or even freeze to death.

The X version of the POO software is implemented in terms of the POSIX threads standard, so-called Pthreads. The Windows and OS/2 versions of the POO software use the thread function provided by the compiler, which are based on the thread support embedded in these systems. Thread functions are compiler dependent and very unforgiving.

#define N 4
#define BSO cputs(w,
#define ESO ,0);
#define BFO cputs(w,buf,sprintf(buf,
#define EFO ));

int appl (void)
                        BEGIN
void *w; int n, i; char buf[120+10*N];
long seed, chk; double bucket[N], cnt, t, pcnt;
seed = 1; for (n = 0; n < N; ++n) bucket[n] = 0.0; cnt = 0.0;
w = copen("io:Random Integers;",1,0); pcnt = 1024.0; chk = 0L;
BSO "The time between output lines is doubling and will\n" ESO
BSO "get lengthy.  Hope you're patient; 2B to go!\n\n" ESO
while (1) BEGIN
  ++bucket[itw(&n,&seed)]; ++cnt;
  if (cnt == pcnt || seed == 1)
    { t = (1000000.0/(double)CLOCKS_PER_SEC)/cnt;
    BFO "\v%11.0lf %8.3lf",cnt,t*clock() EFO
    for (t = 0.0, i = 0; i < N; ++i) { t += bucket[i];
       BFO "\v%10.6lf",bucket[i]/cnt EFO }
    BSO "\n" ESO
    if (t != cnt) {
      BFO "Oops, buckets only have %.0lf != %.0lf!\n",t,cnt EFO
      break; }
    if (seed == 1) break; pcnt += pcnt; }
  else if (++chk == CHK_LIMIT) { chk = 0L; cputs(NULL,NULL,0); }
END
BSO "I quit!\n" ESO return 0;
                         END

Floating-Point Mapping

This example, fpMap, tests the floating-point conversion mappings provided by the C library. This is an old issue that was settled theoretically in the late sixties, and implementations of the correct mappings were in general use in the early seventies.

Polish Notation Calculator

This example application is a Polish notation calculator and is moderately useful if you're familiar with this notation, e.g., have experience using Hewlett-Packard calculators. It supports only rudimentary calculations but can be easily enhanced.

Convergence Map for Newton's Iteration

This application reads/generates a complex polynomial, reads the parameters describing a rectangular region of the complex plane, and then draws a map of this rectangle based on the convergence of Newton's iteration for the zeros of the polynomial when the points in the rectangular region are used to start the iteration. The map is drawn in a window as a printer plot, which is an ancient but honorable technique for drawing pictures with a computer.

Nonsymmetric Eigenproblem

The previous example applied a numerical method of dubious virtue to a problem of your choice to illustrate the idiosyncrasies of the method. This example illustrates the converse: an impeccable method applied to nonsymmetric eigenproblems that you specify in terms of their eigenvalues and condition numbers. By varying the condition numbers, you can control the accuracy of the computed eigenvalues because the inevitable rounding errors provide the perturbations necessary to bring the condition numbers into play.

Internal Links: [ Preface | TOC | Intro | Using... | Writing... | Examples ]

X WINDOW SYSTEM C/C++ SOURCE
MICROSOFT WINDOWS C/C++ SOURCE
OS/2 PRESENTATION MANAGER C/C++ SOURCE

.
.
.
The POO software is in one, large file for your convenience. Thus,
to use the software, you only need to copy this file and to add
one dependency to your application. A single file avoids pollution
of your application's name space because all function and variable
references are within this file.  Further, if perusing the source,
all references to variables, functions, etc., can be found with a
single search. For this reason, contractions for names are used in
comments so that scans will find only code references, e.g., the
initial O_ is dropped from the names of functions.

Lines of the form "=...=" demarcate the major sections in this
file; each starts with an overview.  Within these major sections,
lines of the form "-...-" demarcate the individual functions,
which start with an introduction and contain embedded commentary.
.
.
.
/*
Memory Management Macros

All memory allocations are done using the VM_... macros and are
made in pages, i.e., multiples of 4096 bytes.  The ACQUIRE and
POINTER returns are treated as distinct but may be identical,
e.g., in Unix.  These macros were designed to be portable among
the supported systems, and any resemblance to an actual design
is purely coincidental.  They are placed here because .._HNDL is
required to define the structs in the next section.
*/
typedef size_t VM_SIZE;
typedef void * VM_HNDL;
#define VM_ACQUIRE(h,s) h = malloc(s)
#define VM_POINTER(h)   (h)
#define VM_RELEASE(h)   free(h)
.
.
.
/*
For all other application names, MemoryLoad is called to load the
memory file, and all windows must be opened explicitly.
*/
else
  { if (! O_MemoryLoad(oNONE)) return -1; State |= sbOTHER; }
return (int)SSN;
.
.
.
/*
The ? command is display-only:  the names of the application and
window plus status information.  If multithreaded, the state flags
may be wrong in rare instances; the DONE state flag is set if appl
returns, but the application may have started other threads.  The
application's date/time stamp is appended.
*/
case oWHOAMI:
  O_InputMgr(lw,ApplicationName,0);
  if (WindABH == ApplABH) O_InputMgr(lw,"ST",-1);
  if (State & sbSTOP) O_InputMgr(lw,"suspended",-1);
  if (State & sbDONE) O_InputMgr(lw,"done",-1);
  if (State & sbAPI) O_InputMgr(lw,"API",-1);
  O_InputMgr(lw,"::",-1); O_InputMgr(lw,lw->wndname,-1);
  sprintf(lw->tmp,"#%li",lw->SSN); O_InputMgr(lw,lw->tmp,-1);
  if (lw->apiarg) O_InputMgr(lw,"awaiting input",-1);
  if (lw->flags & bSTATIC) O_InputMgr(lw,"static",-1);
  s = lw->tmp; *(s+1) = *s = ':'; *(s+2) = ' ';
  O_Time(s+3,&(Work->mtime));
  break;
.
.
.
/*
A NEW file, a file that doesn't exist in the file system or as a
VM file, is not acceptable when calling LoadVMF.  If esize is
positive, a directory is not acceptable; likewise a binary file,
but that cannot be detected without loading the file.
*/
if (lf->flags & bNEW)
  { O_DestroyVMF(lf); *e = "doesn't exist."; return NULL; }
if (lf->flags & bDIR && esize > 0)
  { O_DestroyVMF(lf); *e = " Directory!"; return NULL; }
.
.
.

Internal Links: [ Preface | TOC | Intro | Using... | Writing... | Examples | Source ]