NETSIM
C++
User's Manual
Table
of Contents
1.0 Introduction
2.0 Using NETSIM C++
3.0 Data Definition Language Files
4.0 Data Manipulation Language Syntax
5.0 Utility Variables and Methods
6.0 Interactive Debugger
7.0 Error Messages
1.0 Introduction
1.1 Overview of NETSIM
C++
The Network Database Simulator system in C++ (NETSIM C++)
simulates selected features of a network database management system. Using
NETSIM C++, you can create record
types, set types, and keeplists for a network database, and then manipulate
this database in the context of a C++ program. The system will translate your
type declarations and data manipulation commands into C++ code, which can then
be compiled by a C++ compiler.
NETSIM C++ includes several utility methods
(in C++) which you can include in your database programs. The system also
incorporates a debugging facility to assist you in tracking down errors in the
structure of your databases.
Note:
It is assumed throughout this manual that the user has a working
knowledge of C++ and of object orientation.
1.2 Network Database
Concepts
A network database consists of a collection
of records connected to one another by links. Each link associates two records
together in some way. Record types can also be linked to one another. When this
occurs, they form a set. In every set, one record type is designated as the
owner of the set, and the other
is designated as the member of the set. Sets can only exhibit one-to-many relationships
in a network database (with the set owner being the "one").
Each owner record along with its associated member records form an occurrence
of a given set type. Each member type record can be in at most one set occurrence,
though a set type itself can have any number of occurrences.
When
a set is formed, its method of insertion must be specified. This insertion
method dictates properties
which must hold on records which are inserted into an occurrence of the set.
Insertion methods may be one of the following:
Manual: the
record is inserted into the set explicitly via a data
manipulation
command
Automatic: the record is inserted
into the set implicitly upon its creation
Similarly, a set must
have a rule concerning the removal of its member records. This rule is called
a retention method and can be one
of the following:
Fixed: the member record
may not be disconnected from its set occurrence
Mandatory: the
member record must be reconnected to another set
occurrence of the same set upon its removal from the original
set
occurrence; it cannot just be simply disconnected
Optional: the
member record may be disconnected without
restriction
from
the set occurrence
Record and set types and variables are declared
using a data definition language (DDL). The data manipulation language (DML)
provides facilities for creating, manipulating, and deleting individual instances
of these. DML commands are embedded in a host language (C++ for this system),
and can access database variables (created via the DDL) as well as locally
defined program variables. (DDL and DML statements for NETSIM C++ are discussed
below.)
For each
database application program or run unit, the network database system maintains
a user work-area. This is a buffer storage area which contains templates for
each record type defined for the run unit. It also contains a set of pointers
to the most recently accessed entities in the application program. These currency
pointers include the following:
Current of record type:
a pointer to the address of the most recently accessed
record
for each record type
Current
of set type: a pointer to the address of the most
recently accessed
record in the set for each set type; this may point
to the set owner or one of
its members
Current of run
unit: a pointer to the most recently accessed record, regardless
of
its type
Note that an application
program may not directly access these currency pointers, but may manipulate
them indirectly through DML statements.
Additionally, the user work-area contains a set of status flag variables
used to communicate the outcome of the last operation performed to the run
unit. (Some of these can be accessed in NETSIM C++ and are outlined below.)
Sometimes
the currency pointers in the user work-area are insufficient
for keeping track of things. A keeplist is a useful structure which can hold
currency pointers so that they can be reactivated later. Keeplists behaves like
queues as far as insertion and
removal go.
NETSIM C++ is based upon the report issued by the Database
Task Group (DBTG. However, only a subset of the DDL, DML, and other facilities
outlined in this report are implemented in this system.
2.0 Using
NETSIM C++
2.1 Understanding the System
In
and of itself, NETSIM C++ is not an application program with a standard
user interface, but rather a tool for building small scale network databases.
Because of this, you will
need several building blocks to effectively make use of the system. These include
the following:
DDL file(s): These files will
contain declarations which describe the database
you wish to use. Specifics
of the NETSIM C++ DDL are outlined below. All
DDL files must have
a ".ddl" extension.
Application program(s):
These programs will contain a mixture of C++ code
and comments, NETSIM
C++ DML commands, and a #ddl
directive
referencing the DDL files to be used with the
program. The last two of these
articles are described in detail below.
Each application program must have a
".dml" extension.
The
NETSIM C++ system consists of two major parts:
2.2 Preprocessor
Program (netpp)
This
program takes as input the application program(s) and DDL
file(s) you have written for a
network database system. It transforms the declarations for records, sets, and
keeplists in the DDL file(s) into appropriate C++ class declarations. It also
translates the DML commands in the application program(s) into calls to methods
defined in the NETSIM C++ library.
For each application program submitted
to it, the preprocessor outputs a program written in "pure C++"
which contains the class declarations from the DDL file(s), the C++ code and
comments which were in the original
application program, and the method calls corresponding to the translated
DML statements. (Note that these will be in the same relative positions in the
output file as the DML statements in the application program.) This file will
have a ".cc" extension and will be immediately ready for compilation
by a C++ compiler.
For each syntax error the preprocessor detects
while translating the DDL and application program files, it outputs an appropriate
error message to the screen.
(These error messages are described below.) If this happens, you should correct
the error(s), and then re-submit the application program.
To submit
an application program to the preprocessor, run the netpp program.
It will prompt for the name of the application file. The file it outputs
(provided no errors are found) will have the same name as the application program,
except that its extension will be ".cc" rather than ".dml".
(The preprocessor can deduce
which DDL files are associated with the application program based upon the
contents of its #ddl directive.) The output file can then be compiled and linked
as any normal C++ program.
Note that every NETSIM C++ application
program you intend to use must be successfully parsed and translated by the
preprocessor before being processed by a C++ compiler.
2.3 NETSIM
C++ Library (netlib)
The
NETSIM C++ library contains C++ methods for carrying out DML commands as well as
several utility methods and variables which your programs can access. (These
are listed and explained below.) Additionally, this library contains error messages
to be printed if a run time error occurs with your database. Declarations
necessary for maintaining the structure of a network database are also kept
here.
When you submit an application program to the preprocessor, it
will append the following C++
directives to the beginning of the file it outputs. These directives instruct
the C++ preprocessor to include the NETSIM C++ library.
#include
"lolevel.h"
#include "netsim.h"
#include
"record.h"
#include
"set.h"
#include "keep.h
#include
"debug.h"
In
addition, you must remember
to include the netlib library in the link command for your program.
Exactly how to do this is system specific.
2.4
Other System Pieces
NETSIM C++ also
includes a Date class which is used to model calendar dates and display them
with the form dd-mm-yyyy This class includes facilities for manipulating
dates in various ways through overloaded operators. The Date class is
declared in the file date.h.
A
help
text file entitled netdbg.hlp is also included. This file is printed
when the help command is issued from within the debugger,
discussed below.
3.0 Data Definition Language Files
3.1
Creating and Referencing DDL Files
Each
NETSIM C++ application program will use one or more DDL files describing
the database. You should
not alter a DDL file once this program is compiled and linked, and once data
has been loaded into the corresponding database, since interpretation of this data
hinges on the declarations in the DDL file. Doing so will require you to recreate
the database as the information stored in it will be unreliable.
The
names of your DDL files should end with
a ".ddl" extension. They should only contain NETSIM C++ DDL constructs
as described below and C++
comments.
Each application program using objects declared in a given
DDL file must list that file in a #ddl directive. An application
program using DML statements must contain at least one such directive (one
for each DDL file referenced), and this should appear before any DML commands
in the program (preferably along with other C/C++ preprocessor directives).
A #ddl directive stands by itself on one line of the source file.
It consists of the directive
(#ddl) followed by a DDL file name within quotation marks.
Example:
#ddl "myddl.ddl"
3.2
DDL Syntax
The NETSIM C++
preprocessor requires that you use the following constructs in declaring records,
sets, and keeplists in your DDL files. Each of these constructs begins with
a # as the first non-blank character on the line. The declarations
may continue over any
number of lines in the DDL file, but nothing else (including comments) should appear
on these lines. All sets must be declared after the records which are their
members and owners.
In the syntax described below (both here and
in the following sections), reserved words and characters in statements are written
in bold face Names you supply are italicized, and fixed identifiers (in
the examples) are in plain text. Furthermore, optional segments are enclosed in
square brackets, and angle brackets
surround parts which may be repeated any number of times. If several terms
are possible at a point in a statement, these are listed in a column. Note
that the NETSIM C++ system (like the C++ programming language) is case sensitive;
all lexical conventions outlined in this section and those that follow must
be expressly adhered to.
3.2.1 Record Declaration
#record
recordName on fileName
using
{ < fieldType fieldName
; > } ;
The value of fileName is the name
of a file in which all records of the type being declared are stored. The name
of this file must be enclosed in quotation marks.
The value of fieldType
declares its corresponding fieldName to be of
some type, which may be one of the following:
int an
integer
float a
floating point number
date a
date (defined
in date.h)
string length a
string of length characters
Example:
#record
Student on "student.dat"
using
{
string 7 studentId ;
string 20 lastName ;
string 20 firstName ;
int yearAdmitted ;
float gpa ;
date birthday ;
 } ;
For each field
of each record you declare, you may access a template of the form recordName.fieldName
(e.g. given the student record declaration above, you
could reference Student.studentId
and Student.gpa, to name a couple possibilities). You may use the name of a
record by itself, or the field names by themselves within a DML command, but not
in any other context.
Whenever you copy character arrays to fields
of type string, be sure to use the C library function strncpy(
string1, string2, len ) in your application programs,
passing the size of the character array to be copied as the final parameter.
(This can be done using the
C sizeof operator.) This function ensures that all character slots
in the string field are copied
into (either by characters from the copied character array or by NULL characters),
andwill keep some obnoxious errors out of your program.
3.2.2 Set
Declaration
#set setName owner
recordName member recordName
[
insertion
insertMode ] [ retention retainMode
] ;
The value of insertMode
may be either automatic or manual.
The value of retainMode may be one of fixed,
mandatory, or optional.
Examples:
#set
StudentRoom owner Room member
Student
;
#set StudentRoom owner Room
member Student retention optional ;
You
may use set names within DML statements, but nowhere
else.
3.2.3 Keeplist Declaration
#keeplist keeplistName
;
Example:
#keeplist
TempKeep ;
You
may use keeplist
names inside DML commands as well, but nowhere else.
Certain
identifiers in a given DDL file need to be unique. Records, sets, and keeplists
cannot share names. However, different record types may have fields with the
same name (but obviously all fields declared in a given record type should be
distinct). It is probably a good idea to choose unique names for identifiers
in the application, so that they are different from others in the program and in
relevant DDL files. This may
help to avoid some translation and compilation errors.
Note that all
record, field, set, and keeplist names may not exceed 16 characters in length.
4.0
Data Manipulation Language Syntax
The
following DML statements may be used from within your application
programs, interspersed with C++ code and comments. Each must have the #
as the first non-blank character on its initial line and can extend
over multiple lines in the source
code file. Normally, nothing else (including comments) should appear with
a DDL command on the lines it occupies. (The conditional statements described
below are exceptions to this, since they require additional code for completeness.)
4.1
Find Statements
One
of the most basic network database command is find.
The find statement attempts to locate a record in the
database which matches the criteria
you specify.
Although there are several variations on the find
statement, there are some properties common to all of them.
When a record is successfully found, several currency pointers converge upon
it. These include the current of run unit, the current of record for its type,
and the current of set for all sets in which it participates (either as an owner
or a member). If the record found is of the member type of a certain set,
but itself is not currently the
member of an occurrence of that set, then the current of set pointer for that
set is not affected. If you wish to selectively repress updating some of these
currency pointers, you should use a retaining clause, described
below. If no record is found which matches the specified criteria,
none of the currency pointers are altered. Instead, the status Netsim::status
is set equal to Netsim::NOT_FOUND. (This variable and others like it
are discussed below.)
All
named values in a find statement must be defined in some
DDL file. That is, recordName must be a declared #record,
setName a #set, and keeplistName
a #keeplist.
NETSIM
C++ does not provide a find update statement. Update is
allowed after any successful find.
In the following
syntactic descriptions, first and any
have exactly the same meaning, as do next and duplicate.
The first and any keywords specify
that record to be found is the first one of the specified type. The next
and duplicate keywords denote that the record found
should be the next record meeting the criteria given following the current
of record for the specified record
type.
4.1.1 Record Oriented Find Statement
first
#find next  recordName
[
using fieldName < , fieldName >
] [ retaining clause ] ;
any
duplicate
This
is the simplest of the find
commands. It attempts to locate the first/next record of the type specified
by recordName.
If you include a using clause in the statement, it looks
for one that matches the record template (in the user work-area) on all of the
specified fields.
Examples:
#find
first Student ;
#find
next Student using lastName ;
#find
first Room using
dorm, number ;
4.1.2
Set Oriented Find Statements
first
#find next recordName
within
setName [ retaining clause ] ;
any
duplicate
This
form of
the find command tries to locate the first/next member of the
set occurrence associated with the current of set for the specified set. The
value in recordName
must refer to the member record type of setName. If the set has
no current record then Netsim::status is set to Netsim::NO_CURRENT.
Example:
#find
first Student within OccupiedBy
;
#find owner within setName
[ retaining clause ] ;
The find
owner statement looks up the owner of the set occurrence associated
with the current of set
for the specified set. Again, if there is no current record for the set, Netsim::status
is set to Netsim::NO_CURRENT.
Example:
#find
owner within OccupiedBy ;
4.1.3 Currency
Oriented Find Statement
recordName
#find setName [ retaining clause ] ;
keeplistName
This
form of find has
different effects depending upon its argument. If the parameter is a recordName,
then the current of record for that type is selected. If it
is a setName, then the current of set for that type is selected.
If it is a keeplistName, then the front entry of the specified keeplist
is selected and removed.
Examples:
#find Student
;
#find OccupiedBy ;
#find
TempKeep ;
4.2 Store
Statement
#store recordName
[ retaining clause ] ;
The
store statement adds a new record to the specified
record type, and data is copied from the user work-area template for that record
type to it. You need to be sure that the data to be stored is first placed into
the template before the store
command is carried out.
The newly-created record
is also added to current occurrence of any sets with insertion automatic
of which it is the member type. If the record being created is the
member type of such a set, you also need to ensure that the currency pointer(s)
for each such set is pointing to the current occurrence before the store
statement is executed.
The new record becomes the current
of run unit, current of record
for its record type, and current of set for all sets of which it is the owner
type or an automatic member. Updating of currency pointers
may be selectively repressed via use of a retaining clause (discussed below).
Example:
#store
Student ;
4.3
Record Fetch/Update Statements
The
following commands are used to access and alter
records in the database. Each
of these statements operates on the record pointed to by the current of run unit,
and the recordName argument is optional, and only included for
the sake of documentation and clarity for the reader. If it is specified, it
must be a declared #record, and it must match the record type
that is the current of run unit when the statement is executed. Otherwise, the
statement will fail.
4.3.1 Get Statement
#get
[ recordName ] ;
The
get command copies data from the current of
run unit record on disk to the template for its record type in the user work-area.
Many
users run into problems by forgetting this statement after
they have
found some record and before they try to test some attribute of that
record. Remember, you cannot access a record on disk via a currency pointer;
you must first bring it into
main memory. Don't forget the get!
Example:
#get
Student ;
4.3.2 Modify
Statement
#modify [ recordName
] ;
The modify
command copies data from a user work-area template in memory
to the current of run unit record on disk.
This statement is not analogous
to store.
The modify command alters records which already exist in
the database. The store command creates new records. If you
try to use the two interchangeably, you'll have problems.
Example:
#modify
Room ;
4.3.3 Erase
Statement
#erase [ all
] [ recordName ] ;
The
erase
command deletes the current of run unit record. If the all
keyword is omitted, erase does away with any
member records of set occurrences the record being deleted owns, but only if
the set has retention fixed. If the all keyword
is included, erase deletes all member records of set occurrences
the record being deleted owns, regardless of the retention rule of the
set.
In either case,
the erase statement recursively deletes member records of sets
owned by set members according to the same rules. An erase statement
without the all keyword will fail if any record being
deleted owns a non-empty set occurrence of a set with retention mandatory.
Since
the erase
command deletes the current of run unit, the current of run unit pointer
and all other currency pointers
referring to that record will point to an empty slot in the database after the
statement is executed. Thus, subsequent attempts to access that record directly
will fail. However, statements like find next will still work
properly. (It will look up the record after the one just erased.)
Example:
#erase
all Room ;
4.4
Set Modification Statements
The
following statements
allow you to alter set memberships. In all cases, recordName
must be a declared #record, and setName a #set.
The value in recordName must also refer to the
member record type of setName. The record affected is the current
of run unit, which must be of the type specified by recordName,
or the statement will fail.
4.4.1 Connect Statement
#connect
recordName
to setName [
retaining clause ] ;
The
connect command makes the specified record a
member of the specified set type, connecting it to the set occurrence which is
its current of set. Obviously, the record to be connected to the set should not
be a member of that set prior to the connect statement. The
connected record becomes the
current of set for the specified set type, unless updating of set currency is suspended
by a retaining clause.
Example:
#connect
Student to OccupiedBy
;
4.4.2 Disconnect Statement
#disconnect
recordName from
setName [ retaining clause ] ;
The
disconnect statement removes
the specified record from the set occurrence of the specified set of which
it is a member. Of course, the record must be a member of the set in order to
be disconnected from it. The disconnect command is illegal for
a set declared with retention fixed or mandatory.
After a record which was current of set of a set is disconnected, the
current of set for that set becomes
undefined. However, find next . . . within and find
owner statements will still execute correctly.
Example:
#disconnect
Student
from OccupiedBy ;
4.4.3 Reconnect
Statement
#reconnect recordName
within setName [ retaining
clause ] ;
The
reconnect statement
transfers the specified record's membership from the set occurrence of which
it is currently a member to the set occurrence which is the current of set for
the specified set type. The reconnect command is
illegal for a set declared with retention fixed. As with the
connect statement, the reconnected record becomes the current
of set for the specified set
type, unless a retaining clause keeps it from doing so.
Example:
#reconnect
Student within OccupiedBy
;
4.5
Keep Statement
[ recordName
]
#keep [ setName
] using
keeplistName ;
[
keeplistName ]
The keep command
adds the specified entity (or the current of run unit if none is
specified) to the end of keeplistName. The values of recordName,
setName, and keeplistName(s) must each
be a declared #record, #set, and #keeplist,
respectively.
If a recordName is given, the current of record for that type is
inserted. If a setName is provided the current of set for that set
type is appended. If a keeplistName is specified, the front of
that keeplist is used. In any case, no currency pointers are altered.
Examples:
#keep
Student using TempKeep
;
#keep using TempKeep ;
4.6
Retaining Clause
record
record
. . . retaining [
set ] setName < , [ set
] setName > ;
As
indicated above, the various find statements and the store
statement normally make the record accessed current of run unit,
current of record for its record
type, and current of set for all sets in which it participates. Also, the connect,
and reconnect commands make the record
involved current of set for the specified set. Sometimes it is necessary to
suppress the updating of currency for the record type and/or one or more set types
when one of these operations is performed. This can be done by appending
a retaining clause to the end of the statement.
Specifying
record
suppresses the updating of currency for the record type accessed by the statement.
Specifying one or more sets keeps their corresponding current
of set pointers from being changed. A successful statement with a retaining
clause will still update all currency pointers affected by
that statement and not mentioned in the clause.
No other statements
besides find, store, connect,
and reconnect
may have retaining clauses attached to them. In the case of
connect and reconnect, only the setName
involved in the operation may be specified.
Examples
#find
Student retaining
set OccupiedBy currency ;
#find owner
within OccupiedBy retaining record currency
;
#store
Student retaining record, set OccupiedBy currency
;
#connect Student to OccupiedBy
retaining OccupiedBy currency ;
4.7
Set Membership Conditional Statements
The
following conditional statements test whether the
current of run unit points to a record with is a member of some occurrence of
the specified set, and the conditional
returns true if it is. The test can be inverted by use of the C++ !
operator. In both cases, this setName must be a declared
#set.
#if
( [ ! ] member setName
. . . ) . . .
#while
( [ ! ] member setName
. . . )
. . .
These conditionals translate
into C++ if or while statements, and
anything appearing on the line after the last keyword (normally a closing parenthesis
or a Boolean connective such as &&) will be passed
on to the pure C++ code unchanged. The conditions themselves are converted
into C++ Boolean expressions. The entire conditional expression can should be
followed by a typically C++ statement
block.
Upon evaluating these conditionals, the utility variable
Netsim::status will be set to SUCCESS unless they cannot be tested for some
reason (e.g. the current of run unit is not defined, or the current of run unit
is not of the correct record type to be a member of the specified set). A condition
which cannot be tested evaluates to false.
Examples:
#if
( member OccupiedBy ) . . .
#while
( ! member OccupiedBy
&& ! done ) . . .
Note
that these conditionals are defined for NETSIM C++, but not for the general
DBTG model on which the system is based.
5.0 Utility Variables and Methods
5.1
The Netsim Class
The NETSIM
C++ library declares a manager class called Netsim. This class has several methods
and instance variables which may be useful to your application programs.
A partial declaration of the Netsim
class is given below.
class Netsim
{
public :
enum Status { SUCCESS, NOT_FOUND, ALREADY_CONNECTED,
EMPTY_KEEPLIST, NO_CURRENT,
NOT_CONNECTED, NOT_CRU,
NOT_MEMBER_TYPE, RECORD_SIZE_MISMATCH,
RETENTION_VIOLATION } status ;
static void
signal ( bool abort = true ) ;
static void netdbg()
;
static int setAutomaticSignals ( bool set = true
) ;
static Status status ;
private :
// These variables and methods are not visible to the user.
// ...
} ;
This
declaration is
available to any application program which #includes the NETSIM C++
library.
5.1.1 Status Variable
The variable
Netsim::status is set by all of the DML statements outlined above. It is set
to Netsim::SUCCESS if the statement succeeded and something else if it failed.
The possible values which Netsim::status can take on are explained as follows
(each prefaced by Netsim:: ):
ValueInterpretation
SUCCESSThe
last operation performed was successful.
ALREADY_CONNECTEDYou
attempted to connect a record to
a set it was
already connected to.
EMPTY_KEEPLISTYou
tried to find the front of an empty keeplist.
NO_CURRENTThe
current of run unit, record, or set pointer is
undefined.
NOT_CONNECTEDYou
attempted to
disconnect a
record which was
not connected to anything.
NOT_CRUYou
attempted to manipulate a record that was not
the
current of run unit.
NOT_FOUNDA find
operation failed to locate a matching record.
NOT_MEMBER_TYPEThe
record you specified is not the member type of
the
specified set.
RECORD_SIZE_MISMATCHThe record size for a record
type specified in its file
does
not match the size in its declaration.
RETENTION_VIOLATIONThe
last operation would result in a violation of
the
retention rule of some set it manipulates.
Note that,
in general Netsim::NOT_FOUND is the only "benign" status code other
than Netsim::SUCCESS. In most cases, other values for Netsim::status indicate
a problem in the logic of your program.
It will probably be useful
for you to test the value of Netsim::status
throughout your program. You can write statements like the following.
if
( Netsim::status == Netsim::NOT_FOUND )
. . .
while ( Netsim::status == Netsim::SUCCESS
) . . .
5.1.2 Error Signaling
The
signal() method of Netsim is called by the NETSIM C++ library when an operation
returns a status other than Netsim::SUCCESS or Netsim::NOT_FOUND. It indicates
that there was a problem
with this last operation, and prints a message describing what failed.
The
Netsim::signal() method takes a Boolean parameter, which has true for
its default value. If this parameter is true, the signal() method will alert the
host operating system of an error and trigger a stack dump. If it is false,
the method will return control to its caller after printing its error message.
(Error messages are described below.) If signal() is called when the current
status is Netsim::SUCCESS, it
will simply print a descriptive message, regardless of its parameter value.
Your
applications may call Netsim::signal() using the declaration given
above as a model. A good place to do this is at a point where you know that a
DML statement has just returned an erroneous status.
Examples:
Netsim::signal()
;// aborts after printing an error
message
Netsim::signal( false ) ;//
always returns
to caller
5.1.3 Setting Automatic Signaling
The
signal() method is typically called when an erroneous status occurs. (NOT_FOUND
is an exception.) You may turn this behavior off and on with the Netsim::setAutomaticSignals()
method. This method takes a Boolean parameter which has a default
value of true. If the parameter is set to true, automatic signaling for
errors will be turned on. If it is false, signaling will be turned off.
Examples:
Netsim::setAutomaticSignals(
) ;// turns on automatic error signaling
Netsim::setAutomaticSignals(
false ) ;// turns off automatic error signaling
5.1.4
Calling the Interactive Debugger
You can
use the netdbg() method to activate the NETSIM C++ interactive debugger from
within your program. Specifics of the debugger are detailed below.
Example:
Netsim::netdbg(
) ;
5.2 The Date Class
The
NETSIM C++
library includes a Date class (declared in date.h) which facilitates
working with date fields in records. A partial declaration
of the Date class is given below;
class Date
{
public :
Date ( )
; //
Constructors.
Date ( const Date & date
) ;
Date ( const char * representation ) ;
Date
& operator = ( char * representation ) ; // Arithmetic
Date
& operator = (Date & date); //
operators
Date & operator += ( int offset
) ;
Date & operator -= ( int offset )
;
Date & operator + ( int offset ) const ;
Date
& operator - ( int offset ) const ;
int
&
operator - ( const Date other ) const ;
bool
operator < ( const Date & other ) const ; // Logical
bool
operator <= ( const Date & other )
const ; // operators.
bool operator == ( const
Date & other ) const ;
bool operator != ( const
Date & other ) const ;
bool operator >=
( const Date & other ) const
;
bool operator > ( const Date & other ) const
;
static Date stringToDate
( const char * representation ) ; // Auxiliary
static
char * dateToString ( const Date & date ) ; // methods.
friend
ostream & operator <<
( ostream & stream, const Date & d ) ;
private
:
// These methods and variables are not visible
to the user.
// . . .
} ;
The public methods and operators of
the Date class can be called on Date objects which your program defines. (Typically,
your program will define Date objects indirectly, as fields of records.
The preprocessor program will convert these field declarations into Date object
instantiations. You will need
to call methods in a manner like the following.)
recordName.fieldName.dateMethod
The
two static methods should not be called
on objects, but in the manner appropriate for C++ static methods (i.e. Date::stringToDate
( string ) ; ). Note that you can also declare Date variables explicitly
within your application programs. The methods and operators declared above
are detailed as follows:
5.2.1 Constructors
The first
three methods listed in the
Date class are constructors. The first takes no parameters and initializes that
Date variable being created to today's date. The third takes a character representation
of the form dd-mm-yyyy and assigns this date to the
new instance. (Note that a character representation for a Date must always
contain two digits for its day number. Also, the abbreviation for a
month name in a Date character representation must be in all capital letters.
Thus, "13-FEB-1997"
and "03-JUN-2001" are valid character representations, while "8-MAR-1994"
and "14-May-1991" are not. )
5.2.2
Arithmetic Operators
The next six operators declared allow arithmetic
manipulation of dates. The first one allows a valid character representation
to be assigned to a Date object. The next four allow a Date to be incremented
or decremented by a certain amount, given by the offset parameter.
The sixth operator computes
the difference between two dates, taking its Date parameter as the second
of these.
5.2.3 Logical Operators
The final six operators
defined for the Date class allow comparison between two dates, with the second
of these being contained in the Date parameter.
5.2.4 Auxiliary
Methods
The two auxiliary methods allow for conversions from
a character representation to a Date object and vice versa. An error in these
conversions will result in a BAD
DATE value being returned instead of a string or Date.
Friend Extraction
Operator
The final declaration in the public section of
the Date class allows instances of the class to be output via the extraction operator
declared in the ostream class.
6.0 Interactive Debugger
NETSIM
C++ provides an interactive debugging system which allows you
to view information about items in your database. It can also help you to track
down and eliminate errors in
your application programs.
The debugger is entered by calling the
Netsim::netdbg() function from within your program. (This function is included
in the NETSIM C++ library.) You may also enter the NETSIM C++ debugger from within
your system's debugger. Use your debugger's mechanism for calling a procedure
by name to call the netdbg() function (not Netsim::netdbg()).
6.1
Preliminary Information
When the NETSIM C++ preprocessor
encounters declarations for
records, sets, and keeplists in your DDL files, it converts them to C++ class
declarations. Each instance of these classes is assigned a type which conveys
what kind of network database structure (e.g. record, set, keeplist) it represents,
as well as the name you gave it in its DDL declaration. Additionally, record
class instances are assigned numbers which identify them while your program
is running.
Note that, in the debugger, you still refer to records,
sets, and keeplists by the same
names you gave them in their DDL declarations. The description provided above
is intended to help you better understand how the NETSIM C++ system works, and
the meaning of the data printed for you by the various debugger commands.
6.2
Debugger Commands and Syntax
The NETSIM C++
debugger will prompt for a command as follows:
NETDBG >
At
this prompt, you may enter any of the following commands, always typing
the command on a single line and
pressing return to terminate it.
6.2.1 List Command
There
are several formats to the list command (as well as others).
The syntax of each is given below followed by their meanings.
list
[ all ]Generic list
command
list [ recordName [ all
] ]Record oriented list command
[ owner ]
list
[ setName [ all
] ]