When you program with OrgC++, errors are reported at three levels:
Level 1: The class generator (zzprep) reports some errors, referring to the line numbers of the code that you ran through it. In most cases, this is only your header file with the definitions of organizations (ZZ_HYPER_ statements). The rule of thumb is that all OrgC++ calls which start with the prefix ZZ_ should run through the class generator. If you have several header files, concatenate them into a single file, and run the class generator on that file.
Level 2: The compiler reports additional errors. The class generator is designed to force the compiler into more checking. With OrgC++, it takes a bit longer to get the code through the compiler, but the resulting program is safer to run.
Level 3: At run-time, OrgC++ provides more checking, mainly to prevent dangling pointers.
Normally, messages at all levels come out on standard output (stdout) - see below. When you receive your copy of OrgC++, the output language is set to English. You can convert level 1 and 3 messages to any other language, if you translate all the messages in the file orgC/lib/msgs.c and then recompile the entire library, including the class generator (see Chap.2 on how to recompile the library).
In addition to run-time error messages, programs coded with OrgC++ may set a special error flag that may be checked by your program. The flag is binary coded, and can be accessed through the following function: int util.error(void);
ZZ_HYPER_UTILITIES(util);
util.strAlloc(...);
if(util.error()){
printf("error=%o\n",util.error());
return;
}
The error condition is bit encoded (shown as octal here):
01=allocation error
02=index out of range
04=using an organization that has not been formed
010=object not disconnected, or not compatible
020=internal algorithm failure
040=wrong structure
0100=wrong file or unable to open a file
The error condition can be set to the no-error state by calling void util.ok(void).
If you don't want your messages on the standard output (stdout), provide your own error handling function somewhere in your code. The default version of zzReportError() is in file orgC/lib/heading.h and consequently also in file orgC/zzcomb.h. If you include #define ZZcallBack in your environment file, the default version will be disabled and prevent multiple declaration of this function. The default version contains a single call to printf() which you can replace by a fprintf(), or turn it into a call-back function that handles the errors.
In particular, when using Microsoft Visual C++, the printf(...) statement inside zzReportError() can be replaced by TRACE(...). Sending messages to stdout is usually not practical in the visual environment. Note however, that TRACE(...) displays the messages only in the debugging mode, not in the release mode. That is not sufficient since OrgC++ may display run-time error messages which are vital for detecting serious errors. If you don't want error codes which include both alpha and numeric characters, use function errorCodeConvert() which converts the error code string into a unique long integer (file msgs.c).
For instructions see Chap. 2.6.
Some run-time error messages give you an indication which data structure (and which internal pointer) has been corrupted or is causing the problem. The best way to explain this is on an example.
Example 1:
A program using objects of class Node, issues the following message:
cannot add to dsNodes, object 7950688 not disconnected
You look at the ZZ_HYPER_.. statements and search for dsNodes
ZZ_HYPER_SINGLE_AGGREGATE(dsInElem, NetwElem, Node); ZZ_HYPER_DOUBLE_AGGREGATE(dsNodes, Layer, Node); ZZ_HYPER_SINGLE_AGGREGATE(dsSegments, Layer, Segment); ....
Now it is clear, that the program tried to add a Node with address 7950688 to aggregate dsNodes, but the Node is already in this aggregate. This operation would likely destroy the integrity of your data, and was not performed. The address of the object is usually irrelevant. You have to check your code in the place where it adds objects to dsNodes. Search for all occurences of dsNodes.add(...).
Example 2:
The same program issues the following message:
errLevel=8 errCode=SD3: cannot free object=Node, pointer No.0 not disconnected
This message may occur, if you requested testing of objects before destructing them, and you placed ZZ_CHECK() into the destructor:
~Node(){ZZ_CHECK(Node);}
The error message tells you that when your program tried to destroy a Node, the Node was not disconnected from all data structures. This will cause a serious corruption of your data, and the program will likely crash later on. Unfortunately, once the destruction process started, the library cannot stop it, but at least you know what happened, and the tedious debugging which would normally follow is prevented.
The message tells you that the internal pointer index=0 on object Node is not disconnected. In order to interpret this, you look at file zzincl.h, search for ZZ_EXT_Node, and here is what you may see:
#define ZZ_EXT_NodeLink \ Layer *ZZpdsNodes; \ Node *ZZfdsNodes; \ Node *ZZbdsNodes; \ Node *ZZfdsNodeLink; \ NodeLink *ZZsdsSameCost;\ ...
The names of the pointers combine the name of the data structure with a one letter code expressing the purpose of the pointer. For example p=parent, c=child, f=forward link, b=backward link, n=name. The first pointer relates to dsNodes, so you see that the Node is still not disconnected from this aggregate. The code 'p' indicates that it is the parent pointer (and possibly some other pointers) which is not NULL at the time of the destruction.
| Chapter 16: Adding New Features |