This file contains the spec for the sample application discussed in
the article "Sizing Up Application Frameworks and Class Libraries",
by Ray Valdes, DDJ, October 1992.

The spec follows the list of files and list of vendor addresses.

================================================================

LIST OF FILES:


DDJAFX   TXT     37681 09-15-92  10:32p  <--The file you are reading now
BOROWL   ARC    165984 09-15-92  10:15p  <--Borland OWL
OWLYAO   ARC     53664 09-15-92   9:47p  <--OWL version by Paul Yao
INZAPP   ARC    209142 09-15-92  10:21p  <--Inmark zApp
OBJMNU   ARC    496849 09-15-92   9:52p  <--Island Systems Object Menu
CPPVUS   ARC    188334 09-15-92  10:10p  <--Liant C++/Views
MSMFC    ARC     56420 09-15-92   9:34p  <--Microsoft MFC 


================================================================
VENDOR ADDRESSES:

Liant Software Corporation
959 Concord Street
Framingham MA 01701-4613
(508) 872-8700

Inmark Development Corporation
2065 Landings Drive
Mountain View CA 94043
(415) 691-9000

Island Systems
7 Mountain Rd.
Burlington MA 01803
Tel: 617-273-0421
Fax: 617-270-4437
BBS: 617 270 9552

Borland International
1800 Green Hills Road
PO Box 6600001
Scotts Valley CA 95067-0001
(408) 438-8400

===================================================================
What follows is the original spec as distributed to vendors by DDJ.
===================================================================

CRUISING ABOVE THE API:
APPLICATION FRAMEWORKS, CLASS LIBRARIES AND GUI TOOLKITS

DDJ AAPI Project Spec V1.0b
by Ray Valdes
June 25, 1992


Dr Dobb's Journal has begun a project to evaluate
application frameworks, class libraries and GUI toolkits.
This document presents the project rationale and provides
the specs for a sample application.  Earlier this month, we
circulated a preliminary version of the document and
incorporated many constructive comments. Although this
document is now at Version 1.0b, there is still some room
for judicious revisions. The major change changes since
Version 1.0, dated June 23 1992, is the addition Appendices
A and B.


COMPARING APPLES, ORANGES AND BANANAS

Application frameworks are complex and powerful development
tools that have generated much excitement among PC
programmers. The choice of a framework is as critical to a
development project's success as a choice of algorithm or
programming language. Frameworks are new enough that no
clear standards have emerged, and many plausible contenders
exist.

Although application frameworks are not a new concept, they
have only recently arrived as a mainstream development tool
on the PC platform. Many of the key elements in application
frameworks were present in Smalltalk-80, now over ten years
old. However, it was Apple's MacApp system that rigorously
systematized the key ideas of an application framework: a
generic app on steroids, providing a large amount of
general-purpose functionality within a well-planned,
integrated structure.  Object-oriented languages are ideal
vehicles in which to embody an application framework, and
the advent of C++ to the PC platform has allowed mainstream
PC programmers to finally enjoy the benefits of frameworks.

Class libraries and GUI toolkits are generally smaller and
simpler systems than application frameworks. GUI toolkits
predate object-oriented languages, and some of the most
successful products in this category are written in
assembler. Class libraries, on the other hand, incorporate
much of the same functions as a GUI toolkit, but do so in an
object-oriented fashion and add support for non-GUI
functions such as data structure manipulation (queues,
lists, arrays, collections). Both class libraries and GUI
toolkits often come bundled with design tools that allow you
to interactively specify application components, such as
dialog boxes and menus.

Because application frameworks, class libraries and GUI
toolkits represent very different technological approaches,
comparing them is like comparing apples, oranges and
bananas.  Yet the fact remains that many programmers are
faced with exactly that decision when starting a development
project. As that stage of the project, all these products
"look like fruit to me", as the saying goes. All these
products address the same basic software development issues:
how to reduce coding effort, speed time to market, increase
maintainability, add robustness, and leverage off prefab
functionality.


THE VIEW FROM SQUARE ONE

Recently at DDJ, we faced this decision at the outset of the
Handwriting Recognition Contest.  One of the programs we
needed to write was a browser for handwriting data samples.
Although this kind of program does not fall within the
standard product categories of shrink-wrapped software, many
of the functions required by our program are representative
of those in modern graphics-oriented applications (see
"Program Spec" section later).

The view from square one is very simple: do you stay with
the raw API (basic DOS or Windows services), or do you
choose something at a higher level?  If you choose the
latter (the "fruit" scenario), then you're at square two:
choosing between a framework, a class library or a GUI
toolkit.  By using an application framework, you can cruise
above the API at a high altitude, but have the steepest
learning curve. Because the framework constrains your design
decisions, you also run the risk of crashing into a brick
wall (to mix a metaphor). Using a GUI library, you're much
closer to ground level, and enjoy a gentle learning gradient
as well as free choice in architectural design approach. The
downside is, of course, you must do more of the work
yourself.

In the case of the DDJ Recognition Contest, our deadline did
not permit the uncertainties associated with any kind of
learning curve, so we stayed with the ground-level Windows
API (we also implemented an even more rudimentary DOS
version using our C compiler's graphics library).  We wished
for the time to properly evaluate development alternatives,
and so this project began.


DEFINITIONS

For our purposes, we define an application framework as an
integrated object-oriented software system that offers
application-level classes (documents, views, commands) and
that is meant to be used in its entirety. An application
framework embodies a particular philosophy for structuring
an application, and, in return for a large mass of pre-built
functionality, the programmer gives up control over many
architectural design decisions. The principal design
approach used by most application frameworks is an
evolutionary descendant of Smalltalk's Model/View/Controller
triad.

We define a class library as an object-oriented set of
workhorse classes that can be incorporated piece-meal into
an application, rather than the other way around. By
allowing the programmer to pick and choose, a class library
does not enforce any particular architectural approach. The
services offered by class libraries include both user
interface functions (menus, dialog boxes, and graphics
primitives) as well as general utility functions (date and
time conversion, data structure manipulations, and so on).

Finally, a GUI toolkit offers similar services as a class
library, but using a procedure-oriented rather than an
object-oriented interface. Most DOS-based GUI libraries are
at the same basic level of abstraction as Windows (or at
least the early versions of Windows).  Unlike class
libraries, GUI toolkits generally do not offer non-graphical
utility routines (queue management routines, for example).

In practice, the distinctions between one product and
another are not as clear-cut as these definitions. For
example, one vendor of a class library directly compares
their product against a popular application framework.
Another class library vendor avoids comparisons with
application frameworks, yet the sample programs bear an
uncanny philosophical resemblance to those of the
application framework.


THE PROBLEM WITH "SATURDAY NIGHT" REVIEWS

So how does the programmer make an informed choice?  Not by
reading most product reviews we've seen. Because much of an
application framework's machinery lies under the surface,
evaluating application frameworks is a uniquely difficult
task. A few hours spent with the manual or looking over
example programs is not appropriate for such a complex and
subtle tool.

As with evaluating a programming language, the best way is
to try using it on a development project of nontrivial size.
But there are a couple of problems with this approach.  The
first is the steep learning curve. The second is that many
weeks or even months may elapse before running into specific
limitations that stymie further development or require
contrived workarounds. It may be too late when you discover
that your framework is actually a straightjacket. Another
problem is that, even if a framework is well-designed and
bug-free, it may offer multiple ways of accomplishing a
given task, and it is not always clear to the novice which
is the best approach.  By contrast, the experienced user of
a framework knows which methods offer best performance and
are easiest to code, but this knowledge is often hard-won.

Because the limited hours alloted for a standard product
review (typically, an evening with the manual, plus a
weekend working with sample code) do not give the reviewer
sufficient exposure to real-world use of the framework, we
have arrived at an alternative approach.


OUR PROPOSAL

Our proposal is to evaluate frameworks, class libraries and
GUI toolkits by asking vendors (or friendly third parties
who are expert with that particular product) to code up a
small but non-trivial example program.  Briefly, the program
we propose is an interactive browser for digitized
handwriting samples.  Its functional requirements are
specified later in this document.

Our aim is not a confrontational "shoot-out". Arguing about
which is the "best" framework is like arguing about which is
the best cuisine, text editor or  programming language.  Our
position is that different products satisfy different needs
and tastes.  Some products support portability between
platforms, others focus on high level of object-orientation,
others emphasize closeness to the Windows API, others swear
by performance optimization, and so on.  Every programmer
has a unique set of opinions about which characteristics are
important and which can be sacrificed in real-world
tradeoffs. Not only that, but strongly-held opinions often
change in the course of development, in response to changing
market conditions.

We think it's possible to arrive at a task that will
exercise many of the most interesting features of various
frameworks. By implementing the same functional requirements
using different frameworks, we provide a concrete example
that readers can use in making the decision about whether a
framework is appropriate --- each person examining the
resulting code in terms of his or her unique tradeoffs. The
program as specified is small but nontrivial. Our goal is to
arrive at a simple spec that can be implemented by an expert
user of a framework in three working days or less.  Someone
new to the framework, by contrast, may spend a couple of
weeks accomplishing the same task.

Our specs were not arrived at with any vendor's feature list
in mind.  Rather, the specs are come from an entirely
different project and predate the current effort. The
example includes real-world randomness, and as such does not
claim to comprehensively exercise every item on a product's
feature list.  The main value of the example is that its
requirements are broadly representative of a large class of
graphics-oriented programs.  We find it more interesting to
get a real-world useful application that works rather than a
contrived example that displays twenty different dialog
boxes that we'll never use.  With this in mind, our
specification offers plenty of leeway to the implementor to
solve the problem in the way best suited to the application
and tool.


WHO'LL  PASS  JUDGEMENT?

DDJ will not benchmark the submitted code, nor will we pass
categorical judgements on the merits of each submission.
Those judgements are left to our readers. We'll publish the
code (or as much as will fit into the magazine) and provide
an introduction similar to this document.

Readers will be able to run the programs, examine the code,
check the EXE size, and try to modify it (assuming they
possess the necessary tools), and so on. If space permits,
we'll point out interesting landmarks and development
implications in our tour through the code.

We realize that not all systems rely on hand-coded source
files. Some vendors offer interactive design tools to
accomplish all or part of the task.  This is a legitimate
approach, as long as it is made clear how much of the
process has been automated, what the output looks like (in
the case of code generators), and what it would take to
modify the results.


PROJECT SCHEDULE

This project will be done in two parts: for our October and
November issues (on Object-Oriented Programming and on User
Interfaces, respectively).  Although the boundaries are not
always clear-cut, the October issue will focus on object-
oriented application frameworks and class libraries, and the
November issue will cover GUI toolkits and barebones class
libraries.

The production schedule for our October OOP issue means
vendors must submit first drafts to us by July 7th (or
thereabouts). Because the time is close at hand, we'd like
to hear from participants as soon as possible.

For our November issue on user interfaces, the deadline is
August 7th.


PROJECT PARTICIPANTS

We've asked the following vendors to participate (listed in
alphabetical order):
   o  Autumn Hill Software (Menuet and Baby Driver II)
   o  Borland (Object Windows Library)
   o  Inmark Development (zApp)
   o  Island Systems (Object Menu for C++)
   o  MetaGraphics (MetaWindow)
   o  Microsoft  (MFC)
   o  Liant (C++/Views)
   o  XVT Software (XVT Toolkit)

From this list (and other possible additions), it is likely
we will have four or five participants in each round of this
project. Depending on reader response, we may follow up with
a future article featuring additional frameworks, or new
versions of existing products.

In certain cases where a vendor was unable to participate,
we've chosen to rely on a third party developer to implement
the example application.  We've not tried to be
comprehensive in our selection of vendors (there are way too
many to cover in one or two issues of the magazine).
Rather, our focus remains on technology issues rather than
specific products. We've tried to make our list
representative rather than comprehensive. Comparing apples,
oranges and bananas is a stated goal; comparing all such
instances is not.

Every participant will receive the same specs and have the
same amount of time (from now until July 7th, in the case of
the October issue). No participant will see the code of
others until it is appears in print. In addition to
submitting code, participants can optionally submit a short
narrative about their implementation. This would be a
maximum of 500 words, and can be used to point out
interesting features or clarify one's development approach.

Participants are also free to add as many features to the
spec as they desire, in order to highlight features of their
framework not addressed by the original spec. This is
entirely optional.


THE PROGRAM SPEC

The application is called HWX BROWSER, and allows users to
read in different sets of handwriting data from files on
disk and display the alphabets in an application window.

As stated earlier, the program is not a contrived example
meant to exercise items on a vendor's feature list.  Rather
it is something arising from real-world needs that is in
many ways representative of graphics-oriented programs, as
well as offering its own unique challenges to the
implementor.

The browser allows interactive viewing of handwriting
samples which have been gathered from a number of people.
Each file represents samples collected from a single person,
in the form of a series of alphabets.  The file has a
particular structure, specified in Appendix A.  Briefly, it
consists of a short header, followed by the data for
individual letters of the alphabet, each letter being
represented by multiple instances or versions.  The data for
a single instance is basically a sequence of coordinates as
gathered by the digitizer, a set of points for each stroke
in a character.  Displaying a stroke is easily accomplished
by MoveTo() and LineTo() graphics primitives, or by a call
to Polyline().

The basic areas of functionality are: file operations,
character selection, display of the image in a window,
printing, and debugging. Within these basic areas, we've
identified some aspects that are optional, given the severe
time constraints.


FILE OPERATIONS

The application must present a list of files to the user,
and allow one of these to be made active. Windows 3.1 makes
this easy, with the advent of the Common File Dialogs
(equivalent to Apple's StdFile dialog).  Products that run
directly on DOS or on other platforms that don't offer this
kind of functionality must implement it themselves.


CHARACTER SELECTION

The user must be able to identify items of interest in the
selected file (after the file has been read into memory by a
DDJ-supplied function). The UI mechanism can be a dialog box
or a menu or some other technique.

Typically, users will want to look at:
     1. an individual instance of a particular letter of the
alphabet
     2. all instances for a given letter of the alphabet
     3. an entire alphabet (comprising one sample set)
     4. all instances for all alphabets
     5. custom sequences of letters, such as a short
sentence of phrase displayed in a given alphabet.

Of the items on this list, the first two are minimal
requirements. The final three items are optional, and
probably can't be done within the time constraints.


CHARACTER DISPLAY

In addition, the user needs to control aspects of the
presentation. These aspects include:
     1. changing line thickness
     2. changing line color
     3. changing background color
     4. scaling the image
     5. scrolling the image

The first two items on this list are minimal requirements,
the rest optional. Left up to the discretion of the
implementor is the choice of UI mechanism: menu bar, dialog
box, icon bar, tool palette, pie menu, etc. Scrolling may or
may not be necessary, depending on the way letters are
presented. A single letter in a single window probably does
not need to be scrolled.  A fancier alternative would be to
display all alphabets in a spreadsheet-like table, with
column and row headings (each complete alphabet would be one
column).  In this case, scrolling around this table is
essential, because it won't fit on one screen. Unless the
framework offers a built-in tableaux or matrix class, it's
likely that most implementors will display a single
character per window, given the time constraints.

This wide latitude in design choices reflects the leeway we
encountered in implementing the program described here: we
had no dogmatic preferences about UI widgets, and just cared
about getting the job done. Our philosophy is that any
program is better than no program, and the world's fanciest
empty dialog box is useless compared to a complete
rudimentary program that accomplishes the given task. In the
case of our DDJ implementations (the raw Windows API and the
DOS versions), the results are indeed homely but usable
nevertheless.


PRINTING

The application needs to produce hard copy of letters and/or
alphabets. There is much leeway in how printing is
implemented:
     1. It can be done one letter at a time, similar to a
screen dump of a window's contents.
     2. It can be done an alphabet at a time, with no
pagination or headings.
     3. It can be done in a more elaborate report form, with
full pagination and headings.

Given the time constraints, it is expected most submissions
will opt for the rudimentary approach. While we consider
printing essential to the program spec, we realize that
printing is a problematic issue for some systems, requiring
much hand-coding. As with any other part of the spec, if
implementing any particular feature will bust the suggested
time budget (2-3 days of an expert's programming time) by a
large amount, then our advice is to note the fact and pass
along to the next feature.


A HEX VIEW OF DATA

One aspect of a graphics-oriented application that
Smalltalk-80 handles particularly well is the ability to
provide different kinds of views on a single set of data. In
the case of the HWX Browser, this could mean showing both
the line drawing of a character as well as its hexadecimal
representation in memory (to examine the data compression
method, or for debugging purposes).

Due to time constraints and our close-to-the-ground
approach, we did not implement this feature in our native
Windows version of this application.  Nor is this a
requirement for other implementors. It is a suggested
option, for those "real" frameworks whose design allows this
feature to be added easily.  We'll provide the function that
returns a pointer to the binary data, as well as sample code
for generating a hex string from binary data (see the
section later in this document, "What DDJ Will Provide").


DEBUGGING


Debugging support is not an application-level component per
se, in that it does not find its way into a shrink-wrapped
box or the feature list for the completed application.
Nevertheless, it is important issue from the application
developer's point of view. Although no mainstream frameworks
include debugging support as part of their definition, it is
instructive to note that the framework's spiritual ancestor
(Smalltalk-80) offered extensive support for debugging in
terms of a trace window and object inspector. It is our view
that eventually most DOS/Windows frameworks will incorporate
some facilities for debugging.  Because at present they do
not, this feature is entirely optional, for "extra credit".

OTHER  "EXTRA CREDIT"

If any vendors feel that their product has unique features
that are not demonstrated by the example application
requirements, they are free to add these features to their
implementation, and let readers judge for themselves.

Examples of additional features may include:
     1. special dialogs or controls, such as a color wheel
for color
     selection, or a slider for size specification
     2. resizable toolbars or tool palettes
     3. animated About box, and so on.
     4. spreadsheet-like view of the sampled data (see
"Character Display" above).


WHAT DDJ WILL PROVIDE

We'll supply the data files and the specification for the
file format.  We'll also supply functions to read the data
from the disk into an in-memory data structure, and other
functions to display a letter on the screen using MoveTo( )
and LineTo( ) callback functions.

In addition to providing the sample data files, we will
provide C code that implements the following workhorse
functions:

*     LoadHWXData(fileName)
      Given a filename, allocates memory and reads data from
      diskfile into an in-memory data structure, and returns
      a handle to this data.

*     RegisterCallback(displayEntity, pMoveTo, pLineTo)
      This function is passed a handle to a display entity (a
      window, canvas, grafport or equivalent concept), and
      pointers to two callback functions.  The callback
      functions are graphics primitives that are equivalent
      to MoveTo() and LineTo() in the Windows GDI.

*     GetInstanceCount(charCode)
      Given the ascii code for a character, return the number
      of instances loaded into memory for this character.

*     DisplayInstance(charCode,instanceNumber)
      Given the ascii code for a character, and a number for
      a particular instance of this character (enumeration
      begins at 0), display the character by using previously
      specified MoveTo and LineTo callback functions.

*     GetInstanceData(charCode,instanceNumber,pNumberOfBytes)
      Given the ascii code for a character, a number for a
      particular instance of this character (enumeration
      begins at 0), return a pointer to this instance data
      (for purposes such as a hex dump). Also return the
      number of bytes in this instance data, by placing a
      value in a variable whose pointer is passed to this
      function.

*     UnloadHWXData()
      Upon program exit or termination, free up any resources
      allocated earlier.

The specification for the functions listed above is not
quite exact. There are minor variations between the DOS and
Windows versions.  The DOS versions use pointers (large-
model far pointers), while the Windows versions use handles
from which pointers can be obtained. Consult the actual code
for the exact versions.

Note that implementors are free to change the code to their
liking, as long as functionality is preserved (by basic
functionality, we mean accessing the character data so it
can be displayed).  We won't be offended if our C code is
replaced entirely, if this makes things easier for the
implementor. Our approach currently suffers from a design
flaw in that the entire file of data must be read in before
it can be processed; in building an industrial-strength
application, such a constraint would be unacceptable.

The file structure is described in Appendix A, and the in-
memory structure is described in Appendix B.


WHAT THE SPEC LEAVES OUT

Although we've tried for a representative selection rather
than a comprehensive exercise of all features, it's
important to note what the spec leaves out. Our focus is on
the single-user, graphics-oriented application.  Our example
does not do anything related to text-editing,  multi-form
data entry, database access, or multi-user processing. These
are important aspects of many real-world applications in the
enterprise, and will hopefully be covered in a future round.

Even given the limited domain of the application, there are
functions used by many single-user interactive graphics
applications that our spec does not address. For example:
cut, copy, paste, selection by pointing, raster image data,
and the all-important undo command.  In homage to real-world
randomness, we'll have to leave these for another time.


THIS IS NOT AN EXAM

This is not a programming exam in the sense that there are
trick questions or hidden problems to solve.  We're only
interested in looking at the final result, in understanding
what it took to get there, and in discussing the
technological issues surrounding frameworks, class libraries
and GUI toolkits.  Also, we hope this will all provide some
good fun.

If this spec leaves out any information, it's by accident
rather than design. If you have any questions, please do
call, rather than attempting to jump through unnecessary
hoops.


FOR FURTHER INFORMATION

If you have any questions, please don't hesitate to contact:

     Ray Valdes, Senior Technical Editor
     Dr. Dobb's Journal
     411 Borel Avenue, Suite 100
     San Mateo, CA   94402

     (415) 358-9500 x314



____________________________________________________________

APPENDIX A: THE FILE STRUCTURE

The handwriting data is stored in files that contain
multiple sampled alphabets. Within the file, the multiple
versions or instances of each letter are organized by ASCII
character code rather than by alphabet.  Generally, each
file contains the handwriting samples belong to one person.
For each person, there may be ten or twenty different
alphabets in their file.

Our DDJ implementation of HWX BROWSER first reads all
information from the data file into an in-memory data
structure, before allowing access to individual characters.

Implementors are free to rewrite the functions we provide,
as long as the basic functionality is preserved: accessing
the character data from the file and displaying it.

The character data file is a binary file, consisting first
of a signature word, then a small header, followed by the
rest of the data.  The digitized stylus points in the
handwriting samples consist of two 16-bit signed integers,
one for the x-coordinate and the other for the y-coordinate
(there is no time stamping, pressure or angle information in
the data stream). The data as stored in the file is kept in
a very simple compressed form. The simple compression scheme
stores the first point in a stroke as a full pair of 16-bit
integers. Subsequent points in that stroke are stored as 8-
bit deltas off the original point (no provision is made for
overflowing the range of 8-bit displacements).

The units and coordinate system used in the data is whatever
is used by our Wacom 510C digitizing tablet, approximately
200 dots per inch.  In the DDJ implementation, we divide the
coordinate values by 8 in order to display them on a VGA
screen.  For future versions, we plan to put appropriate
metrics into the file header, to handle a range of devices.

The file header consists of a file signature followed by 32
bytes (sixteen words) of mostly unused header (reserved for
future use). The file signature value is 0x2121 and is not
considered part of the header.  The first word following the
signature value contains the size in bytes of header. In the
current version, it must be 32. This value includes the size
of the header-size variable. This is followed by two words,
one for the major version number (currently a value of 1),
the second contains the minor version number (currently a
value of 0). The remaining bytes are unused.

The following code excerpt shows how to read the file
header. It reads in the values without doing anything with
them -- for example, error checking. The actual code does a
little bit, but not much more.

Here is the excerpt:

void ReadHeader(FILE *data_file)   // function to read datafile header
  {
      extern int  ReadWord(FILE *);  // calls func to read a 16-bit word

      int signature,header_size,version_major,version_minor;

      signature = ReadWord(data_file);   // signature value is 0x2121
      header_size = ReadWord(data_file);// Number of bytes in header
      header_size >>= 1;               // Bytecount becomes wordcount
      header_size--;   // Subtract the word we just read from hdr size
      version_major = ReadWord(data_file); //Get version num (major #)
      header_size--;   // Subtract the word we just read from hdr size
      version_minor = ReadWord(data_file); //Get version num (minor #)
      header_size--;   // Subtract the word we just read from hdr size
      while(header_size--)   // Read the remaining bytes in the header,
            ReadWord(data_file);   // which now consists of unused words
  }

Character data is stored in arbitrary ASCII order,
identified by ASCII character codes, which range from 0 to
MAX_CHARS (which is #defined to have a value of 127). For
each character, there can be a variable number of character
prototypes (sample characters or instances).  Each character
prototype, also known as a gesture, is composed of a
variable number of strokes. Each stroke is composed of a
variable number of points.  The process of reading in the
data therefore consists of several nested for-loops -- to
read the characters, prototypes, strokes, and points,
respectively.

The following code excerpt shows how to read the data file.
The code in the excerpt calls the previously shown
ReadHeader() function.

void ReadDataFile(char *inputFileName) // function to read data file
{
    extern void OpenInputFile(char *); // this opens the input file
    extern void ReadHeader(FILE *);    // this reads the file header
    extern int  ReadWord(FILE *);      // this reads in a 16-bit word
    extern int  EndOfFile(FILE *);     // this checks for end-of-file
    extern void CloseInputFile(void);  // this closes the input file

    extern void ShowPoint(Point *);  // this routine displays a point

    Point Point;         // a struct that holds an (x,y) coord pair
    FILE *inputFile;     // compatible with fopen()

    int   ascii_code;    // the ascii code for current character

    int   cur_instance,cur_stroke,cur_pt;   // used in nested for loops
    int   num_instances,num_strokes,num_pts;// used in nested for loops

    // open the data file for input (note that in this example,
    // routines do not error-check return values; see actual code
    // for proper error-checking)
    inputFile = OpenInputFile(inputFileName);

    ReadHeader(inputFile);       // read the header of the data file

    while (! EndOfFile(inputFile))  // read in variable num of records
    {
          ascii_code    = ReadWord(inputFile);
          num_instances = ReadWord(inputFile);

          if(ascii_code > MAX_CHARS)  // if this has a value of > 127
                   break;             // then stop reading the file
     
          /*--------------Read in the instances-------------------*/
          for (cur_instance= 0;
               cur_instance < num_instances;
               cur_instance++)
          {
              num_strokes = ReadWord(inputFile);

              /*--------Read in the strokes for this instance-------*/
              for (cur_stroke = 0;
                   cur_stroke < num_strokes;
                   cur_stroke++)
              {
                    num_pts = ReadWord(inputFile);

                    // read in the first point
                    Point.x = ReadWord(inputFile);
                    Point.y = ReadWord(inputFile);

                    ShowPoint(&Point);

                    /*--------Read in subsequent points-------*/
                    for (cur_pt = 1;
                         cur_pt < num_pts;
                         cur_pt++)
                    {
                         int word;
                         char *ptr;

                         // read in a word and unpack it
                         word = ReadWord(inputFile);
                         ptr = (char *)&word;

                         // the delta-values apply to previous point
                         Point.x += ptr[1];
                         Point.y += ptr[0];

                         // display the point
                         ShowPoint(&Point);

                    }/*points for-loop*/

               }/*strokes for-loop*/

        } /*instances for-loop*/

    }/*while-loop*/
    CloseInputFile();  // all done
}

____________________________________________________________

APPENDIX B: THE IN-MEMORY STRUCTURE

Variable length information read from the file is stored in
an in-memory data structure.  In DOS, this is an array of
pointers to variable-length List structures.  In Windows,
this is an array of handles to variable-length List
structures.

The List structure is declared as follows:

    typedef void *GenericType;      // arbitrary type
    typedef struct
    {
         int           num_items;   // number of items in list
         GenericType   items[1];    // variable length array
    }  List;

    typedef   List far *   lpList;  // far pointer to a list structure
    typedef lpList far * lpLpList;  // pointer to pointer to list

Note that although this is called a List structure, it is
more properly known as a variable length array.  There are
no link pointers. Nevertheless, the usual list operations
(such as car, cdr, cadr and so on) can be accomplished on
this variable-length array.

In DOS, the List structures are constructed using malloc(),
calloc() and realloc().  They are freed using free().  In
Windows, the API memory management routines are called.

To illustrate how the character instances are accessed, here
is a code excerpt that frees up the list of lists:

void FreeMemStructures(void)
{
    int i,j,k;

    for (i = 0;
         i < MAX_CHARS;     // MAX_CHARS is #defined to be 127
         i++)
    {
        if (CharData[i])    // if the pointer is not null
        {                   // then get each member of the list
            for (j = 0;
                 j < CharData[i]->num_items;
                 j++)
            {
                 // access the sublist that hangs off current element
                 lpList L = CharData[i]->items[j];
                 for (k = 0;
                      k < L->num_items;
                      k++)
                 {
                       mem_Free(L->items[k]);
                 }
                 mem_Free(L);
             }
             mem_Free(CharData[i]);
             CharData[i] = NULL;
         }
    }
}

In Windows, the code is more complicated, because it uses
Windows3-compatible handles rather than pointers, and does
not use realloc().  The results are, however, effectively
the same.

END OF APPENDIX B
================================================================
