ASCDS Error Library API

Error Library : Error List Management Facilities

Contents:
=========
1.  History

2.  Description

3.  How to link/include the Error library (liberr.a)
	- Include files.
	- Code location.

4. Structures
	4.1: dsErrCode
	4.2: dsErrType
	4.3: dsErrMsgType
	4.4: dsErrSeverity
	4.5: dsErrBool
	4.6: dsErrInstance
	4.7: dsErrList
	4.8: dsErrGroup

5. Functions

	5.1: Initialization, Creation, Close
		5.1.1: dsErrInitLib()
		5.1.2: dsErrCreateInstance()
		5.1.3: dsErrResetInstance()
		5.1.4: dsErrCreateList()
		5.1.5: dsErrCloseLib()
		5.1.6: dsErrDirectOutput()

	5.2: Adding/Setting Errors
		5.2.1: dsErrAdd()
		5.2.2: dsErrSetInstance()
		5.2.3: dsErrAddToEnd()

	5.3: Searching for Errors in an Error List
		5.3.1: dsErrLook()
		5.3.2: dsErrLookN()
		5.3.3: dsErrLookCode()
		5.3.4: dsErrLookCodeExcl()
		5.3.5: dsErrLookSev()
		5.3.6: dsErrLookAllSev()
		5.3.7: dsErrLookAllCode()
		5.3.8: dsErrLookAllCodeExcl()
		5.3.9: dsErrGetNumOccur()
		5.3.10: dsErrPeek()
		5.3.11: dsErrPeekN()
		5.3.12: dsErrPeekCode()
		5.3.13: dsErrPeekCodeExcl()
		5.3.14: dsErrPeekSev()


	5.4: Removing Errors from Error Lists
		5.4.1: dsErrRemove()
		5.4.2: dsErrRemoveN()
		5.4.3: dsErrRemoveCode()
		5.4.4: dsErrRemoveSev()
		5.4.5: dsErrRemoveAll()
		5.4.6: dsErrRemoveAllSev()
		5.4.7: dsErrRemoveAllCode()

	5.5: Processing Error Instances and Error Lists
		5.5.1: dsErrPrintList()
		5.5.2: dsErrPrintInstance()
		5.5.3: dsErrReturnInstance()
		5.5.4: dsErrExitInstance()
		5.5.5: dsErrQuitInstance()
		5.5.6: dsErrDumpInstance()

	5.6: Accessor Functions for Error Instances and Error Lists
		5.6.1: dsErrGetErrorCt()
		5.6.2: dsErrGetFatalCt()
		5.6.3: dsErrGetWarningCt()
		5.6.4: dsErrGetInstCt()
		5.6.5: dsErrGetInstCode()
		5.6.6: dsErrGetInstSev()
		5.6.7: dsErrGetInstMsg()

        5.7: Signal Handling

6. How to Add Errors to the Library

6.1 The Error Elements
		6.1.1 The error number:
		6.1.2 The error severity:
		6.1.3 The generic error message:

6.2 Location of the Error

6.3 Modifying the code to place the error in the hash map

7. Debug and Function Tracing
	7.1 Function Tracing
	7.2 Routines for Function Tracing
		7.2.1 init_function_stack()
		7.2.2 check_in()
		7.2.3 check_out()
		7.2.4 exit_upon_error()
		7.2.5 print_function_stack()

8. Synopsis of Defined Errors

1. History

=========== Date Comment ---------------------------------- 5/18/98 DLM - initial release. 7/23/98 DLM - Many updates: more errors, custom error messaging expanded, API in HTML format. 1/27/99 DLM - added ability to redirect output to a logfile. 7/05/00 NRAW - added the debug and function tracing

2. Description

=============== Concepts: A group of new functions has been added to the already existent ASCDS error library. They have been added with the following requirements in mind: - Provide ability to store a large number of errors. - Provide ability to store multiple instances of a given error. - Provide standard set of error messages, to give common feel to error reporting. - Provide ability to customize error messages. - Provide various functionality to search through stored messages and retrieve or remove the error data, either singly, or multiply. - Provide ability to directly process errors stored. - Do not alter/break/remove current functionality of the error library The errors will range from -32000 to -1 with 0 as a NO_ERROR value. The space of errors (32000 values) is divided between the various groups - General, DB, UI, Integ, Pipe/Tools, MTA + V&V, and any others. As some of those groups should perhaps be divided up further, the division may not be equal - the Pipe/Tools group may have a lot of subdivision, and need a larger part of the error space. Currently there are errors defined for General and Pipe/Tools, but the Fitting Engine will also get it's own area. Errors can be stored by either pushing them onto a list of errors, or putting them into an error instance structure. Errors can be retrieved from the lists via a number of search criteria. The searches can also return the first instance of a matching error, or all matching errors. The same search criteria can be used to remove errors from a list. Note that searching for an error, will not remove it if the error is found. Errors must be explicitly removed. In addition, errors may be specified as individual, or as accumulations. Any accumulation errors will be stored once, with their count being incremented each time another such accumulation is added. Memory Allocation/Deallocation. Provided that the user creates and populates the list and instance structures via the functions provided, they will not need to be concerned about managing the memory for the error library. This includes the memory for the error messages that will be stored with each instance of an error. These messages are dynamically sized. This introduces a chance for memory allocation errors to occur in a number of places within the error library code. The routines that may experience this return an error code, which in general will either be dsNOERR, or dsALLOCERR. There are some cases where a third return value may be possible. It has been decided that in the case of an allocation error within the error library, a message will be sent to standard error, notifying the user of this.

3. How to link the Error library (liberr.a)

================================================ There are no special concerns or dependencies of the error library. Simply include it in your link line. cc main.c -lerr ... The only include file you will need in your code is liberr.h, although it does depend on other header files which must be in the include path: dserror_database.h dserror_funcs.h dserror_general.h dserror_ptdmtools.h dserror_ptinstrument.h dserror_ptanalysis.h dserror_ptnonsi.h dserror_signal_handler.h dserror_structs.h dserror_trace_fct.h The code is located in <developement area>/lib/dserror/. Example code can be found in the dserror_test.c file.

4. Structures

============= There are some structures and types that the user will need to know about in order to utilize the added functionality of the error library.

4.1: dsErrCode

This is a long, with values ranging from -32000 to 0, with 0 as the no error value. This is the type that is returned by error library functions, and that identifies an error when it is being added to a list. See the error header files for the errors that have been defined to date. dserror_general.h - generic errors dserror_ptdmtools.h - data model tools errors dserror_ptinstrument.h - pipe/tools group instrument tool errors dserror_ptanalysis.h - pipe/tools group analysis tool errors dserror_ptnonsi.h - pipe/tools group non-si tool errors

4.2: dsErrType

This identifies a given instance of an error (see below) as either an individual error, or an accumulation. Individual errors are useful when you want the same error with slightly different variations (a file i/o error, that occurs for more than one file). Accumulations are useful when you want to note how often a given error occurs, without storing each instance (such as a coordinate error which could occur thousands of times within a program). Values: Accumulation, Individual, Both

4.3: dsErrMsgType

This identifies what type of error message is to be stored in the error instance. This structure is only used when specifying an error as it is added to a list or when a dsErrInstance is to be populated, but it tells the function in question whether to use the generic message, and fill in the elements with values the user provides, or to expect a format string from the user, which will be filled with values the user provides. Values: Custom, Generic

4.4: dsErrSeverity

This defines the severity of the error in question. Errors are either fatal or warnings, at present, with the exception of dsNOERR, which has a severity of NONE. The severity of an error is predefined, but an error list can be searched on the basis of severity. Values: None, Warning, Fatal

4.5: dsErrBool

This is a boolean. False is zero, true is one. Values: dsErrFalse, dsErrTrue

4.6: dsErrInstance

This is a specific instance of an error. While a generic error message is defined for each error code, that message may have elements that need to be filled in (such as a filename for i/o errors). A dsErrInstance will store the dsErrCode, it's severity, and a version of the generic message with any elements filled in. It will also store a count (a long) of the number of times that error has occurred, if it was an accumulation error. The count is zero if the Instance has not been populated. Elements: dsErr{ dsErrCode; dsErrSeverity; dsErrMsg; } count (a long, 1 if Individual, 1+ if Accumulation) error_type_e (indicates Individual/Accumulation)

4.7: dsErrList

This is a linked list that holds instances of errors. New errors can be added to the list, errors can be searched for, errors can be removed. In general new errors are added to the end of the list. The exception is accumulations. When you "add" an accumulation error, and there is another such accumulation error (same dsErrCode), then the count of the existent one is incremented. There are a few elements of a dsErrList that the user may find useful, in addition to the errors themselves. Elements: size(long, number of errors total) contains_fatal(long, number of fatal errors) contains_warning(long, number of warning errors)

4.8: dsErrGroup

This is a bit mask that defines which group's errors will be used within the library, when it is initialized. The generic errors are always used, this bit mask defines which groups in addition will be utilized. Values: dsPTGRPERR, dsPTDMGRPERR, dsPTNONSIGRPERR, dsPTINSTRGRPERR, dsPTANALGRPERR, dsASCFITERR, dsDBGRPERR dsPTGRPERR is comprised of the 4 other dsPT*GRPERR bit masks.

5. Functions

============ The examples are drawn in part from the dserror_test.c code, for those who are interested in seeing a working example.

5.1: Initialization, Creation, Close

The ASCDS Error library does attempt to take care of memory management for the user, but with certain caveats. The following functions must be used to initialize the library, and to create various structures the user will need, and then to close the library. In addition, the error lists won't operate correctly if dsErrCreateList is not used. No guarantees about memory leaks or proper operation of functions is given if the user starts manipulating the structures directly.

5.1.1: dsErrInitLib()

dsErrCode dsErrInitLib(dsErrGroup error_groups_t, char *tool_name_a) where error_groups_t - Input, bit mask that specifies which groups of errors to use in the error library environment. tool_name_a - Input, character array, containing the name of the tool, used by the old initialization routine. dsErrInitLib() is a wrapper around init_error_lib(), the previous error library initialization routine(which may still be used). dsErrInitLib() sets up a hash map which allows it to associate a dsErrCode with its severity and standard message. In addition, structures for internal memory management are initialized. The following groups are defined: dsPTGRPERR, dsASCFITERR, dsDBGRPERR Ex. dsErrGroup groups_to_add_t = dsDBGRPERR; dsErrCode local_errstat_t = dsNOERR; char func_name_a[] = {"this functions name"}; groups_to_add_t |= dsPTGRPERR; local_errstat_t = dsErrInitLib(groups_to_add_t, func_name); Return Codes: dsNOERR, dsALLOCERR, dsINITLIBERR

5.1.2: dsErrCreateInstance()

dsErrCode dsErrCreateInstance(dsErrInstance **error_instance_p) where error_instance_p - Update, this is the dsErrInstance structure to be allocated and initialized. dsErrCreateInstance() takes in a double dsErrInstance pointer, allocates memory for a dsErrInstance, and assigns it to the (dereferenced)input pointer. The dsErrInstance elements are initialized, and the address of the dsErrInstance is added to a list of dsErrInstances, to handle memory allocation. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrCode local_errstat_t = dsNOERR; local_errstat_t = dsErrCreateInstance(&holder_p); Return Codes: dsNOERR, dsALLOCERR

5.1.3: dsErrResetInstance()

void dsErrResetInstance(dsErrInstance *error_instance_p) where error_instance_p - Update, this is the dsErrInstance structure to be re-initialized. dsErrResetInstance() frees any memory allocated for the error message within the instance, and then reinitializes the elements of the instance. Ex. - Initialize library dsErrInstance *holder_p = NULL; dsErrCode local_errstat_t = dsNOERR; local_errstat_t = dsErrCreateInstance(&holder_p); - populate instance (see dsErrSetInstance(), below) - print instance (see dsErrPrintInstance(), below) dsErrResetInstance(holder_p);

5.1.4: dsErrCreateList()

dsErrCode dsErrCreateList(dsErrList **error_list_p) where error_list_p - Update, pointer to a pointer to a list of dsErrInstances dsErrCreateList() takes in a double dsErrList pointer, allocates memory for a dsErrList, and assigns it to the (dereferenced)input pointer. The dsErrList elements are initialized, and the address of the dsErrList is added to a list of dsErrLists, to handle memory allocation. Ex. - Initialize error library dsErrList *base_list_p = NULL; dsErrCode local_errstat_t = dsNOERR; local_errstat_t = dsErrCreateList(&base_list_p); Return Codes: dsNOERR, dsALLOCERR

5.1.5: dsErrCloseLib()

void dsErrCloseLib() dsErrCloseLib() frees memory for any dsErrInstances created via dsErrCreateInstance(), as well as the memory for their error messages. It also frees any nodes in dsErrLists that were created via dsErrCreateList(), including the memory for the error message in each node. The lists are then freed. Some other cleaning up is also performed. Ex. - Initialize error library - Utilize error library, and when done... dsErrCloseLib();

5.1.6: dsErrDirectOutput()

void dsErrDirectOutput(FILE *output_p) where output_p - Input, file pointer to send output to dsErrDirectOutput allows the user to send the error messages to a FILE *, including stderr or stdout. The default is stderr, and will be set when the library is initialized. There is nothing to prevent the user from resetting this multiple times in given tool. Ex. - Initialize error library FILE * err_log_p = NULL; err_log_p = fopen("logfile", "w"); if(err_log_p != NULL) { dsErrDirectOutput(err_log_p); }

5.2: Adding/Setting Errors

The user can either add errors to a dsErrList, or populate an isolated dsErrInstance. In either case, they must specify the dsErrCode, what type of message they want to use (the default, or a custom one), and the type of message. Any additional arguments are used to fill out the error message (in the case of default), or are interpreted as the error message (in the case of custom). If the proper types of arguments are not passed, the error message will end up with garbage in it.

5.2.1: dsErrAdd()

dsErrCode dsErrAdd(dsErrList *error_list_p, dsErrCode error_code_t, dsErrType error_type_e, dsErrMsgType msg_type_e, ...) where error_list_p - Input, error list to add to error_code_t - Input, error code to add to the list error_type_e - Input, error type of the error to add: Individual or Accumulation msg_type_e - Input, message type of the error to add: Custom or Generic ... - Input, elements to fill in in generic message, or the custom error message string and any elements it requires dsErrAdd() adds an error to a list. If the error is an individual error, or the first instance of an accumulation of that error code, the error is added to the end of the list. Otherwise increment the counter in the instance of the accumulation found in the list. The user must specify whether the error is to be an individual one, or an accumulation, and whether the generic message will be used, or a custom message provided by the user. If the former, the ... arguments must fill out the required elements in the generic message. If the message is to be a custom one, ... should have a character string as its' first element. That string may either be the entire custom message, or a formatting string, of the type used in printf, with consecutive arguments of the elipsis(...) filling out the elements in the formatting string. There are some rules about what types of values are allowed in the messages. Generic Message Parsing: The following types of values are allowed: char (c) string (s) short integer (hd) integer (d) long integer (ld) double (e|f|g) long double (L)(e|f|g) There is no provision currently for special formating of the elements. Only the strings in the parenthesis are allowed in the generic error messages. Ex. - initialize library dsErrList *base_list_p = NULL; dsErrCode local_errstat_t = dsNOERR; local_errstat_t = dsErrCreateList(&base_list_p); local_errstat_t = dsErrAdd(base_list_p, dsALLOCERR, Individual, Custom, "This is a custom memory allocation error message\n"); or local_errstat_t = dsErrAdd(base_list_p, dsEVENTCOORDSERR, Accumulation, Generic, NULL); and so on, varying the arguments for dsErrType and dsErrMsgType. Return Codes: dsNOERR, dsALLOCERR, dsUNDEFERR(an undefined value, positive for example, was passed in for the error code)

5.2.2: dsErrSetInstance()

dsErrCode dsErrSetInstance(dsErrCode error_code_t, dsErrType error_type_e, dsErrMsgType msg_type_e, dsErrInstance *error_instance_p, ...) where error_code_t - Input, error code to add to the list error_type_e - Input, error type of the error to add: Individual or Accumulation msg_type_e - Input, message type of the error to add: Custom or Generic error_instance_p - Output, error instance to populate. ... - Input, elements to fill in generic message dsErrSetInstance() follows the same rules as dsErrAdd() except that instead of adding a new node, error_instance_p is repopulated. In the case that an accumulation is set, if error_instance_p is already populated by an accumulation of the same dsErrCode, the count will be incremented. Ex. - initialize library dsErrInstance *holder_p = NULL; dsErrCode local_errstat_t = dsNOERR; local_errstat_t = dsErrCreateInstance(&holder_p); if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) Return Codes: dsNOERR, dsALLOCERR, dsUNDEFERR(an undefined value, positive for example, was passed in for the error code)

5.2.3: dsErrAddToEnd()

dsErrCode dsErrAddToEnd(dsErrList *error_list_p, dsErrInstance *error_to_add_p) where error_list_p - Input, list to add the error to error_to_add_p - Input, error instance to add dsErrAddToEnd() takes a pointer to a dsErrInstance that has already been populated, and adds it to the input error list, at the end. No effort is made to handle situations in which the error is an instance of an accumulation that already exists in the list. Ex. - Initialize library dsErrInstance *holder_p = NULL; dsErrList *base_list_p = NULL; dsErrCode local_errstat_t = dsNOERR; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { local_errstat_t = dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double"); if(local_errstat_t == dsNOERR) dsErrAddToEnd(base_list_p, holder_p); } Return Codes: dsNOERR, dsALLOCERR

5.3: Searching for Errors in an Error List

The user can search a list of errors in a number of ways. They can search by location, search for a specific error code, or search for a given severity. They can also search for only the first match, or they can search for all matches. In the first case they must provide a dsErrInstance to populate, in the second they must provide a dsErrList. Searches can be done in an exclusive manner, rather than inclusive. In addition there are a number of functions that mimic the functionality of the "Look" functions, but rather than copying the data, they return a dsErrInstance pointer to the errors found. These are the "Peek" functions (there are no PeekAll functions, for obvious reasons).

5.3.1: dsErrLook()

dsErrCode dsErrLook(dsErrList *error_list_p, dsErrInstance *out_instance_p) where error_list_p - Input, error list to look in out_instance_p - Output, error instance structure to populate with results of search dsErrLook() copies the first error in error_list_p to out_instance_p. If there are no errors in the list, dsERRNOTFOUNDERR is returned. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrList *base_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { - populate error list if(dsErrLook(base_list_p, holder_p) == dsNOERR) . . . Return Codes: dsNOERR, dsALLOCERR, dsERRNOTFOUNDERR

5.3.2: dsErrLookN()

dsErrCode dsErrLookN(dsErrList *error_list_p, long N, dsErrInstance *out_instance_p) where error_list_p - Input, error list to look in N - Input, element in the list to find out_instance_p - Output, error instance structure to populate with results of search dsErrLookN() finds the Nth error in the error list and copies it into out_instance_p. If N is larger than the number of elements in the list, or if N is less than 1, dsERRNOTFOUNDERR is returned. N starts counting at 1. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrList *base_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { - populate error list if(dsErrLookN(base_list_p, 1, holder_p) == dsNOERR) . . . Return Codes: dsNOERR, dsALLOCERR, dsERRNOTFOUNDERR

5.3.3: dsErrLookCode()

dsErrCode dsErrLookCode(dsErrList *error_list_p, dsErrCode error_code_t, dsErrType error_type_e, dsErrInstance *out_instance_p) where error_list_p - Input, error list to look in error_code_t - Input, error code to search for error_type_e - Input, error type to search for out_instance_p - Output, error instance structure to populate with results of search dsErrLookCode() searches error_list_p for the first instance of an error whose code matches error_code_t, and whose type matches error_type_e. If error_type_e is Both, then either Individual or Accumulations will be matched. If a match is found, it is copied to out_instance_p, otherwise dsERRNOTFOUNDERR is returned. Ex. - Initialize error library, dsErrInstance *holder_p = NULL; dsErrList *base_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { - populate error list if(dsErrLookCode(base_list_p, dsEVENTCOORDSERR, Both, holder_p) == dsNOERR) . . . or if(dsErrLookCode(base_list_p, dsEVENTCOORDSERR, Accumulation, holder_p) == dsNOERR) . . . and so forth. Return Codes: dsNOERR, dsALLOCERR, dsERRNOTFOUNDERR

5.3.4: dsErrLookCodeExcl()

dsErrCode dsErrLookCodeExcl(dsErrList *error_list_p, dsErrCode error_code_t, dsErrType error_type_e, dsErrInstance *out_instance_p) where error_list_p - Input, error list to look in error_code_t - Input, error code to exclude error_type_e - Input, error type to exclude out_instance_p - Output, error instance structure to populate with results of search dsErrLookCodeExcl() operates in the same manner as dsErrLookCode(), except that it searches for the first instance that does not match the input code and type. Return Codes: dsNOERR, dsALLOCERR

5.3.5: dsErrLookSev()

dsErrCode dsErrLookSev(dsErrList *error_list_p, dsErrSeverity err_severity_e, dsErrInstance *out_instance_p) where error_list_p - Input, error list to look in error_severity_t - Input, error severity to search for out_instance_p - Output, error instance structure to populate with results of search dsErrLookSev() searches error_list_p for the first error that matches the input severity type. If a match is found, it is copied to out_instance_p, else dsERRNOTFOUNDERR is returned. Ex. - Initialize error library, dsErrInstance *holder_p = NULL; dsErrList *base_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { - populate error list if(dsErrLookSev(base_list_p, Fatal, holder_p) == dsNOERR) . . . Return Codes: dsNOERR, dsALLOCERR, dsERRNOTFOUNDERR

5.3.6: dsErrLookAllSev()

dsErrCode dsErrLookAllSev(dsErrList *in_list_p, dsErrSeverity err_severity_e, dsErrList *out_list_p) where in_list_p - Input, error list to look in error_severity_t - Input, error severity to search for out_list_p - Output, error list to populate with results of search dsErrLookAllSev() searches in_list_p for all errors with the input severity, and copies them to out_list_p, in the order they were found. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrList *base_list_p = NULL; dsErrList *new_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR && dsErrCreateList(&new_list_p) == dsNOERR) { - populate base_list_p if(dsErrLookAllSev(base_list_p, Fatal, new_list_p) == dsNOERR) . . . Return Codes: dsNOERR, dsALLOCERR

5.3.7: dsErrLookAllCode()

dsErrCode dsErrLookAllCode(dsErrList *in_list_p, dsErrCode error_code_t, dsErrType error_type_e, dsErrList *out_list_p) where in_list_p - Input, error list to look in error_code_t - Input, error code to search for error_type_e - Input, error type to search for out_list_p - Output, error list to populate with results of search dsErrLookAllCode() searches in_list_p for all errors whose code matches error_code_t, and whose type matches error_type_e. If error_type_e is Both, then either Individual or Accumulations will be matched. All matches are copied into out_list_p in the order they were found. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrList *base_list_p = NULL; dsErrList *new_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR && dsErrCreateList(&new_list_p) == dsNOERR) { - populate base_list_p if(dsErrLookAllCode(base_list_p, dsEVENTCOORDSERR, Individual, new_list_p) == dsNOERR) . . . and so forth. Return Codes: dsNOERR, dsALLOCERR

5.3.8: dsErrLookAllCodeExcl()

dsErrCode dsErrLookAllCodeExcl(dsErrList *in_list_p, dsErrCode error_code_t, dsErrType error_type_e, dsErrList *out_list_p) where in_list_p - Input, error list to look in error_code_t - Input, error code to exclude error_type_e - Input, error type to exclude out_list_p - Output, error list to populate with results of search dsErrLookAllCodeExcl() operates as dsErrLookAllCode() does, except it searches for all errors that do not match the input code and type. Return Codes: dsNOERR, dsALLOCERR

5.3.9: dsErrGetNumOccur()

long dsErrGetNumOccur(dsErrList *error_list_p, dsErrCode error_code_t, dsErrType error_type_e) where error_list_p - Input, the error list to look in error_code_t - Input, error code to search for error_type_e - Input, error type to search for dsErrGetNumOccur() searches error_list_p for all errors whose code matches error_code_t, and whose type matches error_type_e. If error_type_e is Both, then either Individual or Accumulations will be matched. If an error is matched, then the count of that error is added to the value that will be returned. This is not to be confused with returning the number of nodes in the list that match the conditions. Accumulations can have a count well above one, and the returned value will represent that. Ex. - Initialize error library dsErrList *base_list_p = NULL; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p long error_count = dsErrGetNumOccur(base_list_p, dsEVENTCOORDSERR, Individual); printf("The number of dsEVENTCOORDSERRs is: %ld\n", error_count); }

5.3.10: dsErrPeek()

dsErrInstance *dsErrPeek(dsErrList *error_list_p) where error_list_p - Input, error list to look in dsErrPeek() returns a pointer to the first error in error_list_p. If there are no errors in the list, NULL is returned. Ex. - Initialize error library dsErrInstance *pointer_p = NULL; dsErrList *base_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { - populate error list if((pointer_p = dsErrPeek(base_list_p)) != NULL) . . . Return Values: NULL or valid address

5.3.11: dsErrPeekN()

dsErrInstance *dsErrPeekN(dsErrList *error_list_p, long N) where error_list_p - Input, error list to look in N - Input, element in the list to find dsErrPeekN() finds the Nth error in the error list and returns its' address. If N is larger than the number of elements in the list, or if N is less than 1, NULL is returned. N starts counting at 1. Ex. - Initialize error library dsErrInstance *pointer_p = NULL; dsErrList *base_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { - populate error list if((pointer_p = dsErrPeekN(base_list_p, 1)) != NULL) . . . Return Values: NULL or valid address

5.3.12: dsErrPeekCode()

dsErrInstance *dsErrPeekCode(dsErrList *error_list_p, dsErrCode error_code_t, dsErrType error_type_e) where error_list_p - Input, error list to look in error_code_t - Input, error code to search for error_type_e - Input, error type to search for dsErrPeekCode() searches error_list_p for the first instance of an error whose code matches error_code_t, and whose type matches error_type_e. If error_type_e is Both, then either Individual or Accumulations will be matched. If a match is found, its address is returned, otherwise NULL is returned. Ex. - Initialize error library, dsErrInstance *pointer_p = NULL; dsErrList *base_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { - populate error list if((pointer_p = dsErrPeekCode(base_list_p, dsEVENTCOORDSERR, Both)) != NULL) . . . or if(dsErrLookCode(base_list_p, dsEVENTCOORDSERR, Accumulation, holder_p) == dsNOERR) . . . and so forth. Return Values: NULL or valid address

5.3.13: dsErrPeekCodeExcl()

dsErrInstance *dsErrPeekCodeExcl(dsErrList *error_list_p, dsErrCode error_code_t, dsErrType error_type_e) where error_list_p - Input, error list to look in error_code_t - Input, error code to exclude error_type_e - Input, error type to exclude dsErrPeekCodeExcl() operates in the same manner as dsErrPeekCode(), except that it searches for the first instance that does not match the input code and type. Return Values: NULL or valid address

5.3.14: dsErrPeekSev()

dsErrInstance *dsErrPeekSev(dsErrList *error_list_p, dsErrSeverity err_severity_e) where error_list_p - Input, error list to look in error_severity_t - Input, error severity to search for dsErrPeekSev() searches error_list_p for the first error that matches the input severity type. If a match is found, its address is returned, else NULL is returned. Ex. - Initialize error library, dsErrInstance *pointer_p = NULL; dsErrList *base_list_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR && dsErrCreateList(&base_list_p) == dsNOERR) { - populate error list if((pointer_p = dsErrPeekSev(base_list_p, Fatal)) != NULL) . . . Return Values: NULL or valid address

5.4: Removing Errors from Error Lists

In all the remove functions, memory that was allocated for the error that is removed, and the node, is freed in the function.

5.4.1: dsErrRemove()

dsErrBool dsErrRemove(dsErrList *error_list_p) where error_list_p - Input, error list to Remove in dsErrRemove() removes the first error in error_list_p. Ex. - Initialize error library dsErrList *base_list_p = NULL; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p dsErrRemove(base_list_p); . . . Return Codes: dsErrTrue, dsErrFalse

5.4.2: dsErrRemoveN()

dsErrBool dsErrRemoveN(dsErrList *error_list_p, long N) where error_list_p - Input, error list to Remove in N - Input, element in the list to find dsErrRemoveN() finds the Nth error in the error list and removes it. If N is larger than the number of elements in the list, or if N is less than 1, dsErrFalse is returned. N starts counting at 1. Ex. - Initialize error library dsErrList *base_list_p = NULL; long element_to_remove = 2; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p dsErrRemoveN(base_list_p, element_to_remove); . . . Return Codes: dsErrTrue, dsErrFalse

5.4.3: dsErrRemoveCode()

dsErrBool dsErrRemoveCode(dsErrList *error_list_p, dsErrBool error_code_t, dsErrType error_type_e) where error_list_p - Input, error list to Remove in error_code_t - Input, error code to search for error_type_e - Input, error type to search for dsErrRemoveCode() searches error_list_p for the first instance of an error whose code matches error_code_t, and whose type matches error_type_e. If error_type_e is Both, then either Individual or Accumulations will be matched. If a match is found, it is removed, otherwise dsErrFalse is returned. Ex. - Initialize error library dsErrList *base_list_p = NULL; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p dsErrRemoveCode(base_list_p, dsALLOCERR, Individual); or dsErrRemoveCode(base_list_p, dsEVENTCOORDSERR, Accumulation); and so forth . . . Return Codes: dsErrTrue, dsErrFalse

5.4.4: dsErrRemoveSev()

dsErrBool dsErrRemoveSev(dsErrList *error_list_p, dsErrSeverity err_severity_e) where error_list_p - Input, error list to Remove in error_severity_t - Input, error severity to search for dsErrRemoveSev() searches error_list_p for the first error that matches the input severity type. If a match is found, it is removed, else dsErrFalse is returned. Ex. - Initialize error library dsErrList *base_list_p = NULL; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p dsErrRemoveSev(base_list_p, Fatal); . . . Return Codes: dsErrTrue, dsErrFalse

5.4.5: dsErrRemoveAll()

dsErrBool dsErrRemoveAll(dsErrList *error_list_p) where error_list_p - Input, error list to Remove errors from dsErrRemoveAll() removes all the errors from a list. It returns dsErrFalse only if there were no errors to remove. Ex. - Initialize error library dsErrList *base_list_p = NULL; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p dsErrRemoveAll(base_list_p); . . . Return Codes: dsErrTrue, dsErrFalse

5.4.6: dsErrRemoveAllSev()

dsErrBool dsErrRemoveAllSev(dsErrList *in_list_p, dsErrSeverity err_severity_e) where in_list_p - Input, error list to Remove in error_severity_t - Input, error severity to search for dsErrRemoveAllSev() searches in_list_p for all errors with the input severity, and removes them. Ex. - Initialize error library dsErrList *base_list_p = NULL; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p dsErrRemoveAllSev(base_list_p, Fatal); . . . Return Codes: dsErrTrue, dsErrFalse

5.4.7: dsErrRemoveAllCode()

dsErrBool dsErrRemoveAllCode(dsErrList *in_list_p, dsErrBool error_code_t, dsErrType error_type_e) where in_list_p - Input, error list to Remove in error_code_t - Input, error code to search for error_type_e - Input, error type to search for dsErrRemoveAllCode() searches in_list_p for all errors whose code matches error_code_t, and whose type matches error_type_e. If error_type_e is Both, then either Individual or Accumulations will be matched. All matches are removed. Ex. - Initialize error library dsErrList *base_list_p = NULL; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p dsErrRemoveAllCode(base_list_p, dsALLOCERR, Individual); or dsErrRemoveAllCode(base_list_p, dsEVENTCOORDSERR, Accumulation); and so forth . . . Return Codes: dsErrTrue, dsErrFalse

5.5: Processing Error Instances and Error Lists

These functions are all wrappers around the existent error processing routines in the error library; err_msg, err_exit, err_quit, err_ret, and err_dump. See the other error lib document for more information on what these tasks do. There is only one function that will process an entire list, dsErrPrintList(). This is a wrapper around err_msg(), which is the only one of the above five functions that does not return or exit the program. All of the processing functions take an argument specifying whether or not they should print out the number of times an accumulation error occurs. If the user says yes, then the following string will be prepended to the dsErrInstance error message: "The following error occurred %d times:\n\t%s" where %d is filled in with the number of times the error occurred, and %s is the actual error message. The user will not need to supply these, it is done internally to the functions.

5.5.1: dsErrPrintList()

void dsErrPrintList(dsErrList *error_list_p, dsErrBool print_accum_e) where error_list_p - Input, list to print print_accum_e - Input, flag indicating whether or not to print the count of an accumulation error. dsErrPrintList() is a wrapper around the existent error library function err_msg(). It will print the dsErrInstance's error message to stderr for each node in the list. Ex. - Initialize error library dsErrList *base_list_p = NULL; if(dsErrCreateList(&base_list_p) == dsNOERR) { - populate base_list_p . . . } dsErrPrintList(base_list_p, dsErrTrue);

5.5.2: dsErrPrintInstance()

void dsErrPrintInstance(dsErrInstance *error_instance_p, dsErrBool print_accum_e) where error_instance_p - Input, instance to print print_accum_e - Input, flag indicating whether or not to print the count of an accumulation error. dsErrPrintInstance() is a wrapper around err_msg(). It prints the dsErrInstance's error message to stderr. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrCode local_errstat_t = dsNOERR; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { dsErrPrintInstance(holder_p, dsErrTrue); } }

5.5.3: dsErrReturnInstance()

void dsErrReturnInstance(dsErrInstance *error_instance_p, dsErrBool print_accum_e) where error_instance_p - Input, instance to print print_accum_e - Input, flag indicating whether or not to print the count of an accumulation error. dsErrReturnInstance() is a wrapper around err_ret(). It prints the dsErrInstance's error message to stderr, and returns. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrCode local_errstat_t = dsNOERR; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { dsErrReturnInstance(holder_p, dsErrTrue); } }

5.5.4: dsErrExitInstance()

void dsErrExitInstance(dsErrInstance *error_instance_p, dsErrBool print_accum_e) where error_instance_p - Input, instance to print print_accum_e - Input, flag indicating whether or not to print the count of an accumulation error. dsErrExitInstance() is a wrapper around err_exit(). It prints the dsErrInstance's error message to stderr, and terminates. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrCode local_errstat_t = dsNOERR; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { dsErrExitInstance(holder_p, dsErrTrue); } }

5.5.5: dsErrQuitInstance()

void dsErrQuitInstance(dsErrInstance *error_instance_p, dsErrBool print_accum_e) where error_instance_p - Input, instance to print print_accum_e - Input, flag indicating whether or not to print the count of an accumulation error. dsErrQuitInstance() is a wrapper around err_quit(). It prints the dsErrInstance's error message to stderr, and terminates. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrCode local_errstat_t = dsNOERR; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { dsErrQuitInstance(holder_p, dsErrTrue); } }

5.5.6: dsErrDumpInstance()

void dsErrDumpInstance(dsErrInstance *error_instance_p, dsErrBool print_accum_e) where error_instance_p - Input, instance to print print_accum_e - Input, flag indicating whether or not to print the count of an accumulation error. dsErrDumpInstance() is a wrapper around err_dump(). It prints the dsErrInstance's error message to stderr, dumps core, and terminates. Ex. - Initialize error library dsErrInstance *holder_p = NULL; dsErrCode local_errstat_t = dsNOERR; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { dsErrDumpInstance(holder_p, dsErrTrue); } }

5.6: Accessor Functions for Error Instances and Error Lists

=========================================================== The following are a series of simple accessor functions that return various data members of the dsErrLists and dsErrInstances.

5.6.1: dsErrGetErrorCt()

long dsErrGetErrorCt(dsErrList *error_list_p) where error_list_p - Input, error list to get the number of nodes of dsErrGetErrorCt() returns the number of dsErrInstances (essentially the number of nodes) in the input error list. Ex. - Initialize error library dsErrList *list_p = NULL; if(dsErrCreateList(&list_p) == dsNOERR) { - populate the list... long list_size = dsErrGetErrorCt(list_p); printf("The number of errors in the list is %ld.\n", list_size); }

5.6.2: dsErrGetFatalCt()

long dsErrGetFatalCt(dsErrList *error_list_p) where error_list_p - Input, error list to get the number of fatal errors of dsErrGetFatalCt() returns the number of dsErrInstances (essentially the number of nodes) in the input error list with a severity of Fatal. Ex. - Initialize error library dsErrList *list_p = NULL; if(dsErrCreateList(&list_p) == dsNOERR) { - populate the list... long list_size = dsErrGetFatalCt(list_p); printf("The number of fatal errors in the list is %ld.\n", list_size); }

5.6.3: dsErrGetWarningCt()

long dsErrGetWarningCt(dsErrList *error_list_p) where error_list_p - Input, error list to get the number of warnings of dsErrGetWarningCt() returns the number of dsErrInstances (essentially the number of nodes) in the input error list with a severity of Warning. Ex. - Initialize error library dsErrList *list_p = NULL; if(dsErrCreateList(&list_p) == dsNOERR) { - populate the list... long list_size = dsErrGetWarningCt(list_p); printf("The number of warnings in the list is %ld.\n", list_size); }

5.6.4: dsErrGetInstCt()

long dsErrGetInstCt(dsErrInstance *error_instance_p) where error_instance_p - Input, error instance to return the value of the count accumulator of. dsErrGetInstCt() returns the value of the count element of the data structure, which for an Individual error will be one, and for Accumulations may be greater than one. Ex. - Initialize error library dsErrInstance *holder_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { long instance_count = dsErrGetInstCt(holder_p); printf("The number of times the dsCOLUMNTYPEERR occurred is:"); printf(" %ld\n", instance_count); } }

5.6.5: dsErrGetInstCode()

dsErrCode dsErrGetInstCode(dsErrInstance *error_instance_p) where error_instance_p - Input, error instance to return the value of the dsErrCode. dsErrGetInstCode() returns the dsErrCode of the error stored within the dsErrInstance, which is essentially a long. Ex. - Initialize error library dsErrInstance *holder_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { dsErrCode instance_code = dsErrGetInstCode(holder_p); printf("The error code of dsCOLUMNTYPEERR is:"); printf(" %ld\n", instance_code); } }

5.6.6: dsErrGetInstSev()

dsErrSeverity dsErrGetInstSev(dsErrInstance *error_instance_p) where error_instance_p - Input, error instance to return the value of the dsErrSeverity. dsErrGetInstCode() returns the dsErrSeverity of the error stored within the dsErrInstance. Ex. - Initialize error library dsErrInstance *holder_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { dsErrSeverity instance_sev = dsErrGetInstSev(holder_p); printf("The error severity of dsCOLUMNTYPEERR is:"); printf(" %s\n", ((instance_sev == Fatal) ? "Fatal" : "Warning")); } }

5.6.7: dsErrGetInstMsg()

dsErrMsg dsErrGetInstMsg(dsErrInstance *error_instance_p) where error_instance_p - Input, error instance to return the value of the dsErrMsg. dsErrGetInstCode() returns the dsErrMsg of the error stored within the dsErrInstance, which is essentially a char *. Ex. - Initialize error library dsErrInstance *holder_p = NULL; if(dsErrCreateInstance(&holder_p) == dsNOERR) { if(dsErrSetInstance(dsCOLUMNTYPEERR, Individual, Generic, holder_p, "foo", "not-a-file", "double") == dsNOERR) { printf("The error message of dsCOLUMNTYPEERR is:"); printf(" %s\n", dsErrGetInstMsg(holder_p)); } }

5.7: Signal Handling

The error library has a singal handler for three signals: SIGSEGV (segmentation violation), SIGFPE (floating point error), and SIGILL (illegal instruction). The user is strongly suggested to add the following line to their main before initializing the error library: setjmp(dserr_jmpbuf); This will allow the error library to have a location to junp to in the case of catching one of these signals.

6. How to Add Errors to the Library

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

6.1 The Error Elements

An error in the DS error library is defined by three elements: an Error Code, a Severity, and a Standard Message. The following serve as examples: #define dsNOERR dsGENERALERROFFSET #define dsNOERRSEV dsERRSEVNONE #define dsNOERRSTDMSG "" and #define dsGENERICERR (dsGENERALERROFFSET - 1) #define dsGENERICSEV dsERRSEVWARNING #define dsGENERICSTDMSG "WARNING: An unspecified error has occurred.\n" These are the first two errors defined in the error library. In general the format is: #define dsERR (ds - ) #define dsSEV dsERRSEVWARNING/dsERRSEVFATAL #define dsSTDMSG ""

6.1.1 The error number:

#define dsERR (ds - ) The error number is usually defined relative to an offset. There are two sorts of offsets, one for groups, and one for subgroups. The group offsets tend to be larger, and are defined on the basis of teams or large projects. So far the group offsets are: dsGENERALERROFFSET 0 dsPTDMTOOLERROFFSET -2000 dsPTINSTRUMENTERROFFSET -3000 dsPTANALYSISERROFFSET -4000 dsPTNONSIERROFFSET -5000 dsDATABASEERROFFSET -8000 There will also be one for the ASC Fitting Engine, and most likely a separate offset for the Pixlib, although both of those are maintained by the Pipe/Tools team. The subgroups are currently only used within the general errors group, as this is the one most likely to have new errors inserted, rather than merely appended. They are defined as follows: dsGENCOLKEYOFFSET (dsGENERALERROFFSET - 25) dsGENFIOOFFSET (dsGENCOLKEYOFFSET - 25) dsGENDMOFFSET (dsGENFIOOFFSET - 25) dsGENPARAMOFFSET (dsGENDMOFFSET - 50) dsGENASCFITOFFSET (dsGENPARAMOFFSET - 25) dsGENTIMEOFFSET (dsGENASCFITOFFSET - 25) dsGENSTACKOFFSET (dsGENTIMEOFFSET - 25) As can be seen, they are defined in a chain like manner, and set the starting point for various smaller groups of errors. It is important to note, that if a sub group grows beyond 25 errors, then these numbers will need to be modified, i.e., if the parameter errors (governed by the dsGENPARAMOFFSET) grow to 27 errors, then they will overlap with the ASCFit errors (governed by dsGENASCFITOFFSET). In that case dsGENASCFITOFFSET should be redefined to dsGENPARAMOFFSET - 50.

6.1.2 The error severity:

#define dsSEV dsERRSEVWARNING/dsERRSEVFATAL There are only two options for this, dsERRSEVWARNING or dsERRSEVFATAL.

6.1.3 The generic error message:

#define dsSTDMSG "" This can be whatever is desired, and may contain % type elements, like the formating strings used in printf and so forth, with the restrictions outlined in section 5.2.1 about parsing. The string must start with either ERROR or WARNING, depending on the severity, and should end in a newline.

6.2 Location of the Error

The errors are defined in a group of header files, which are defined by the groups in the ASCDS. Currently there is a header file for the Pipe Tools team, and the Database team. If you are a member of one of those teams, then your error should go into one of those headers, with the exception of generic errors. The generic error header file contains errors that anyone in the ASCDS or even within a group, is likely to run into. They are errors that have to do with interfaces to libraries (stack, param, ASCFit, Data Model), allocation errors, file I/O and so forth. The following are the existent error header files: dserror_general.h ----> generic errors dserror_database.h ---> errors for the database team dserror_pt{var}.h ----> various headers that include errors for the pipe/tools teams, grouped by broad categories If the error that is being added does not belong in one of these headers (i.e, it is not generic, and is a new group), then the maintainer of the error library needs to be contacted in order to add a new header file to the library. Otherwise, the individual will be able to add the error to the library on their own. In order to do this, the three elements of the new error are added to the header file. If the new error is inserted into the header file, rather than appended to the end, then the error number value of all consecutive errors must be adjusted - the errors should be define in numerical order in the header file. In either case, in each header file there is a macro that defines the number of errors in that header file. This has to be updated to reflect the addition of the new error(s). Please NOTE: If you are adding a series of errors, that pertain to a tool/library, to a group initialization function, please precede them with a comment indicating the tool/library that they pertain to. This way groupings can be easier to discern. Likewise for a series of generic errors that have a common thread.

6.3 Modifying the code to place the error in the hash map

Provided that the new error(s) have been added to a header file that already exists, the last thing the user needs to do is to modify one of a number of initialization helper functions. In the C file dserror_init.c there are a number of functions that help the dsErrInitLib() function. They are dsErrInitGeneralErr(), dsErrInitPTErr(), and dsErrInitDBErr(), and they correspond to one of each of the header files. Each of them calls dsErrInitHashMapElement() a number of times. In order to add a new error, add another call to the appropriate init function, substituting the macros that you defined for the error. It is very important that the errors in the library be initialized in numerical order. To that end it is best to define them in the header file in numerical order, and then have the dsErrInitHashMapElement() calls occur in the same order the errors were defined in. Thus, if an error is INSERTED into the header file, it will need to be inserted into the function call in the initialization routine, in the same location. If an error is merely added to the end of a header file, then add the function call to the end of the initialization routine. That is what is required to add an error to the library. Please NOTE: If you are adding to a groups initialization function a series of errors that pertain to a tool/library, please precede them with a comment indicating the tool/library that they pertain to. This way groupings can be easier to discern. Likewise for a series of generic errors that have a common thread.

Debug and Function Tracing

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

7.1 Function Tracing

In code development, it is sometimes difficult to determine which function an error is occurring in. To help following the function calls made, the error library supplies some functions to trace the function calls. The functions called are tracked by means of a heap/stack. All function tracing routines are described in detail below. The user must begin by calling the function init_function_stack(). After entering a function, the user must call check_in("function name"). This will add the "function name" onto the heap of functions that have been called. Before exiting a function, the user must call check_out() to clear the function stack of this function. The internal data structure used is a stack given its first-in-last-out (filo) model.

7.2 Routines for Function Tracing

Below are the public routines for function tracing

7.2.1 init_function_stack()

void init_function_stack(char * name, int print_it, int num_fct_to_print) where name - Input, name of the program, preferably argv[0] print_it - Input, print messages upon entry and exit of a function num_fct_to_print - Input, if positive, only the requested number of function names will be printed, otherwise, all of the function names will be printed. init_function_stack() sets the output options for using the function tracing. The stack is set to NULL in this function. Ex. - Initialize the function stack init_function_stack("my_code",1,-1); will use "my_code" as the main program name and will print out messages for all functions

7.2.2 check_in()

void check_in(char * name) where name - Input, function name to be added to the stack check_in() will added the name to the stack. If print_it was set, a message will be printed here. Ex int my_function(void) { int print_flag=1; check_in("my_function"); /* checks in the function */ if (print_flag) printf("Hello World!\n"); check_out(); /*check out the function */ }

7.2.3 check_out()

void check_out() check_out() will remove the top function name on the stack. If print_it was set, a message will be printed here. Ex int my_function(void) { int print_flag=1; check_in("my_function"); /* checks in the function */ if (print_flag) printf("Hello World!\n"); check_out(); /*check out the function */ }

7.2.4 exit_upon_error()

int exit_upon_error(long exit_code, char * format, ...) where exit_code - Input, exit value to test. If non-zero, this routine will force the program to exit with this value. format - Input, format string including the standard C format codes. ... - Input, any arguments to the format string exit_upon_error() will check if the exit_code is non-zero. If it is, then the format string and any extra variables are printed via vfprintf. It is the user's responsibility to supply all arguments needed. A segmentation violation may occur if a variable substitution is to occur and the variable is not supplied. Ex. foo=my_function(); exit_upon_error(foo,"my_function failed with error code %d\n",foo); NOTE: It is bad practice for the user to use this function for anything, but debugging purposes. To exit within a function will prevent other libraries from properly closing down and may prevent other error messages from being reported.

7.2.5 print_function_stack()

void print_function_stack(FILE * fp) where fp - Input, function stack is printed to this file stream print_function_stack() will print the current function stack when called. Ex. foo=my_function(); print_function_stack(stderr); /* print the function stack */ NOTE: In general, this should only be used for debugging purposes.

8. Synopsis of Defined Errors

============================= Errors in the dserror_general.h file: Various Misc: allocation, divide by zero, null ptr received, etc. Column and Keyword Errors. File I/O Errors. *Data Model Errors. *Parameter Library Errors. *ASC Fitting Engine Errors. Timing Errors. *Stack Library Errors. * These aren't errors that occur within the named library, but occur in utilizing it within a tool, i.e., a library function failed, etc. Errors in the dserror_ptdmtools.h file: dmhedit dmsort dmwritefef dmextract dmregrid Errors in the dserror_ptinstrument.h file: acis_process_events acis_format_events acis_collate_events acis_build_chip_gti acis_merge_gti hrc_process_events hrc_calc_dead_time hrc_build_badpix hrc_merge_times tg_resolve_events tg_create_mask Errors in the dserror_ptnonsi.h file: mtl_build_table mtl_build_gti asp_calc_offsets asphist ephem_calc_vg_angles tel_data_clean sim_data_select sim_compute_stf_pos obi_merge_times obi_sim_look obi_eng_look obi_asp_look obi_check_tol calc_mean_pointing obi_acishk_look obi_hrchk_look obspar_upd Errors in the dserror_ptanalysis.h file: wrecon wtransform celldetect bkgd_calc_global_count_rate tcd specific csmooth rmfcalc lightcurve