JCore
Version 1.0.0

Reference Manual

(c)1996-97 by John Lindal

Disclaimer

    JCore was originally conceived for my own personal use.  As it evolved, it
became apparent that others could also benefit from using it.  I make no
guarantees as to how well it works or how stable it is other than that it works
for me and that I have written so much code that depends on it that I am
unlikely to make major modifications without a really strong reason.  The file
JCoreLibVersion.h defines the current version of the library and contains
comments describing all the changes from previous versions.

    If you find errors, need documentation on something that has been left out,
or find something to be confusing, please let me know so I can fix the problem.
My email address is jafl@alice.wonderland.caltech.edu.

Availability

    JCore is available via anonymous ftp as part of the JX distribution:

    http://www.cco.caltech.edu/~jafl/jx/download.html

Sample code

    Sample code is included with the JCore library.  For each major class in
JCore, there is a separate, stand-alone program that exercises all the features
of the class.

Mailing lists

    The discussion mailing list provides a way for users to share ideas,
problems, and solutions.  I try my best to follow the discussions and provide
the best possible answers to questions.  To subscribe or unsubscribe, send email
to majordomo@cco.caltech.edu with a message saying "subscribe jx" or
"unsubscribe jx".  To send a message to the list, send email to
jx@cco.caltech.edu.

    The announcement mailing list provides a way to listen for new versions
without having to wade through the discussions.  To subscribe or unsubscribe,
send email to majordomo@cco.caltech.edu with a message saying "subscribe
jx-announce" or "unsubscribe jx-announce".  You cannot send messages to this
list.

Legal stuff

    JCore is not public domain.  The library and associated documentation files
(the "Software") are copyright (c) 1994-97 by John Lindal and Glenn Bach (the
"Authors").

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

The Software is distributed under the SYPP license:

Preamble

    In an ideal world, all software would be free.  In the real world, however,
most people cannot afford to give away what they create because they do not have
sufficient income from other sources.

    Shareware is the accepted compromise for stand-alone programs.  Users only
have to pay if the software is useful.  SYPP provides an equivalent compromise
for libraries of code by asking the program's author to share the profits from
the program with the library's author.

License

*    The Software is free for non-commercial use.

*    Any commercial or government use of the Software must be accompanied by a
license agreement.

*    In the special case of a shareware program, one is only required to pay a
one-time library shareware fee for the Software and only after the program has
brought in 10 times as much as the library shareware fee.  (This means that one
only needs to pay when the program is successful, thereby avoiding any financial
risk to the shareware author.)

*    The Software may be freely redistributed in its original form.  If you make
modifications to the Software you may not redistribute it without express,
written consent from the Authors.

    The official text of the SYPP license is on the World Wide Web:

     http://www.cco.caltech.edu/~jafl/sypp/

    The above copyright notice and this text shall be included in all copies or
substantial portions of the Software.

Table of Contents

Introduction

    5    About this Manual
    5    Design Philosophy
    6    Cross-platform operation
    7    Data types
    7    Other conventions

Library components

    8    JBroadcaster
    9    JString
    9    JCollection
    9    JOrderedSet<T> and friends
    10    JContainer

    11    Instantiating templates

    12    JFileArray
    13    JPrefsFile
    14    JPainter
    15    JFontManager
    16    JTable

    19    UNIX pipes

    19    Utilities
    19        jstreamUtil.h
    20        jfstreamUtil.h
    20        jfstreamOpenModes.h
    20        jstrstreamUtil.h
    21        jfileUtil.h
    21        jdirUtil.h
    22        jmath.h
    23        jrandom.h
    23        jtime.h
    23        jsignal.h
    24        jmemory.h
    24        jerrno.h

    25    User Interface

About this Manual

    This manual was written to provide an overview of the JCore library.
Function level documentation can be found in the doc directory in the official
distribution.  In case of a conflict with this manual, the function level
documentation should be considered correct.

Design Philosophy

    JCore was built on the principle that code can and should be written to
never crash.  C++ exceptions are therefore not supported at all.  (For some of
the many reasons why, read More Effective C++ by Scott Meyers, ISBN
0-201-63371-X.)  Instead, non-fatal problems are dealt with by returning a
boolean value to indicate success or failure.  Fatal problems are caught via the
assert() macro.
    By fatal problems, I mean actions like attempting to access an element
outside the boundaries of an array.  This is truly fatal.  Trying to exit
gracefully (e.g. letting the user save their data before quitting) is impossible
because something has been seriously corrupted and the user would be a fool to
trust anything written out by the program after the error occurred.  If code is
written to be able to gracefully deal with a thrown exception in such cases,
then the programmers should be shot because they should have redesigned the code
to avoid the condition instead.
    Non-fatal problems are situations like trying to convert the string "hello"
to a number.  The function will simply return kFalse.  If this is a string
entered by the user, the problem can very easily be dealt with by printing an
error message and asking the user to re-enter the information.  If it is a
string read from a file, treat it like a string entered by the user since the
file could get corrupted.  If it is a string that is compiled into the program,
use assert() to check that the function succeeds because it really would be a
fatal error in this case.  (Of course, one really should just use a numeric
constant instead.)

    Some will argue that using assert() makes software crash prone instead of
crash proof since assert() always crashes the program.  However, I believe that
if one knows that the code will crash on any error, then this simply provides
incentive to design the system correctly the first time.  I also dismiss the
argument that "What if the user creates some special condition that wasn't
debugged because it was too rare to get tested and then the program crashes?"
The design isn't finished until every possible case has been considered, and the
code is not finished until it has been tested under every possible condition.
Your manager may hate you for missing deadlines, but you're doing him and the
company a favor in the long run when you design and construct solid code.

    When writing code, it is best to #include <jassert.h> instead of <assert.h>
because one can rewrite the macro in jassert.h to call one's own function.  As
an example, in a graphical environment, one might want to display a dialog
window giving both information about the crash and information about how to
report it and get it fixed.
    One must also remember to #include <jassert.h> as the last #include in the
source file so that the correct definition of assert() is used.  All assert.h
files throw out any previous definition of assert() before defining their own.
    As a final reminder, never do actual work inside an assert() because the
production version of the code will probably #define NDEBUG which will kill all
assert()'s and everything inside them.  You will effectively lose code.  This
will be nearly impossible to track down because the debug version will work
correctly.

Cross-platform operation

    JCore was written to work with any ANSI compliant C++ compiler.  (Not that
there ever will be such a thing.)  This would seem to preclude any graphical
user interface (GUI) classes since such code is usually system specific.
However, since the basic equipment, such as a keyboard and a mouse, is available
on all systems, it turns out that most of the work can actually be done by
system independent code.  The trick is to join the system dependent event
dispatching code and the system independent event processing code by using
multiple inheritance:



    The event router inherits from both the event dispatcher and the event
processor.  The arrows in the diagram show the flow of events.  The system
generates events which are caught by the event dispatcher.  The event
dispatcher's functions are declared virtual, so the event router's
implementation of these functions is called.  These functions interpret the
events and call the appropriate functions in the event processor.

    The Text Editor and the Table suite are good examples of this style of
programming.  They provide all the code required to store the data and keep the
display synchronized with the data and leave the issues of scrolling and
catching mouse clicks to be implemented by system dependent, derived classes.

    Currently, the JX library (ftp://ftp.pma.caltech.edu/pub/users/jafl/jx/)
implements the JCore classes for X Windows.  A JL library for Windows95 is under
development.  If anyone is interested in using the JCore classes with other
systems, please contact me.

Data types

    All intrinsic data types are shielded by typedefs to make them system
independent.

    JCharacter    characters
    JInteger    signed integers
    JFloat    floating point
    JSignedOffset    offsets that can be positive or negative
    JUnsignedOffset    offsets that can only be positive or zero
    JBoolean    boolean (kTrue, kFalse)
    JIndex    1-based indexing system
    JSize    size of something (nonnegative)

    JBoolean is an enum with values kTrue and kFalse.  Since comparisons always
return int's which cannot be converted to enum's, ConvertToBoolean() is provided
to perform the conversion safely.  This is a pain, but the intrinsic type bool
will eventually be widely supported, at which point JBoolean will become a
typedef and ConvertToBoolean() will become obsolete.

    JIndex represents a 1-based indexing system, and all functions that take
arguments of this type conform to this convention.


Other conventions

    Passing by value, reference, and pointer is used to distinguish what will be
done with the data.  Intrinsic data types are passed either as const values or
as pointers.  Objects are passed either as const references or as pointers.
When something must be passed as a pointer, it means that it will be modified.
I have tried my best to avoid passing by non-const reference.

    The issue of who owns a particular object after a "set" method has been
called is also settled by how the object is passed to the "set" method.
x.SetElement1(const T& y) means that SetElement1() makes a copy of y.  If y was
allocated on the heap, it must be deleted by the caller.  x.SetElement2(T* y)
means that x now owns y and will delete it when it no longer needs it.  In this
case, the caller must not delete y.  It is also an error in this case to
allocate y on the stack, because then y will be deleted twice: when the calling
function returns and when x is finished with it.  I have tried my best to write
methods like SetElement1() whenever possible.  Methods like SetElement2() are
used only when copying is too expensive to be reasonable.

    When a value is returned by a "get" method, it is sometimes a const
reference.  This saves time if all one needs to do is look at the value.  One
should not assume that such references will remain valid, however, so one should
only use such references locally inside a function.  If one needs to store the
value for a longer period of time, one should store a copy of the value rather
than the reference.

JBroadcaster

    One major advantage provided by object oriented programming is that data can
be decentralized and encapsulated inside objects.  This presents a serious
problem for large programs, however, because data stored in different objects
has to be kept in sync.  Writing custom code to handle each such dependency is a
terrible solution because it means that none of the code will be reusable in
other projects and often also requires that code be duplicated because the
dependencies have to be dealt with in private methods which requires a separate
copy of the class for each set of dependencies.

    JBroadcaster provides a much better solution by defining a protocol that
objects can use to send messages to each other.  To use this system, the class
that sends the message and the class that receives it must both be derived from
JBroadcaster.  To send a message, call Broadcast().  To receive a message, an
object must first call ListenTo() to begin listening for messages and then
override Receive() to receive and process each message.  StopListening() can be
used to stop listening for messages.

    All messages are classes and must be derived from JBroadcaster::Message.  It
is up to each class to define a useful set of messages.  Each message should
contain whatever information is required to process it.  Messages can also
provide methods for performing the default response.  Refer to the messages
defined by JOrderedSet for examples (e.g.
JOrderedSetT::ElementInserted::AdjustIndex()).

    It must be mentioned that just because JBroadcaster is easy to use does not
mean that messages are easy to use.  Objects that communicate via messages
essentially form a distributed system, and computer scientists will gladly point
out how careful one must be in order to get such a system to work flawlessly.
(In the case of JBroadcaster, messages are received immediately after they are
sent, but the order in which listeners are notified is undefined.)
    One particularly dangerous case is a message that is broadcast from within a
destructor.  The best advice is to avoid this at any cost, because objects can
depend on themselves, or they can depend on objects that they own and that they
therefore delete in their destructor.  In both cases, calling Receive() while
the object is being destructed is usually fatal.
    Another deadly possibility is that the message might cause one of the
listeners to delete the sender.  (This will not cause problems if Broadcast() is
the last action before returning because then this will not be referenced after
the message has been sent.)  This often occurs with a "Close window" menu item.
The object that receives the message deletes the window and everything in it,
including the menu that broadcast the message.

JString

    JString was written before C++ got a standard string class, and provides
essentially the same functionality, except for operator[] since JString uses
1-based indexing.  It is easy to construct one from the other because each can
be constructed from the other's char*.  It is important to remember that char*
implies a null-terminated array of characters.

JCollection

    This is the base class for all classes that are primarily collections of
other objects.  It provides IsEmpty() and GetElementCount().

JOrderedSet<T>

    This abstract template class defines the interface for all ordered sets
(arrays, linked lists, run arrays, etc) and a set of messages for notifying
other Broadcasters of changes.  It also defines a set of efficient sorting
functions.

JOrderedSetIterator<T>

    This template class provides a robust way to iterate over the elements in an
OrderedSet.  Next() returns kTrue if there is a next element, and similarly for
Prev().  Using an Iterator in a while loop is more robust thancalling
GetElement() in a for loop because Iterators are automatically notified of
changes to the OrderedSet.  Specifically, they adjust themselves as appropriate
when elements are inserted or removed so they will never accidentally attempt to
access non-existent elements.
    In addition, an iterator can also be faster that using GetElement() in a for
loop.  The time required by GetElement() can be proportional to the element's
index.  An iterator can bypass this if it is tightly coupled with the class that
stores the data.  To get the best iterator for a given OrderedSet, use
NewIterator().
    Note that for Arrays, GetElement() requires constant time, so there is no
need to use an iterator in this case unless the code inside the loop will have
unpredictable effects on the elements in the array.

JArray<T>

    This template class implements a bounds checked, 1-based array of elements.
It does not understand copy constructors, however, so it should only be used for
intrinsic data types and structs of intrinsic data types.  Objects should be
stored in JPtrArray's.
    In general, storing an array of objects (as opposed to an array of pointers)
is dangerous because operator= is not virtual.  This is discussed at length in
More Effective C++.

JPtrArray<T>

    This template class implements a bounds checked, 1-based array of pointers.
It is designed to store lists of objects, and provides DeleteElement() and
DeleteAll() for automatically disposing of the objects when they are removed
from the list.  (For objects allocated with operator new[], use
DeleteElementAsArray() and DeleteAllAsArray() instead so that operator delete[]
is called.)  Use RemoveElement() to remove an object from the list without
deleting it.  (Somebody else must then delete the object elsewhere.)

JLinkedList<T>

    This template class implements a bounds checked, 1-based, doubly linked list
of elements.  As with JArray, JLinkedList does not understand copy constructors,
however, so it should only be used for intrinsic data types and structs of
intrinsic data types.  Objects should be stored in JPtrArray's.  It is doubly
linked so that iterators can efficiently traverse it in either direction and the
worst time for GetElement() is (# of elements)/2.

JRunArray<T>

    This template class implements a bounds checked, 1-based, compressed list of
elements.  Compression is acheived by storing "runs" of equal elements as a
single pair {# of elements, value}.  As with JArray, JRunArray does not
understand copy constructors, however, so it should only be used for intrinsic
data types and structs of intrinsic data types.  Objects should be stored in
JPtrArray's.

JQueue<T>

    This template class implements a first-in-first-out queue of elements.  As
with JArray, JQueue does not understand copy constructors, however, so it should
only be used for intrinsic data types and structs of intrinsic data types.
Objects should be stored in JPtrQueue's.

JPtrQueue<T>

    This template class implements a first-in-first-out queue of pointers to
objects.  It provides FlushDelete() and DiscardDelete().

JStack<T>

    This template class implements a first-in-last-out stack of elements.  As
with JArray, JStack does not understand copy constructors, however, so it should
only be used for intrinsic data types and structs of intrinsic data types.
Objects should be stored in JPtrStack's.

JPtrStack<T>

    This template class implements a first-in-last-out stack of pointers to
objects.  It provides ClearDelete() and UnwindDelete().

JContainer

    Most classes that qualify as Collections will store their data privately in
Arrays or PtrArrays and then implement wrappers and additional methods to access
and manipulate the data.  In order to keep GetElementCount() for the class in
sync with GetElementCount() for the internal data, one should derive the class
from JContainer and then call InstallOrderedSet() in the constructor.
JContainer will then insure that the element counts stay in sync automatically.

Instantiating templates

    Files ending in .tmpls are provided to simplify the process of instantiating
templates.  Each such file contains a header explaining how to use it.  As an
example, to instantiate JArray<JBoolean>, the file JArray-JBoolean.cc contains
the following code:

    #include <JBoolean.h>
    #define JTemplateType JBoolean
    #include <JArray.tmpls>

    To instantiate JPtrArray<JString>, the file JPtrArray-JString.cc contains
the following code:

    #include <JString.h>
    #include <JArray.tmpls>
    #define JTemplateType JString
    #include <JPtrArray.tmpls>

    This code can be copied and used to instantiate any other type of Array or
PtrArray.  Each such instantiation must be in a separate file.

JFileArray

    This class implements an array stored in a file.  All data is stored as
ascii text and is transferred via strstream and JStaticBuffer objects.  Each
element of the array can have an arbitrary size.  A FileArray can be embedded
within another FileArray by storing all the embedded file's data inside one
element of the enclosing file.  The single base file object is initialized with
the file specifications.  An embedded file object is initialized with the file
object that contains it and the ID of the element that contains it.  Embedded
files must be opened after the base file and must be closed before the base
file.

    Each element in a FileArray can be referenced either by its index or its ID.
The index gives the logical ordering of the elements in the file.  (The physical
ordering may be very different since JFileArray is optimized to work with a slow
disk.)  The ID of each element is guaranteed to be unique and to remain the same
regardless of how the item's index changes.  Thus, an ID provides a way to keep
track of an element, regardless of how the elements are rearranged.  JFAIndex
and JFAID were created in order to allow function overloading so that an element
can be accessed via either its index or its ID.

    Storing and retrieving data is quite simple.  The following code creates a
new element at index 1:

    ostrstream dataStream;
    dataStream << 5 << ' ' << 3;
    theFileArray.PrependElement(dataStream);

    The following code retrieves the data from element 1:

    JFAIndex index = 1;
    JStaticBuffer data;
    theFileArray.GetElement(index, &data);
    istrstream dataStream(data);
    dataStream >> x >> y;

    The advantage of sending the data to the FileArray via an ostrstream is that
it provides a simple way to package many pieces of information into one element
of the file.  The only reasonable way to retrieve the data is to use an
istrstream.  By allocating the ostrstream, the JStaticBuffer, and the istrstream
on the stack, one never has to remember to delete anything.  This provides
protection against memory leaks.  (JStaticBuffer is essentially a "smart
pointer," as discussed in More Effective C++.)

    One important restriction when working with FileArrays is that no two
FileArray objects can open the same file.  This is because FileArray objects are
optimized for use with a slow disk and therefore do not keep the data on the
disk up to date.  The file is only complete after it is closed.
    I am still looking for a cross-platform way to enforce this restriction.
flock() won't work because it is often impossible to get the file descriptor
associated with an fstream object.  (gcc is more lenient than most about this.)
If you have any suggestions, please let me know.

JPrefsFile

    This is the base class for managing a preferences file.  Derived classes
(e.g. JUNIXPrefsFile) must provide a location for the file.  Thus, creating a
JUNIXPrefsFile object only requires specifying a file name, not the full path.

    Each item in a PrefsFile is referenced by an ID.  This id is specified when
the item is created, and must be unique.  The id is the only guaranteed way to
get at the data after it is created.  JPrefsFile is derived from JFileArray, so
the code for storing and retrieving data is identical to that for FileArrays,
except that the methods provided by JPrefsFile should be called instead.

    Since multiple copies of a program can run simultaneously, and since
FileArray objects cannot share a file, it is an error to create a PrefsFile and
leave it open.  The correct way is to open the PrefsFile every time it is
needed.  If this is too slow, store the preferences in memory and save them when
the program quits.

JPainter

    This class abstracts the functions required to draw to the screen and to a
printer.  It supports drawing text and the standard shapes (with filling), a
clipping rectangle, an adjustable drawing origin, and a pen location, line
width, and pen color.

    Derived classes must implement the following routines:

SetClipRect

    Set the rectangle that drawing will be clipped to.  Call
JPainter::SetClipRect().

String

    The first version draws text horizontally inside the specified rectangle
with the specified horizontal and vertical alignment.  The second version draws
rotated text.  This routine is only required to handle rotations of 0, 90, 180,
and 270 degrees.

Point

    Draw a point.

Line

    Draw a line between the two specified points.  Call SetPenLocation() with
the ending point.

Rect

    Draw the specified rectangle.  If IsFilled() returns kTrue, fill the
rectangle.

Ellipse

    Draw an ellipse inside the specified rectangle.  If IsFilled() returns
kTrue, fill the ellipse.

Arc

    Draw the specified arc inside the specified rectangle.  startAngle follows
the usual convention of zero degrees on the positive x-axis and increases
counterclockwise.  deltaAngle tells how much of the arc to draw (in degrees) and
is positive in the counterclockwise direction.  If IsFilled() returns kTrue,
fill the ellipse as a pie slice.

Polygon

    Draw the specified polygon, including the closing line from the last vertex
to the first vertex.  top and left specify the offset of the vertices relative
to the current origin.  If IsFilled() returns kTrue, fill the polygon.

Image

    Draw the portion of the image specified by srcRect into the given destRect.

JFontManager

    This class abstracts the interface for accessing fonts.  Derived classes
must implement the following routines:

GetFontNames

    Return an alphabetical list of all the available font names.

GetFontSizes

    Return minimum available size, maximum available size, and a sorted list of
all the available font sizes for the given font name.  If all font sizes are
supported (e.g. Macintosh TrueType), return a reasonable min and max, and an
empty list of sizes.  Return kFalse if there is no such font.

GetFontStyles

    Return JFontStyle with available styles set to kTrue.  Because they are easy
to implement in JPainter, underline, strike, and colors are always available.

GetFontID

    Return a system dependent handle to the specified font.  This routine is
responsible for finding the best approximation if the specified font is not
available.

GetFontName

    Return the name of the font with the given id.

GetLineHeight

    Return the height of a line of text, including separate values for ascent
and descent.

GetStringWidth

    Return the width of the given string.

GetCharWidth

    Return the width of the given character.

JTable

    The purpose of a Table class is to display a two dimensional arrangement of
items.  Each item is displayed in a separate cell of the table.  Items are
referenced by giving the row index and column index.  Each row can have a
different height, and each column can have a different width.

    The Table suite is designed according to the Model-View-Controller paradigm.
A TableData object provides the Model by storing the data to be displayed.  A
Table object provides the View and updates itself automatically based on
messages received from the TableData object.  As discussed in the section on
cross-platform operation, system dependent derived classes are written to handle
mouse clicks, key presses, etc.  These derived classes implement the
Controllers.

    JTable and JTableData provide the foundation for JCore's Table suite.  When
a pair of JTable and JTableData objects are used in a program, the correct
procedure for modifying the data is always to call methods in JTableData.
JTable will then adjust itself automatically because it is designed to operate
transparently with any object that follows the JTableData message protocol.
These messages are described below.  (In order to keep JTableData's row and
column counts up to date, when one broadcasts the message, one must also call
the indicated function.)

    Message    Action
    RowChanged    The elements in a row have changed
    RowInserted    A new row was inserted (also call RowAdded())
    RowDuplicated    A row was duplicated (also call RowAdded())
    RowRemoved    A row was removed (also call RowDeleted())
    AllRowsRemoved    All the rows were removed (also call SetRowCount(0))
    RowMoved    A row was moved to a new location

    ColChanged    The elements in a column have changed
    ColInserted    A new column was inserted (also call ColAdded())
    ColDuplicated    A column was duplicated (also call ColAdded())
    ColRemoved    A column was removed (also call ColDeleted())
    AllColsRemoved    All the columns were removed (also call SetColCount(0))
    ColMoved    A column was moved to a new location

    ElementChanged    The information in a cell was changed

    The most common uses of JTableData are provided as part of JCore.  The
JValueTableData template is designed to store a dense matrix of values or
structs.  Just like JArray, this class cannot handle anything that requires a
copy constructor, however.  For true classes, use the JObjTableData template.
This is designed to store a dense matrix of pointers to objects.  (Unlike
JPtrArray, this class owns all the objects that it stores.  i.e. GetRow() and
GetCol() return copies of the objects which must be deleted by the caller, and
SetRow() and SetCol() store copies of the objects that are passed in, so the
originals must be deleted by the caller.)  In order to store sparse matrices or
ragged-edge rows or columns, you must create your own class derived from
JTableData and follow the above protocol.

    The JAuxTableData template is designed to efficiently store a redundant
matrix of values by column.  This is often useful for storing style information
for a table that displays text in each cell.  Most cells will have the default
style, with a few cells displaying bold or italicized text.
JAuxTableData<JFontStyle> stores such information in a memory efficient way.
Every JAuxTableData object automatically links itself to the Table object that
is passed to the constructor, thereby insuring that it automatically stays in
sync with the Table and that the Table is redrawn whenever the data stored by
JAuxTableData changes.

    Since drawing to the screen is data dependent, you will always have to
create your own class derived from JTable to override TableDrawCell() and draw
the contents of each cell.

    JTable also provides routines for editing the data displayed in each cell.
Derived classes decide when to call BeginEditing(), EndEditing(), and
CancelEditing(), and then override the editing field manipulation functions
described below.  Normally, an edit field is a text input box.  However, since
JTable does not understand anything about the edit field object, it could just
as easily be a modeless dialog window instead.   One should call EndEditing()
before saving, printing, etc.

    JTable has its own set of messages that it broadcasts when it changes.
These can be used to keep several tables synchronized.  The most common examples
are row and column headers displayed to the right and at the top of the main
table.

    Classes derived from JTable must implement the routines described below.
Normally, all but TableDrawCell() will be implemented once (e.g. JMacTable or
JXTable) and all other table classes (e.g. JMacStringTable or JXStringTable)
will be derived from this class.

TableDrawCell

    Draw the contents of the given cell.  All drawing is automatically clipped
to the boundaries of the cell.  This can usually only be overridden by leaf
classes since it requires understanding the actual data.

TableSetGUIBounds

    The total size of the table has changed to the given width and height.

TableAdjustScrollSteps

    Adjust the step sizes used when scrolling the table.

TableScrollToCell

    Scroll the table to display the specified cell.

TableRefresh

    Redraw the entire table.

TableRefreshRect

    Redraw the specified rectangle (in pixels).

    Derived classes can also override the following routines:

TablePrepareToDrawRow

    DrawCell is about to be called for each cell in a row.  If some common
initialization needs to be done, do it here.

TablePrepareToDrawCol

    DrawCell is about to be called for each cell in a column.  If some common
initialization needs to be done, do it here.

    To use JTable's editing mechanism, a derived class must override the
routines described below.  Normally, all but ExtractInputData() will be
implemented once (e.g. JMacEditTable or JXEditTable) and all other table classes
that support editing will be derived from this class.

CreateInputField

    Create or activate an input field to edit the specified cell.

ExtractInputData

    Check the data in the active input field, and save it if it is valid.
Return kTrue if it is valid.

DeleteInputField

    Delete or deactivate the active input field.  Called when editing is
cancelled or when ExtractInputData() returns kTrue.

PlaceInputField
MoveInputField
SetInputFieldSize
ResizeInputField

    Adjust the position or size of the input field.

    To draw page headers and footers while printing, override the following
routines:

GetPrintHeaderHeight

    Return the height required for the page header.

DrawPrintHeader

    Draw the page header.  JTable will lock the header afterwards.

GetPrintFooterHeight

    Return the height required for the page footer.

DrawPrintFooter

    Draw the page footer.  JTable will lock the footer afterwards.

    To include row headers and column headers while printing, call
SetRowHeader() and SetColHeader().  JTable will then position and draw them
automatically.

UNIX pipes

    JInputPipe and JOutputPipe are provided to simplify the use of UNIX pipes.
Each is constructed with the shell command to be executed.  Since both are
derived from the appropriate stream classes, JInputPipe acts just like any other
istream, and JOutputPipe acts just like any other ostream.


Utilities

    Due to variations in the header files provided by various systems (notably
Sun's miserable, non-ANSI garbage) and the general stupidity of the ANSI
committees, some standard headers are overridden.  An an example, jmath.h should
be used instead of math.h because it provides round(), lfloor(), and lceil()
which the ANSI committee conveniently left out of the standard and jlabs() to
replaces labs() which Sun doesn't bother to implement.  The stream utilities are
especially useful because the ANSI committee has worked especially hard to
insure that the stream classes are a pain to use.


jstreamUtil.h

void CopyBinaryData(istream& input, ostream& output, const JSize byteCount);

Copies data between streams, treating the data as binary values instead of text.

JString Read(istream& input, const JSize count);

Reads count characters from the stream.

JString ReadUntil(istream& input, const JCharacter delimiter);

Reads characters from the stream until delimiter is reached.  delimiter is read
in and discarded.

JString ReadUntilws(istream& input);

Reads characters from the stream until white space is reached.  White space is
read in and discarded.

JBoolean ReadStringUntil(istream& input, const JSize delimiterCount,
                     const JCharacter delimiters[], JString* str,
                     JCharacter* delimiter);

Reads characters from the stream until one of the delimiters is reached.  The
character is read in, stored in *delimiter, and the function returns kTrue.  The
function returns kFalse if the end of the stream is reached before finding a
delimiter.

JString ReadLine(istream& input);

Reads characters from the stream until newline (\n) is reached.  Newline is read
in and discarded.

JString ReadAll(istream& input);

Slurps in the entire file.  Be careful, since the file could be huge!

void IgnoreUntil(istream& input, const JCharacter delimiter);

Discards characters from the stream until delimiter is reached.  delimiter is
read in and discarded.

JSize tellg(istream& stream);
void  seekg(istream& stream, streampos position);
void  seekg(istream& stream, streamoff offset, ios::seek_dir direction);
JSize tellp(ostream& stream);
void  seekp(ostream& stream, streampos position);
void  seekp(ostream& stream, streamoff offset, ios::seek_dir direction);

The ANSI standard seems to have discarded these functions.


jfstreamUtil.h

JString ReadFile(const JCharacter* fileName);
JString ReadFile(ifstream& input);

Slurps in the entire file.  Be careful, since the file could be huge!  These are
equivalent to ReadAll() in jstreamUtil.h, except that they are optimized to work
with ifstream.

fstream* OpenScratchFile();

Creates a new file and returns an fstream that operates on the file.

void CloseScratchFile(fstream** theFile);

Use this to correctly close an fstream and erase the file created by
OpenScratchFile().

JSize GetFStreamLength(ifstream& theStream);

Returns the length of the file associated with the given ifstream.

fstream* SetFStreamLength(const char* fileName, fstream& originalStream,
                      const JSize newLength, const JFstreamOpenMode io_mode);

Sets the length of the file associated with originalStream.  Since this
completely confuses originalStream, originalStream is closed and a new fstream
is returned.


jfstreamOpenModes.h

    Defines useful modes for opening fstream's:  kBinaryFile and kTextFile.
With so many changed to the stream classes over the years, each compiler seems
to have its own ideas about what these settings should be.  This file defines
them correctly for each supported compiler.


jstrstreamUtil.h

void Unfreeze(ostrstream& s);

Convenience function to unfreeze an ostrstream after using str().

jfileUtil.h

JBoolean FileExists(const JCharacter* fileName);

Returns kTrue if the specified file exists.

JBoolean FileReadable(const JCharacter* fileName);

Returns kTrue if the specified file can be read from.

JBoolean FileWritable(const JCharacter* fileName);

Returns kTrue if the specified file can be written to.

JBoolean GetFileModificationTime(const JCharacter* fileName, time_t* modTime);

Returns the time when the contents of the file were last modified.

JString GetTempFileName(const JCharacter* dirName = NULL);

Returns a file name that is guaranteed not to exist.  If dirName is NULL, the
file is guaranteed not to exist in the current working directory.  Otherwise,
the file is guaranteed not to exist in the directory specified by dirName.

JBoolean SearchFile(const JCharacter* fileName, const JCharacter* searchStr,
                  JIndex* lineIndex);

Returns the index of the first line in the specified file that contains
searchStr.


jdirUtil.h

JBoolean NameUsed(const JCharacter* name);

Returns kTrue if the specified name exists.  (file, directory, link, etc)

JBoolean DirectoryExists(const JCharacter* dirName);

Returns kTrue if the specified directory exists.

JBoolean DirectoryReadable(const JCharacter* dirName);

Returns kTrue if the specified directory can be read from.

JBoolean DirectoryWritable(const JCharacter* dirName);

Returns kTrue if the specified directory can be written to.

JDirError CreateDirectory(const JCharacter* dirName);

Returns kNoError if is was able to create the requested directory.

JDirError CreateDirectory(const JCharacter* dirName, const int mode);

Returns kNoError if is was able to create the requested directory with the
requested access permissions.

JDirError ChangeDirectory(const JCharacter* dirName);

Returns kNoError if is was able to change the current working directory to the
specified directory.

JDirError RemoveDirectory(const JCharacter* dirName);

Returns kNoError if is was able to remove the requested directory.  This will
only succeed if the directory is empty.

void KillDirectory(const JCharacter* dirName);

Guaranteed to delete the directory and everything in it.

JString GetCurrentDirectory();

Returns the full path of the current directory.

JBoolean GetHomeDirectory(JString* homeDir);

Returns kTrue if the user has a home directory.

JBoolean GetTrueName(const JCharacter* name, JString* trueName);

Returns kTrue if the file or directory specified by name exists.  If so,
*trueName contains the full path and name with all symbolic links removed.

JBoolean SearchSubdirs(const JCharacter* startPath, const JCharacter* name,
                     const JBoolean isFile, JString* path);

If isFile is kTrue, searches for the file with given name in the directory
subtree starting at startPath.  If isFile is kFalse, searches for the directory
with given name in the directory subtree starting at startPath.  If successful,
returns kTrue and sets *path to the full path to what it found.

JString OpenTempDirectory(const JCharacter* dirName = NULL);

Creates a new directory in the directory specified by dirName or in the current
working directory if dirName is NULL.

void CloseTempDirectory(const JCharacter* dirName);

Use this to correctly close a directory created by OpenTempDirectory().

JString CombinePathAndName(const JCharacter* path, const JCharacter* name);

Concatenates path and name, inserting the appropriate separator ('/' for UNIX)
if necessary.

void SplitPathAndName(const JCharacter* file, JString* path, JString* name);

Splits file into a path and name.

void AppendDirSeparator(JString* dirName);

Appends the appropriate separator ('/' for UNIX) to the end of *dirName, if
neccessary.


jmath.h

long round(const double x);

Rounds the given number to the nearest integer.

long lfloor(const double x);

Integer version of floor().

long lceil(const double x);

Integer version of ceil().

long jlabs(const long x);

Sun header doesn't define labs().

jrandom.h

    This set of functions provides a simple random number generator.

void Randomize();

Sets the random number seed to the current time.

void Seed(const long seed);

Sets the random number seed to the specified value.

long RndInt(long lim1, long lim2);

Returns a random integer uniformly distributed between the two specified limits.

double RndFloat(double lim1, double lim2);

Returns a random value uniformly distributed between the two specified limits.

double RndProb();

Returns a random value uniformly distributed between 0 and 1.

double Gaussian(const double mean = 0.0, const double sigma = 1.0);

Returns a random value distributed normally with specified mean and standard
deviation.


jtime.h

CLOCKS_PER_SEC is not defined in the Sun header.

void Wait(double delta);

Waits for the specified number of seconds in a multi-tasking friendly way.
Fractions of a second are allowed.

JString GetTimeStamp();

Returns the current time in the standard time stamp format.

JString ConvertToTimeStamp(const time_t t);

Converts the specified time to the standard time stamp format.


jsignal.h

sig_atomic_t is not defined in the Sun header.

typedef void (j_sig_func)(int);

Provides a nicer way to declare signal handlers.

jmemory.h

JCharacter* CreateBuffer(JSize* bufferSize);

Attempts to allocate a buffer of size bufferSize.  The pointer returned is
guaranteed to point to a valid block of memory, but the size may be less than
what was requested.  bufferSize is set to the actual size of the block.  This is
useful if a routine needs to allocate memory, doesn't care exactly how much, and
cannot afford to fail.


jerrno.h

    Augments errno.h to hide the fact that multi-threaded applications must call
a function to obtain the correct value of errno.

int jerrno();

Returns the value of errno.

void jclear_errno();

Clears the value of errno.

JBoolean jerrno_is_clear();

Returns kTrue if errno is empty.

User Interface

    JUserNotification and JChooseSaveFile define the interfaces for the global
objects gUserNotification and gChooseSaveFile that allow otherwise system
independent code to remain that way when only required to notify the user of an
error, ask the user a simple Yes/No question, or ask the user to open or save a
file.

    JProgressDisplay defines the interface for objects that display the progress
of a long calculation.  The global object gCreatePG should be used to create
such objects, because it will always create an object of the appropriate type,
based on the run-time environment.

    It is the library user's responsibility to create whichever global objects
are needed by the linker.  Typically, main() provides the storage for the global
objects (as pointers) and creates the appropriate type of each one.  For a
text-based user interface, the following code is all that is required:

    #include <JTextUserNotification.h>
    #include <JTextChooseSaveFile.h>
    #include <JCreateTextPG.h>

    JUserNotification*    gUserNotification;
    JChooseSaveFile*        gChooseSaveFile;
    JCreateProgressDisplay*    gCreatePG;

    int
    main
        (
        int   argc,
        char* argv
        )
    {
        gUserNotification = new JTextUserNotification;
        assert( gUserNotification != NULL );

        gChooseSaveFile = new JTextChooseSaveFile;
        assert( gChooseSaveFile != NULL );

        gCreatePG = new JCreateTextPG;
        assert( gCreatePG != NULL );

        <your code here>

        delete gCreatePG;
        delete gChooseSaveFile;
        delete gUserNotification;
        return 0;
    }

    jCommandLine.h provides two useful routines when writing a text based user
interface:  WaitForReturn() and InputFinished().  WaitForReturn() lets you pause
so the user can read what is on the screen.  InputFinished() is required after
every statement of the form "cin >> x;" because operator>> always leaves the
user's return keypress in the stream.  (Why they chose to do this is beyond me.)
If one does not call InputFinished(), this will confuse both WaitForReturn()
(which sees the return keypress and immediately returns) and keyboard input of
JString's (which are (sensibly) terminated by the user's return keypress, and
therefore think that the user entered an empty string).