Planetary Data System Label Library Light (L3) - Version 1.1 User's Guide S. Hughes, D. Bernath, S. Monk February 3, 1998 1.0 Introduction This user's guide describes Version 1.1 of the PDS Label Library Light (L3). It describes a set of library routines that allow the access and manipulation of PDS object descriptions in ODL labels. This implementation was based on requirements [2] extrapolated from the original ODL label library, requirements gathered from the PDS discipline nodes, and several years of user input. This introduction continues with a section on available platforms, definitions, and the list of functions that are described in this document. Section two of this document includes a brief discussion of the scope of the proposed library. Section three describes the implementation and includes four sub-sections: the C function prototypes, function parameter descriptions, error and return status codes, and design notes. Appendix A includes an example of a simple program and library function calls. Appendix B list differences that exist between the design document and the actual implementation. Appendix C includes the definitions of the OBJDESC and KEYWORD "C" structures used to build the ODL parse tree. 1.1 Available Platforms The label library light (L3) code has been successfully tested on the following platforms. Sun Sparc/SunOS, Solaris SGI/Irix Macintosh 64K, PowerPC IBM PC/Dos, Windows, NT Dec VAX/VMS Dec Alpha/OpenVMS, OSF Dec 3100/Ultrix When compiling, a platform-specific symbol may be needed in order to select appropriate platform-specific code. OAL requires this on all platforms, but L3 can be compiled separately from OAL, and requires it only on two platforms: IBM/PC: define IBM_PC and Macintosh: define MAC. See the OAL User's Guide [4] pg. 8 for more information on compiling. 1.2 Definitions The label library parses and allows manipulation ODL labels. The following example ODL label and definitions will help in the understanding the subsequent library functions. RECORD_TYPE = FIXED_LENGTH RECORD_BYTES = 1000 FILE_RECORDS = 814 /* Image Object */ OBJECT = IMAGE LINES = 800 LINE_SAMPLES = 800 SAMPLE_BITS = 8 SAMPLE_TYPE = UNSIGNED_INTEGER END_OBJECT Figure 1. Example ODL Label An ODL label is an ASCII file that can either be attached to or detached from the data it is describing. Figure 1 illustrates a partial attached label for a spacecraft camera image. In this label the first three statements describe the file in which the label and the data are contained. This part of the label is considered part of the "implicit" FILE object. The following six statements describe an image in the file by explicitly declaring an IMAGE object and supplying four attributes of that image. The ODL language specification can be found in the PDS Standards Reference. [5] A ODL is expressed syntactically as = where is the name of a data element and where is a character string to be assigned to the data element. The must meet semantic constraints specified in the PDS Standards Reference [5]. A value delimited by "{" and "}" represents a SET and a value delimited by "(" and ")" represents a SEQUENCE. Both SET and SEQUENCE are classified as collections. An ODL is the token to the left of the equal ("=") sign in the = statement. In approved PDS labels, it is the name of a data element defined in the Planetary Science Data Dictionary (PSDD) [6]. It typically represents an attribute of an object. An ODL consists of the set of ODL statements delimited by the "OBJECT = " and "END_OBJECT = " statements. Once parsed, the keyword names and values are stored in a OBJDESC structure. The of the object is the value in the "OBJECT = " statement and specifies the general classification of the object described. A list of all approved PDS objects can be found in [5]. An ODL is the instantiation of an ODL object description. Instantiation occurs within a software tool that parses ODL object descriptions (labels) and instantiates the object with the specified attributes and a set of functions that manipulate the object. An ODL is the instantiation of an ODL object description. A ODL data object is distinct from an ODL object (see above) since it has associated data. (e.g. image) Instantiation occurs within a software tool that parses ODL object descriptions and instantiates the object with the specified attributes, data, and a set of functions that manipulate the object. 1.3 Function Index The following is a list of the functions described in this document. 3.1.1 Label Access Function Prototypes 3.1.1.1 Parsing Function Prototypes 3.1.1.1.1 OdlParseLabelFile 3.1.1.1.2 OdlExpandLabelFile 3.1.1.1.3 OdlParseLabelString 3.1.1.2 Object Description Function Prototypes 3.1.1.2.1 OdlFindObjDesc 3.1.1.2.x OdlGetObjDescxxx 3.1.1.2.2 OdlGetLabelVersion 3.1.1.2.3 OdlGetObjDescClassName 3.1.1.2.4 OdlGetObjDescChildCount 3.1.1.2.5 OdlGetObjDescLevel 3.1.1.2.6 OdlGetObjComments 3.1.1.2.7 OdlGetObjPreComment 3.1.1.2.8 OdlGetObjLineComment 3.1.1.2.9 OdlGetObjPostComment 3.1.1.2.10 OdlGetObjEndComment 3.1.1.2.11 OdlGetObjFilename 3.1.1.2.12 OdlFindObjDescParent 3.1.1.3 Keyword Function Prototypes 3.1.1.3.1 OdlFindKwd 3.1.1.3.2 OdlNextKwd 3.1.1.3.3 OdlGetFirstKwd 3.1.1.4.4 OdlGetNextKwd 3.1.1.4.x OdlGetKwdxxx Functions 3.1.1.4.2 OdlGetKwdValue 3.1.1.4.3 OdlGetKwdValueType 3.1.1.4.4 OdlGetKwdUnit 3.1.1.4.5 OdlGetKwdName 3.1.1.4.6 OdlGetKwdPreComment 3.1.1.4.7 OdlGetKwdLineComment 3.1.1.4.8 OdlGetKwdFilename 3.1.1.5 OdlFreeTree 3.1.2 Label Modify/Write Prototypes 3.1.2.1 OdlCutObjDesc 3.1.2.2 OdlPasteObjDesc 3.1.2.3 OdlPasteObjDescBefore 3.1.2.4 OdlPasteObjDescAfter 3.1.2.5 OdlCopyObjDesc 3.1.2.6 OdlNewObjDesc 3.1.2.7 OdlAdjustObjDescLevel 3.1.2.8 OdlCutKwd 3.1.2.9 OdlPasteKwd 3.1.2.10 OdlPasteKwdBefore 3.1.2.11 OdlPasteKwdAfter 3.1.2.12 OdlCopyKwd 3.1.2.13 OdlNewKwd 3.1.2.14 OdlFreeAllKwds 3.1.2.15 OdlFreeKwd 3.1.2.16 OdlGetFileName 3.1.2.17 OdlPrintHierarchy 3.1.2.18 OdlPrintLabel 3.1.2.19 OdlChangeExpansionFile 3.1.2.20 OdlSetObjComments 3.1.2.21 OdlSetObjPreComment 3.1.2.22 OdlSetObjLineComment 3.1.2.23 OdlSetObjPostComment 3.1.2.24 OdlSetObjEndComment 3.1.2.25 OdlSetKwdPreComment 3.1.2.26 OdlSetKwdLineComment 3.1.2.27 OdlSetObjFilename 3.1.2.28 OdlSetKwdFilename 2.0 Scope This user's guide describes a set of C library routines that allow the access and manipulation of PDS object descriptions in ODL labels. The L3 library described in this document is part of the Object Access Library (OAL). OAL provides many additional label access and manipulation routines, an IDL and Fortran interface to L3, as well as a full suite of data access routines. For a detailed discussion of the Object Access Library, please see [4]. As a guideline, the functionality of the library routines is limited to that which can be generalized across all approved PDS objects. By generalizing, we are defining a library interface that will not change as PDS objects are modified or added. As an example of the scope of the library functionality, a user can use the library to parse the ODL label for the Galileo IMAGE object included in appendix A, find the IMAGE object description in the resultant tree structure, and retrieve the value of SAMPLE_TYPE in character string format. 3.0 Label Library Design The label library design is presented in four sections. The first section contains the actual design in the form of function prototypes. The remaining sections include function parameter descriptions, error and return status codes, and design notes. 3.1 Function Prototypes 3.1.1 Label Access Function Prototypes 3.1.1.1.1 OdlParseLabelFile Function Prototype OBJDESC *OdlParseLabelFile (filespec, errfilespec, expand, nomsgs) char *filespec, *errfilespec; MASK expand; unsigned short nomsgs; Description This routine returns a pointer to an ODL tree that represents a parsed ODL label, given the name of a file that contains an ODL label in ASCII format. This routine will optionally expand ^STRUCTURE pointers. (See section 3.4 for parameter values and descriptions.) WARNING: This function allocates memory. It can be deallocated using OdlFreeTree. This routine may not work on labels in variable-length record files, depending on the platform being run on; the OAL routine OaParseLabelFile, which takes the same parameters, works on all files. 3.1.1.1.2 OdlExpandLabelFile Function Prototype OBJDESC *OdlExpandLabelFile (objdescptr, errfilespec, expand, nomsgs) OBJDESC *objdescptr; char *errfilespec; MASK expand; unsigned short nomsgs; Description This routine returns a pointer to a new ODL tree whose nested ^*STRUCTURE and/or ^*CATALOG keywords have been expanded. The keywords and objects parsed from the file referenced in the keyword are included as a sub-tree in the existing tree, just after the keyword, which is left as is. (See section 3.2 for parameter values and descriptions.) WARNING: This function allocates memory. It can be deallocated using OdlFreeTree. 3.1.1.1.3 OdlParseLabelString Function Prototype OBJDESC *OdlParseLabelString (odlstring, errfilespec, expand, nomsgs) char *odlstring, *errfilespec; MASK expand; unsigned short nomsgs; Description This routine returns a pointer to an ODL tree that represents a parsed ODL label, given a pointer to a character string containing an ODL label in ASCII format. This routine will optionally expand ^STRUCTURE pointers. (See section 3.2 for parameter values and descriptions.) WARNING: This function allocates memory. It can be deallocated using OdlFreeTree. 3.1.1.2.1 OdlFindObjDesc Function Prototype OBJDESC *OdlFindObjDesc (objdescptr, classname, kwdname, kwdvalue, position, scope) OBJDESC *objdescptr; char *classname, *kwdname, *kwdvalue; unsigned long position unsigned short scope; Description This routine returns a pointer to the first occurrence of an object description that meets the constraints supplied in classname, kwdname, kwdvalue, position, and scope. A pointer to an ODL object description must be supplied. Class name may include a wildcard '*' for generic class name searches. Keyword name and value may be used to select an object description using any attribute (e.g. NAME). Position indicates the nth occurrence of the object description that meets the constraints specified. Both position and scope are relative to the ODL object description pointer. (See section 3.2 for parameter values and descriptions. See section 3.4 note 3 for a discussion on constraints.) 3.1.1.2.x OdlGetObjDescxxx 3.1.1.2.2 OdlGetLabelVersion Function Prototypes char *OdlGetLabelVersion (objdescptr) OBJDESC *objdescptr; Description This routine returns a pointer to the PDS version number in character string format, given an ODL tree pointer. This value is determined from the PDS_VERSION_NUMBER keyword. 3.1.1.2.3 OdlGetObjDescClassName Function Prototypes char *OdlGetObjDescClassName (objdescptr) OBJDESC *objdescptr; Description This routine returns a pointer to the object description class name in character string format, given a pointer to an object description in an ODL tree. 3.1.1.2.4 OdlGetObjDescChildCount Function Prototypes int OdlGetObjDescChildCount (objdescptr) OBJDESC *objdescptr; Description This routine returns the number of child objects, given a pointer to the parent object in an ODL tree. 3.1.1.2.5 OdlGetObjDescLevel Function Prototypes int OdlGetObjDescLevel (objdescptr) OBJDESC *objdescptr; Description This routine returns level number of the object description, given a pointer to an object description in an ODL tree. The 'root' object is at level zero (0). 3.1.1.2.6 OdlGetObjComments Function Prototype void OdlGetObjComments (object, pre_comment, line_comment, post_comment, end_comment) OBJDESC *object; char **pre_comment; char **line_comment; char **post_comment; char **end_comment; Description This routine returns the comment strings from an OBJDESC structure. No memory is allocated by this routine. Each output pointer points to the actual information stored in the OBJDESC structure and must not be freed. 3.1.1.2.7 OdlGetObjPreComment Function Prototype char *OdlGetObjPreComment (object) OBJDESC *object; Description This function gets the pre-comment string stored in an OBJDESC structure. No memory is allocated by the routine. The return value is a pointer to the actual string stored in the OBJDESC structure and must not be freed. 3.1.1.2.8 OdlGetObjLineComment Function Prototype char *OdlGetObjLineComment (object) OBJDESC *object; Description This function gets the line comment string stored in an OBJDESC structure. No memory is allocated by the routine. The return value is a pointer to the actual string stored in the OBJDESC structure and must not be freed. 3.1.1.2.9 OdlGetObjPostComment Function Prototype char *OdlGetObjPostComment (object) OBJDESC *object; Description This function gets the post-comment string stored in an OBJDESC structure. No memory is allocated by the routine. The return value is a pointer to the actual string stored in the OBJDESC structure and must not be freed. 3.1.1.2.10 OdlGetObjEndComment Function Prototype char *OdlGetObjEndComment (object) OBJDESC *object; Description This function gets the end-comment string stored in an OBJDESC structure. No memory is allocated by the routine. The return value is a pointer to the actual string stored in the OBJDESC structure and must not be freed. 3.1.1.2.11 OdlGetObjFilename Function Prototype char *OdlGetObjFilename (object) OBJDESC *object; Description This function gets the file_name string stored in an OBJDESC structure. No memory is allocated by the routine. The return value is a pointer to the actual string stored in the OBJDESC structure and must not be freed. 3.1.1.2.12 OdlFindObjDescParent Function Prototype OBJDESC *OdlFindObjDescParent (objdescptr) OBJDESC *objdescptr; Description This routine returns a pointer to the parent object description, given a pointer to a child object description in an ODL tree. 3.1.1.3.1 OdlFindKwd Function Prototype KEYWORD *OdlFindKwd (objdescptr, kwdname, kwdvalue, position, scope) OBJDESC *objdescptr; char *kwdname, *kwdvalue; unsigned long position; unsigned short scope; Description This routine returns a pointer to the first occurrence of a keyword that meets the constraints supplied in kwdname, kwdvalue, position, and scope. A pointer to an ODL object description must be supplied and may be the ROOT object description. Keyword names and values may include a wildcard '*' for generic searches. Position indicates the nth occurrence of the keyword meeting the constraints specified. Both position and scope are relative to the ODL object description pointer. (See section 3.2 for parameter values and descriptions. See section 3.4 note 3 for a discussion on constraints.) 3.1.1.3.2 OdlNextKwd Function Prototype KEYWORD *OdlNextKwd (kwdptr, kwdname, kwdvalue, position, scope) KEYWORD *kwdptr; char *kwdname, *kwdvalue; unsigned long position; unsigned short scope; Description This routine returns a pointer to the first occurrence of a keyword that meets the constraints supplied in kwdname, kwdvalue, position, and scope. A pointer to an ODL keyword must be supplied. Keyword names and values may include a wildcard '*' for generic searches. Position indicates the nth occurrence of the keyword meeting the constraints specified. NOTE: Use a position value of two (2) to get the next occurrence. Both position and scope are relative to the ODL keyword pointer. (See section 3.2 for parameter values and descriptions. See section 3.4 note 3 for a discussion on constraints.) 3.1.1.3.3 OdlGetFirstKwd Function Prototype KEYWORD *OdlGetFirstKwd (objdescptr) OBJDESC *objdescptr; Description This routine returns a pointer to the first keyword of an object description. A pointer to an ODL object description must be supplied. 3.1.1.4.4 OdlGetNextKwd Function Prototype KEYWORD *OdlGetNextKwd (kwdptr) KEYWORD *kwdptr; Description This routine returns a pointer to the next keyword of an object description. A pointer to an ODL keyword must be supplied. 3.1.1.4.x OdlGetKwdxxx Functions 3.1.1.4.2 OdlGetKwdValue Function Prototypes char *OdlGetKwdValue (kwdptr) KEYWORD *kwdptr; Description This routine returns a pointer to the value in character string format, given a pointer to a keyword in an ODL tree. The value pointed to is the character string to the right of the equal sign whether the string represents a scalar, set, or sequence. 3.1.1.4.3 OdlGetKwdValueType Function Prototypes unsigned short OdlGetKwdValueType (kwdptr) KEYWORD *kwdptr; Description This routine returns a value indicating the type of the keyword value, given a pointer to a keyword in an ODL tree. Value types are listed in section 3.2. 3.1.1.4.4 OdlGetKwdUnit Function Prototypes char *OdlGetKwdUnit (kwdptr) KEYWORD *kwdptr; Description This routine returns a pointer to the units explicitly supplied with the keyword value, given a pointer to a keyword in an ODL tree. (Note: units in ODL statements are optional and delimited by '<>'.) WARNING: This function allocates memory for the return value that must be freed. 3.1.1.4.5 OdlGetKwdName Function Prototypes char *OdlGetKwdName (kwdptr) KEYWORD *kwdptr; Description This routine returns a pointer to the name of the keyword in character string format, given a pointer to a keyword in an ODL tree. 3.1.1.4.6 OdlGetKwdPreComment Function Prototype char *OdlGetKwdPreComment (keyword) KEYWORD *keyword; Description This function gets the pre-comment string stored in an KEYWORD structure. No memory is allocated by the routine. The return value is a pointer to the actual string stored in the KEYWORD structure and must not be freed. 3.1.1.4.7 OdlGetKwdLineComment Function Prototype char *OdlGetKwdLineComment (keyword) KEYWORD *keyword; Description This function gets the line comment string stored in an KEYWORD structure. No memory is allocated by the routine. The return value is a pointer to the actual string stored in the KEYWORD structure and must not be freed. 3.1.1.4.8 OdlGetKwdFilename Function Prototype char *OdlGetKwdFilename (keyword) KEYWORD *keyword; Description This function gets the file_name string stored in an KEYWORD structure. No memory is allocated by the routine. The return value is a pointer to the actual string stored in the KEYWORD structure and must not be freed. 3.1.1.5 OdlFreeTree Function Prototype OBJDESC *OdlFreeTree (objdescptr) OBJDESC *objdescptr; Description This routine frees the memory allocated for storage of the ODL tree pointed to by the ODL tree pointer. 3.1.2 Label Modify/Write Function Prototypes 3.1.2.1 OdlCutObjDesc Function Prototype OBJDESC *OdlCutObjDesc (object) OBJDESC *object; Description This routine cuts an ODL object structure out of an ODL tree and returns a pointer to it. All references to it in the tree are removed, and all references to the original tree within the object are removed. 3.1.2.2 OdlPasteObjDesc Function Prototype OBJDESC *OdlPasteObjDesc (new_object, parent_object) OBJDESC *new_object; OBJDESC *parent_object; Description This routine adds an object to a tree as the last child of the parent_object. 3.1.2.3 OdlPasteObjDescBefore Function Prototype OBJDESC *OdlPasteObjDescBefore (new_object, old_object) OBJDESC *new_object; OBJDESC *old_object; Description This routine adds an object to a tree as the left sibling of the old_object. 3.1.2.4 OdlPasteObjDescAfter Function Prototype OBJDESC *OdlPasteObjDescAfter (new_object, old_object) OBJDESC *new_object; OBJDESC *old_object; Description This routine adds an object to a tree as the right sibling of the old_object. 3.1.2.5 OdlCopyObjDesc Function Prototype OBJDESC *OdlCopyObjDesc (object) OBJDESC *object; Description This routine makes a copy of an object and returns a pointer to the copy. All fields are duplicated except for references to the original tree, which are removed. 3.1.2.6 OdlNewObjDesc Function Prototype OBJDESC *OdlNewObjDesc (object_class, pre_comment, line_comment, post_comment, end_comment, file_name, is_a_group, line_number) char *object_class; char *pre_comment; char *line_comment; char *post_comment; char *end_comment; char *file_name; short is_a_group; long line_number; Description This routine creates a new object structure and initializes its fields with the values passed in. 3.1.2.7 OdlAdjustObjDescLevel Function Prototype void OdlAdjustObjDescLevel (object) OBJDESC *object; Description This routine changes the nesting level of an object and all of its subobjects so they fit in with their place in the overall ODL tree. This is particularly useful when objects are cut from one tree and pasted into another tree, perhaps higher or lower in the nesting hierarchy then they were in the original tree. 3.1.2.8 OdlCutKwd Function Prototype KEYWORD *OdlCutKwd (keyword) KEYWORD *keyword; Description This routine removes a keyword from an object and returns a pointer to it. All references to the object within the keyword are removed, and all references to the keyword within the object are removed. 3.1.2.9 OdlPasteKwd Function Prototype KEYWORD *OdlPasteKwd (keyword, object) KEYWORD *keyword; OBJDESC *object; Description This routine adds a keyword to the end of an object's keyword list. 3.1.2.10 OdlPasteKwdBefore Function Prototype KEYWORD *OdlPasteKwdBefore (new_keyword, old_keyword) KEYWORD *new_keyword; KEYWORD *old_keyword; Description This routine adds a keyword to an object as the left sibling of the old_keyword. 3.1.2.11 OdlPasteKwdAfter Function Prototype KEYWORD *OdlPasteKwdAfter (new_keyword, old_keyword) KEYWORD *new_keyword; KEYWORD *old_keyword; Description This routine adds a keyword to an object as the right sibling of the old_keyword. 3.1.2.12 OdlCopyKwd Function Prototype KEYWORD *OdlCopyKwd (keyword) KEYWORD *keyword; Description This routine makes a copy of a keyword and returns a pointer to it. All of the keyword's fields are duplicated except for references to the parent object, which are removed. 3.1.2.13 OdlNewKwd Function Prototype KEYWORD *OdlNewKwd (keyword_name, value_text, pre_comment, line_comment, file_name, line_number) Description This routine creates a new keyword structure, initializes its fields with the values passed in, and returns a pointer to it. 3.1.2.14 OdlFreeAllKwds Function Prototype KEYWORD *OdlFreeAllKwds (object) OBJDESC *object; Description This routine frees all memory used by an object's keywords. When it's finished, all references to keywords are gone from the object. The return value is always NULL. 3.1.2.15 OdlFreeKwd Function Prototype KEYWORD *OdlFreeKwd (keyword) KEYWORD *keyword; Description This routine frees the memory used by a keyword. The return value is always a pointer to the right sibling of the keyword. 3.1.2.16 OdlGetFileName Function Prototype char *OdlGetFileName (keyword, start_location, start_location_type) KEYWORD *keyword; unsigned long *start_location; unsigned short *start_location_type; Description This routine extracts the file name from a "^" keyword, allocates storage for it, and returns a pointer to this new character string. It also returns information about where the data actually begins in the file. For example, lets say we're looking at a label in a file called test.lbl, and we want to get the file name associated the FNAME keyword. Here are the possible values this keyword might have, and what information would be returned for each possibility: ^FNAME = 17 file name : test.lbl (attached) *start_location : 17 *start_location type : ODL_RECORD_LOCATION ^FNAME = 29 file name : test.lbl (attached) *start_location : 29 *start_location type : ODL_RECORD_LOCATION ^FNAME = 197 file name : test.lbl (attached) *start_location : 197 *start_location type : ODL_RECORD_LOCATION ^FNAME = 346 file name : test.lbl (attached) *start_location : 346 *start_location type : ODL_BYTE_LOCATION ^FNAME = 2189 file name : test.lbl (detached) *start_location : 2189 *start_location type : ODL_BYTE_LOCATION ^FNAME = "file_name.dat" file name : file_name.dat (detached) *start_location : 1 *start_location type : ODL_RECORD_LOCATION ^FNAME = ("file_name.dat", 17) file name : file_name.dat (detached) *start_location : 17 *start_location type : ODL_RECORD_LOCATION ^FNAME = ("file_name.dat", 29 ) file name : file_name.dat (detached) *start_location : 29 *start_location type : ODL_RECORD_LOCATION ^FNAME = ("file_name.dat", 197 ) file name : file_name.dat (detached) *start_location : 197 *start_location type : ODL_RECORD_LOCATION ^FNAME = ("file_name.dat", 346 ) file name : file_name.dat (detached) *start_location : 346 *start_location type : ODL_BYTE_LOCATION ^FNAME = ("file_name.dat", 2189 ) file name : file_name.dat (detached) *start_location : 2189 *start_location type : ODL_BYTE_LOCATION 3.1.2.17 OdlPrintHierarchy Function Prototype void OdlPrintHierarchy (object, message_fname, message_fptr) OBJDESC *object; char *message_fname; FILE *message_fptr; Description This routine prints the object hierarchy to a message file. 3.1.2.18 OdlPrintLabel Function Prototype void OdlPrintLabel (object, message_fname, message_fptr, root_level, options) OBJDESC *object; char *message_fname; FILE *message_fptr; unsigned long root_level; MASK options; Description This routine prints an ODL tree to a file, in ODL format. If the input message_fptr is non-NULL, it should be an open file descriptor; OdlPrintLabel appends the label to the file, and the file is left open upon return. If message_fptr is NULL, then the routine opens message_fname, prints the label to it, and closes it upon return. The input root_level should normally be set to 0. However, if object isn't the actual root of the tree, then setting root_level to object->level prints the ODL tree whose root is object, and setting root_level less than object->level prints the partial ODL trees whose roots are object, and all the partial ODL trees whose roots are nodes to the right of object. The options input includes the inverse of OdlParseLabelFile's expand inputs. ODL_UNEXPAND_STRUCTURE and/or ODL_UNEXPAND_CATALOG causes keywords and children ODL tree nodes with the same filename in their OBJDESC or KEYWORD structure as the ^STRUCTURE keyword value, to be "unexpanded". To "unexpand" means to remove these nodes from the main tree, and print them to the file path specified in the filename fields of the OBJDESC and KEYWORD structures. Per PDS standards, a ^STRUCTURE keyword value may contain only the file name in upper-case. The file name part of the filename path in each OBJDESC and KEYWORD structure must match this file name, in order to be included in the unexpanded file. This "unexpansion" process is repeated for all the ^STRUCTURE and/or ^CATALOG pointers, including nested ones. The function OdlChangeExpansionFile may be used to change the file referenced by a ^STRUCTURE keyword, and along with the filename fields in all its expanded keywords and objects. 3.1.2.19 OdlChangeExpansionFile Function Prototype int OdlChangeExpansionFile (expand_kwd, filename KEYWORD *expand_kwd; char *filename; Description This routine identifies keywords and ODL tree nodes which resulted from a ^STRUCTURE or ^CATALOG expansion, and changes the filename field of each KEYWORD or OBJDESC structure to the input filename. The input filename can be a full path; it is used as the new filename field, and the file name part of the path, converted to upper-case, is used as the new ^STRUCTURE keyword value. The routine traverses the sub-tree whose root is the input object node, and compares each keyword or ODL tree node structure's filename field (file name part only if it's a path) with the file name specified in the input expand_kwd value. If they match, then the routine changes the filename field to the new file name (path). If an OBJDESC's file_name doesn't match the expand_kwd value, then its children are NOT searched, since they could not have originated from the same ^STRUCTURE expansion. The routine changes the input expand_kwd keyword value to the filename and returns 0. If bad inputs were given, the routine returns 1. 3.1.2.20 OdlSetObjComments Function Prototype void OdlSetObjComments (object, pre_comment, line_comment, post_comment, end_comment) OBJDESC *object; char *pre_comment; char *line_comment; char *post_comment; char *end_comment; Description This routine sets the comment strings of an object structure to the corresponding input strings. Each input string is copied before setting it as a new comment value. The old comment strings are freed. If an input string is NULL, the corresponding comment string in the object structure is set to NULL. 3.1.2.21 OdlSetObjPreComment Function Prototype void OdlSetObjPreComment (object, pre_comment) OBJDESC *object; char *pre_comment; Description This function sets the pre-comment string in an OBJDESC structure. The input string is copied before setting it as the new value. The old string is freed. If the input string is NULL, the corresponding string in the object structure is set to NULL after freeing the old string. 3.1.2.22 OdlSetObjLineComment Function Prototype void OdlSetObjLineComment (object, line_comment) OBJDESC *object; char *line_comment; Description This function sets the line comment string in an OBJDESC structure. The input string is copied before setting it as the new value. The old string is freed. If the input string is NULL, the corresponding string in the object structure is set to NULL after freeing the old string. 3.1.2.23 OdlSetObjPostComment Function Prototype void OdlSetObjPostComment (object, post_comment) OBJDESC *object; char *post_comment; Description This function sets the post-comment string in an OBJDESC structure. The input string is copied before setting it as the new value. The old string is freed. If the input string is NULL, the corresponding string in the object structure is set to NULL after freeing the old string. 3.1.2.24 OdlSetObjEndComment Function Prototype void OdlSetObjEndComment (object, end_comment) OBJDESC *object; char *end_comment; Description This function sets the end-comment string in an OBJDESC structure. The input string is copied before setting it as the new value. The old string is freed. If the input string is NULL, the corresponding string in the object structure is set to NULL after freeing the old string. 3.1.2.25 OdlSetKwdPreComment Function Prototype void OdlSetKwdPreComment (keyword, pre_comment) KEYWORD *keyword; char *pre_comment; Description This function sets the pre-comment string in a KEYWORD structure. The input string is copied before setting it as the new value. The old string is freed. If the input string is NULL, the corresponding string in the keyword structure is set to NULL after freeing the old string. 3.1.2.26 OdlSetKwdLineComment Function Prototype void OdlSetKwdLineComment (keyword, line_comment) KEYWORD *keyword; char *line_comment; Description This function sets the line-comment string in a KEYWORD structure. The input string is copied before setting it as the new value. The old string is freed. If the input string is NULL, the corresponding string in the keyword structure is set to NULL after freeing the old string. 3.1.2.27 OdlSetObjFilename Function Prototype void OdlSetObjFilename (object, filename) OBJDESC *object; char *filename; Description This function sets the file_name string in an OBJDESC structure. The input string is copied before setting it as the new value. The old string is freed. If the input string is NULL, the corresponding string in the object structure is set to NULL after freeing the old string. 3.1.2.28 OdlSetKwdFilename Function Prototype void OdlSetKwdFilename (keyword, filename) KEYWORD *keyword; char *filename; Description This function sets the file_name string in a KEYWORD structure. The input string is copied before setting it as the new value. The old string is freed. If the input string is NULL, the corresponding string in the keyword structure is set to NULL after freeing the old string. 3.2 Label Access Function Parameters and Values NULL NULL as a value to a parameter implies that the parameter is to be ignored. NULL is defined to have a value of zero (0). classname classname is a character string that provides the class name to be used as a constraint in a search. The object's class name is the value in the OBJECT = ODL statement. (see note 1 and note 2) errfilespec errfilespec is a character string that identifies the file into which parser errors will be written. If the file previously exists, then the error messages are appended to the existing file. If NULL is specified, then the error messages are written to stdout. expand expand is a mask (typedef unsigned short MASK) which specifies whether or not the specified ODL files are to be expanded. ODL_EXPAND_STRUCTURE - expand ^STRUCTURE and ^*_STRUCTURE keywords only ODL_EXPAND_CATALOG - expand ^CATALOG keywords only ODL_EXPAND_STRUCTURE | ODL_EXPAND_CATALOG - expand both the ^STRUCTURE and ^CATALOG keywords (the "|" character is the logical "or" of both values). filename filename is a character string that represents the specification of the file a keyword or object was parsed from, and is stored as a field in the keyword or object structure by the parser. The field can be set by specifying filename as an input to functions which create new keywords or objects. The field is used by OdlPrintLabel when ^STRUCTURE or ^CATALOG un-expansion has been specified, as the output file path. filespec filespec is a character string that represents a file specification. File specifications are assumed to be valid for the host system. If they are not, an error status is returned. NOTE: An exception exists for file specifications supplied for ^STRUCTURE. PDS standards do not allow directory path names to be included. The rules for finding files referenced by ^STRUCTURE are documented in the PDS standards. kwdname kwdname is a character string that provides the keyword name to be used as a constraint in a search. (see note 1 and note 2) kwdptr kwdptr is a pointer to a keyword within an ODL tree. kwdvalue kwdvalue is a character string that provides the keyword value to be used as a constraint for a search (see note 1 and note 2) nomsgs nomsgs is a flag that indicates whether or not error messages are to be written. A value of TRUE or (1) indicates that error messages will not be written even if an error message file has been specified. NULL NULL as a value to a parameter implies that the parameter is to be ignored. NULL is defined to have a value of zero (0). objdescptr objdescptr is a pointer to an object description within an ODL tree. odlstring odlstring is a character string containing ODL statements. position position indicates the nth occurrence of an entity that satisfies the specified constraints. For example, a pointer to the second occurrence of a COLUMN within a TABLE would be return from OdlFindObjDesc, given a pointer to the TABLE object, "COLUMN" as class name, and two (2) as position. One (1) and zero (0) supplied as values for position are equivalent and indicate the first occurrence. NOTE: In a "find next" situation, a position value of either NULL or one (1) will return either the object description or keyword pointer passed to the routine since this would be the first entity that matches the constraints. Use a position value of two (2) to get the "next" matching entity. scope scope is an integer value that determines the context of the search. The entity being searched for dictates the interpretation of the values of scope. object description scope - The proposed values of scope for finding object descriptions restrict the tree search relative to the current OBJDESC pointer. These values are: ODL_RECURSIVE_DOWN (0) - restrict to subobjects of the current object description and all their subobjects recursively. (Expects an object description pointer.) ODL_TO_END (1) - no restrictions. The ODL tree is searched exhaustively from the given pointer to the end of the tree. ODL_CHILDREN_ONLY (2) - restrict to subobjects of the current object description only. (Expects an object description pointer.) ODL_SIBLINGS_ONLY (3) - restrict to the siblings of the current object description. (Expects an object description pointer.) keyword scope - The proposed values of scope for finding keywords restrict the tree search relative to the current OBJDESC pointer. These values are: ODL_RECURSIVE_DOWN (0) - restrict to the keywords contained in the current object description and the keywords contained in the subobjects of the current object and all of their subobjects recursively. ODL_TO_END - (1) - No restriction. The ODL tree is searched exhaustively from the given pointer to the end of the tree. ODL_CHILDREN_ONLY (2) - restrict to the keywords contained in the current object or subobjects of the current object description. ODL_SIBLINGS_ONLY (3) - restrict to the keywords contained in the current object or siblings of the current object description. ODL_THIS_OBJECT (4) - restrict to the keywords contained in the current object description only. valuetype valuetype indicates the data type of a keyword's value. ODL_UNKNOWN 0 ODL_INTEGER 1 ODL_REAL 2 ODL_SYMBOL 3 ODL_TEXT 4 ODL_DATE 5 ODL_DATE_TIME 6 ODL_SEQUENCE 7 ODL_SET 8 3.3 Return and Error Status (TBD First Quarter 95) L3 functions return NULL when the function fails. A global error status variable odl_errno is set by the function if the function detects an error. The values to return are still under development. The following error values simply suggest what could be returned. Note: Routines that accept ODL tree pointers assume that the pointer is valid for the function. (i.e. The OdlFindObjDesc routine assumes a pointer to an object description has been passed.) Function Return Status if SUCCESS else Error Status - (odlerrorstatus) 00 -> Normal 10 -> Warnings 11 -> no match 12 -> no next 13 -> no parent 20 -> Errors 21 -> illegal file name 22 -> file not found 23 -> severe syntax error 24 -> invalid objdescptr 3.4 Label Library Design - Notes 1) Class names, keyword names, and keyword values passed as parameters to label library functions will be converted to upper case before comparison. ODL keyword values embedded in double quotes are an exception. 2) Class names, keyword names, and values used as search constraints in the find routines may all contain wildcard ('*') characters. For example, the strings "*TABLE" and "IMAGE*" supplied as class names to OdlFindObjDesc would both match "IMAGE_ENGINEERING_TABLE". 3) Find routines which allow more than one constraint for matching, such as OdlFindObjDesc, will find only those objects which match all non-null constraints. For example, if OdlFindObjDesc were called with a class name of "COLUMN" and a position value of 2, it will return the second COLUMN object. All other non-COLUMN objects in the given scope would be ignored. Any search constraint with a null value will be ignored by the routine. For example, if OdlFindObjDesc were called with a value of 2 for position and NULLs for all other constraints, a pointer to the second object in the ODL tree would be returned. The search path is depth first. (i.e. for a single parent with children and grandchildren, the children of child one are search before child two or its children.) In a "find next" situation, a position value of either NULL or one (1) will return either the object description or keyword pointer passed to the routine since this would be the first entity that matches the constraints. Use a position value of two (2) to get the "next" matching entity. Appendix A1. Simple Label Parse and Display Program CCSD3ZF0000100000001NJPL3IF0PDS200000001 = SFDU_LABEL /* FILE FORMAT AND LENGTH */ ... OBJECT = IMAGE LINES = 160 LINE_SAMPLES = 252 SAMPLE_TYPE = UNSIGNED_INTEGER SAMPLE_BITS = 8 SAMPLE_BIT_MASK = 2#11111111# CHECKSUM = 2636242 END_OBJECT = IMAGE ... END {data} ------- #include "lablib3.h" OBJDESC *lp; OBJDESC *op; KEYWORD *kp; main () { /* open / parse file - error messages to file */ lp = OdlParseLabelFile ("mdim.lbl", "l3terr", NULL, NULL); if (lp == NULL) { printf ("***Parse Failed\n"); exit (0); } /* find IMAGE object */ op = OdlFindObjDesc (lp, "IMAGE", NULL, NULL, 1, ODL_RECURSIVE_DOWN); if (op == NULL) { printf ("***Find Object Failed\n"); exit (0); } printf ("OBJECT = %s\n", OdlGetObjDescClassName(op)); /* find first keyword */ kp = OdlGetFirstKwd (op); if (kp == NULL) { printf ("***Find First Keyword Failed\n"); exit (0); } /* find remaining keywords */ while (kp != NULL) { printf (" %s = %s\n", OdlGetKwdName (kp), OdlGetKwdValue (kp)); kp = OdlGetNextKwd (kp); } OdlFreeTree (lp); } Appendix A2. Examples of L3 Function Calls ---GALILEO IMAGE FILE LABEL - FILE_NAME = 2000R.LBL--- CCSD3ZF0000100000001NJPL3IF0PDS200000001 = SFDU_LABEL RECORD_TYPE = FIXED_LENGTH RECORD_BYTES = 1000 FILE_RECORDS = 814 ^TELEMETRY_TABLE = ("2000R.IMG",3) ^IMAGE = ("2000R.IMG",15) ... DATA_SET_ID = "GO-A/E-SSI-2-REDR-V1.0" SPACECRAFT_NAME = "GALILEO ORBITER" INSTRUMENT_NAME = SOLID_STATE_IMAGING /* Time tags and observation descriptors */ SPACECRAFT_CLOCK_START_COUNT = "01651920.00" IMAGE_TIME = 1992-12-09T07:13:01.011Z IMAGE_ID = E2W0914 ORBIT_NUMBER = 12869 OBSERVATION_ID = "E2WSZOOMMV01-000WDTL" TARGET_NAME = "EARTH" ... /* Table Object (for telemetry table) */ OBJECT = TELEMETRY_TABLE INTERCHANGE_FORMAT = BINARY ROWS = 1 COLUMNS = 86 ROW_BYTES = 1800 ^STRUCTURE = "RTLMTAB.FMT" END_OBJECT /* Image Object */ OBJECT = IMAGE LINES = 800 LINE_SAMPLES = 800 SAMPLE_BITS = 8 SAMPLE_TYPE = UNSIGNED_INTEGER ... END_OBJECT END ---GALILEO TABLE FORMAT FILE - ^STRUCTURE = "RTLMTAB.FMT"--- OBJECT = COLUMN NAME = RECORD_ID DATA_TYPE = UNSIGNED_INTEGER START_BYTE = 1 BYTES = 1 DESCRIPTION = "Is always 0 for the telemetry record" END_OBJECT OBJECT = COLUMN NAME = FILE_NUMBER DATA_TYPE = UNSIGNED_INTEGER START_BYTE = 2 BYTES = 1 DESCRIPTION = "Tape file number. Not applicable for CD-ROMs." END_OBJECT OBJECT = COLUMN NAME = MISSION_NAME DATA_TYPE = CHARACTER START_BYTE = 3 BYTES = 10 DESCRIPTION = "Mission name, valid is GALILEO." END_OBJECT ... ---EXAMPLES OF FUNCTION CALLS--- Assume: OBJDESC *label_ptr, *table_ptr, *column_ptr, *image_ptr; KEYWORD *name_ptr, *first_ptr; char name [31], value [11]; unsigned short valuetype; 1) Parse the file, expand the label, and create a new error message file. label_ptr = OdlParseLabelFile ("2000R.LBL", "error.lst", ODL_EXPAND_STRUCTURE, NULL); 2) Find the TELEMETRY_TABLE object description. table_ptr = OdlFindObjDesc (label_ptr, "*TABLE", NULL, NULL, 0, ODL_RECURSIVE_DOWN); 3) Find the second column (FILE_NUMBER) in the table. column_ptr = OdlFindObjDesc (table_ptr, "COLUMN", NULL, NULL, 2, ODL_CHILDREN_ONLY); 4) Find the NAME keyword of the column. name_ptr = OdlFindKwd (column_ptr, "NAME", NULL, NULL, ODL_THIS_OBJECT); 5) Get the name (i.e. FILE_NUMBER) of the column. strcpy (name, OdlGetKwdValue (name_ptr)); 6) Find the next column (i.e. MISSION_NAME) in the table. column_ptr = OdlFindObjDesc (column_ptr, "COLUMN", NULL, NULL, 2, ODL_SIBLINGS_ONLY); if (column_ptr != NULL) 7) Find the IMAGE object description. image_ptr = OdlFindObjDesc (label_ptr, "IMAGE", NULL, NULL, NULL, ODL_RECURSIVE_DOWN); 8) Find the first attribute of IMAGE. (i.e. LINES) first_ptr = OdlFindKwd (image_ptr, NULL, NULL, 1, ODL_THIS_OBJECT); if (first_ptr != NULL) 9) Get the name, value type, and value of the first keyword of IMAGE. (i.e. LINES, 1 (ODL_INTEGER), 800) strcpy (name, OdlGetKwdName (first_ptr)); valuetype = OdlGetKwdValueType (first_ptr); strcpy (value, OdlGetKwdValue (first_ptr)); 10) Find the first format file anywhere in the label. first_ptr = OdlFindKwd (label_ptr, NULL, "*.FMT", NULL, ODL_RECURSIVE_DOWN); Appendix B. This appendix lists differences and their rationales that exist between the design document and the actual implementation. 1) A nomsgs flag has been added to the parse file functions (OdlParseLabelFile, OdlParseLabelString, and OdlExpandLabelFile) to indicate whether or not error messages are to be suppressed. This approach is less confusing than the approach suggested in the design. 2) The term "keyword" when used in a function name has been shortened to "kwd". This saves space and is consistent with the use of "obj" for "object". 3) The ODLTREE type definition has been changed to either OBJDESC or KEYWORD. An ODL tree resulting from parsing an ODL file consists of two type of nodes (structures) either an OBJDESC node or a KEYWORD node. 4) The function OdlFindKwd is defined differently due to item 3 above. It now requires a pointer to an OBJDESC. In order to find the next KEYWORD, the function OdlNextKwd has been implemented. Appendix C. This appendix contains the OBJDESC and KEYWORD structure and Symbol definitions used by the parser to build the ODL tree. /*********************************************************/ /* Symbol definitions */ /*********************************************************/ #define ODL_NOEXPAND 0 #define ODL_EXPAND_STRUCTURE 1 #define ODL_EXPAND_CATALOG 2 #define ODL_UNEXPAND_STRUCTURE 1 #define ODL_UNEXPAND_CATALOG 2 #define ODL_RECURSIVE_DOWN 0 #define ODL_TO_END 1 #define ODL_CHILDREN_ONLY 2 #define ODL_SIBLINGS_ONLY 3 #define ODL_THIS_OBJECT 4 #define ODL_RECORD_LOCATION 0 #define ODL_BYTE_LOCATION 1 #define ODL_UNKNOWN 0 #define ODL_INTEGER 1 #define ODL_REAL 2 #define ODL_SYMBOL 3 #define ODL_TEXT 4 #define ODL_DATE 5 #define ODL_DATE_TIME 6 #define ODL_SEQUENCE 7 #define ODL_SET 8 /***************************************************************/ /* Typedefs */ /***************************************************************/ typedef struct Object_Structure { char *class; char *pre_comment; /* Comments before the OBJECT = line */ char *line_comment; /* Comments on the OBJECT = line */ char *post_comment; /* Comments before the END_OBJECT = line */ char *end_comment; /* Comments on the END_OBJECT = line */ char *file_name; /* the file this node was parsed from, or the */ /* file it is written to by OdlPrintLabel when */ /* ODL_EXPAND_* is specified */ char *appl1; /* used internally by OAL */ char *appl2; /* free for your application to use as you see fit */ unsigned short is_a_group; /* not currently set by parser */ unsigned long level; /* the number of levels below the root, used */ /* by OdlPrintLabel for indentation, etc. */ unsigned long line_number; /* line in the source file when parsed; */ /* for accounting purposes only */ unsigned long child_count; struct Object_Structure *parent; struct Object_Structure *left_sibling; struct Object_Structure *right_sibling; struct Object_Structure *first_child; struct Object_Structure *last_child; struct Keyword_Structure *first_keyword; struct Keyword_Structure *last_keyword; } OBJDESC; typedef struct Keyword_Structure { char *name; char *file_name; char *value; unsigned long size; char *pre_comment; /* Comments before the KEYWORD = line */ char *line_comment; /* Comments on the KEYWORD = line */ char *appl1; /* free for your application to use as you see fit */ char *appl2; /* free for your application to use as you see fit */ unsigned short is_a_pointer; unsigned short is_a_list; unsigned long line_number; /* line in the source file when parsed; */ /* for accounting purposes only */ struct Object_Structure *parent; struct Keyword_Structure *left_sibling; struct Keyword_Structure *right_sibling; } KEYWORD; ============================================================== References [1] DeMore, M.D., "Object Access: A Discussion of Software Architecture", JPL Internal Document. [2] Hughes, J.S., etal, "Planetary Data System Label Library Light (L3) - Requirements Document", JPL Internal Document, April 1993. [3] Hughes, J.S., etal, "Planetary Data System Label Library Light (L3) - Design Document", JPL Internal Document, October 1993. [4] Davis, R., Monk, S., "Object Access Library - User's Guide, Version 1.2, Laboratory for Atmospheric and Space Physics, December 1997. [5] _______, PDS Standards Reference, "JPL Internal Document", JPL D-7669; Part 2, Jet Propulsion Laboratory, November 1992. [6] Cribbs, M.A., Wagner, D.A., Planetary Science Data Dictionary, "JPL Internal Document", JPL D-7116; Rev C, Jet Propulsion Laboratory, November, 1992. NOTE: The PDS Standards Reference and Planetary Science Data Dictionary are available on the World Wide Web under the PDS Home Page, http://pds.jpl.nasa.gov/