/*========================================================================*/ /* */ /* PDS Label Library Lite */ /* (lablib3) */ /* */ /* Version: */ /* */ /* 1.0Beta Mar 31, 1994 */ /* 1.0 Jan 23, 1995 */ /* 1.1 Feb 23, 1995 */ /* 1.2 Jun 06, 1995 Preliminary */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* 01-09-95 jsh - Changed OBJECT to OBJDESC */ /* 01-09-95 jsh - Corrected strcmp and strncmp == NULL */ /* 02-16-95 jsh - Applied LASP changes (from OA dvlp - s. monk) */ /* - Function Prototypes */ /* - Filename Units */ /* - Filename for SUN/Unix */ /* - TB_MAX_BUFFER */ /* - Several 0 -> NULL in function calls */ /* 02-20-95 jsh - Added OdlPrintLine (reduced # fprintf) */ /* 06-06-95 jsh/gmw - Allow SFDU without "= SFDU" */ /* 06-06-95 jsh/gmw - Stop gap for "/*" in text strings */ /* */ /* */ /*========================================================================*/ #include "header.h" #include "io_lablib3.h" #ifdef _WINDOWS #include "system.h" #else #include #endif long odl_message_count = {0}; short odl_suppress_messages = {TRUE}; char * find_file(char *fname); /*========================================================================*/ /* */ /* Label Parse routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlParseLabelFile */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine causes a file containing a PDS label to be parsed */ /* and its "^" keywords expanded. It returns a pointer to the */ /* root of the OBJECT tree data structure. */ /* */ /* The "filespec" parameter is the full path and name of the */ /* label file to be parsed. */ /* */ /* The "message_fname" parameter is the name of the file where */ /* parser error messages will be written. If the file exists, */ /* the messages are appended, otherwise a new file is created. */ /* A NULL value passed in causes messages to be sent to stdout. */ /* */ /* The "suppress_messages" parameter is a flag that tells the code */ /* whether or not to print parser error messages. A value of TRUE */ /* (1) tells the code to supress all messages. If this parameter */ /* is 1, it doesn't matter what you specified with the */ /* "message_fname". Nothing will be written to that file. If a */ /* zero (0) is passed in, then messages will be written to the */ /* file you specified with the "message_fname" parameter. */ /* */ /* The expand parameter is a flag that controls whether or not */ /* ^STRUCTURE and ^CATALOG keywords are expanded. To expand one */ /* of these keywords means to take the file name it points to, */ /* parse its contents, and insert the results into the tree right */ /* where the keyword is sitting. In other words, these keywords */ /* function just like include files in "C". These are the values */ /* that can be passed in: */ /* */ /* ODL_EXPAND_STRUCTURE - expand ^STRUCTURE keywords only */ /* ODL_EXPAND_CATALOG - expand ^CATALOG keywords only */ /* ODL_EXPAND_STRUCTURE | ODL_EXPAND_CATALOG - expand */ /* both keywords (the "|" character is the logical */ /* "or" of both values). */ /* */ /*----------------------------------------------------------------------*/ /* */ /* WARNING: The value returned by this routine points to memory */ /* allocated by this routine (sometimes quite a bit of */ /* memory!). Be sure to deallocate it using the */ /* OdlFreeTree routine. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlParseLabelFile (filespec, message_fname, expand, suppress_messages) char *filespec; char *message_fname; MASK expand; unsigned short suppress_messages; #else OBJDESC *OdlParseLabelFile (char *filespec, char *message_fname, MASK expand, unsigned short suppress_messages) #endif { OBJDESC *root = {NULL}; odl_suppress_messages = suppress_messages; root = (OBJDESC *) OdlParseFile(filespec,NULL,message_fname,NULL,suppress_messages,1,1,0); root = (OBJDESC *) OdlExpandLabelFile(root, filespec, message_fname, expand, suppress_messages); return(root); } /* End: "OdlParseLabelFile" */ OBJDESC *OdlParseLabelFptr (fp, message_fname, expand, suppress_messages) FILE *fp; char *message_fname; MASK expand; unsigned short suppress_messages; { OBJDESC *root = {NULL}; odl_suppress_messages = suppress_messages; root = (OBJDESC *) OdlParseFile(0,fp,message_fname,NULL,suppress_messages,1,1,0); root = (OBJDESC *) OdlExpandLabelFile(root, NULL, message_fname, expand, suppress_messages); return(root); } /* End: "OdlParseLabelFptr" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlParseLabelString */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine causes a character string containing an ODL */ /* statement to be parsed and its "^" keywords expanded. It */ /* returns a pointer to the root of the OBJECT tree data structure.*/ /* */ /* WARNING: The value returned by this routine points to memory */ /* allocated by this routine. Be sure to deallocate it */ /* using the OdlFreeTree routine. */ /* */ /* WARNING: This routine will try to create a temporary file in */ /* the following locations, depending on the system: */ /* */ /* UNIX: ~/.tmp */ /* VMS: sys$login:.tmp */ /* MSDOS: C:\.tmp */ /* All others: .tmp */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlParseLabelString (odl_string, message_fname, expand, suppress_messages) char *odl_string; char *message_fname; MASK expand; unsigned short suppress_messages; #else OBJDESC *OdlParseLabelString (char *odl_string, char *message_fname, MASK expand, unsigned short suppress_messages) #endif { OBJDESC *root = {NULL}; FILE *tmp_fptr = {NULL}; char *tmp_fname = {NULL}; odl_suppress_messages = suppress_messages; tmp_fname = (char *) OdlTempFname(); if (tmp_fname == NULL) OdlPrintMessage(message_fname,NULL,0,"Unable to create a temporary file"); if ((tmp_fptr = (FILE *) fopen(tmp_fname, "w")) != NULL) { fprintf(tmp_fptr, "%s", odl_string); fclose(tmp_fptr); root = (OBJDESC *) OdlParseLabelFile(tmp_fname, message_fname, expand, suppress_messages); #ifdef VMS AppendString(tmp_fname, ";*") #endif remove(tmp_fname); } LemmeGo(tmp_fname) return(root); } /* End: "OdlParseLabelString" */ /*========================================================================*/ /* */ /* Label Expand routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlExpandLabelFile */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates "^STRUCTURE" and "^CATALOG" keywords and */ /* expands them. To "expand" means to extract the file name */ /* pointed to by the keyword, parse its contents, and insert the */ /* resulting tree into the label right where the keyword is */ /* sitting. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlExpandLabelFile (object, orig_fspec, message_fname, expand, suppress_messages) OBJDESC *object; char *orig_fspec, *message_fname; MASK expand; unsigned short suppress_messages; #else OBJDESC *OdlExpandLabelFile (OBJDESC *object, char *orig_fspec, char *message_fname, MASK expand, unsigned short suppress_messages) #endif { KEYWORD *kwd = {NULL}; KEYWORD *new_kwd = {NULL}; KEYWORD *save_kwd = {NULL}; OBJDESC *temp_root = {NULL}; OBJDESC *new_obj = {NULL}; OBJDESC *save_obj = {NULL}; FILE *l_ptr = {NULL}; unsigned long start_loc = {1}; unsigned short loc_type = {ODL_RECORD_LOCATION}; unsigned short done = {FALSE}; char *fspec = {NULL}; char *fname = {NULL}; char *keyword_name = {NULL}; char error_message[5*(TB_MAXLINE + TB_MAXPATH + TB_MAXFNAME)]; odl_suppress_messages = suppress_messages; /* Let's expand all ^STRUCTURE keywords, shall we? */ if ((expand&ODL_EXPAND_STRUCTURE) == ODL_EXPAND_STRUCTURE) { expand -= ODL_EXPAND_STRUCTURE; CopyString(keyword_name, "^*STRUCTURE") } else /* On second thought, let's expand all ^CATALOG keywords */ if ((expand&ODL_EXPAND_CATALOG) == ODL_EXPAND_CATALOG) { expand -= ODL_EXPAND_CATALOG; CopyString(keyword_name, "^*CATALOG") } else /* Hmmm. I guess we have nothing left to expand. */ { expand = ODL_NOEXPAND; done = TRUE; } /* Keep expanding until we can expand no more forever */ while (! done) { /* Find the expand keyword wherever it my be hiding */ kwd = (KEYWORD *) OdlFindKwd(object, keyword_name, NULL, 1, ODL_RECURSIVE_DOWN); /* We're done if there aren't any more keywords to expand */ if (kwd == NULL) done = TRUE; else { /* Get the file name, minus quotes and blanks, sans path */ fname = (char *) OdlGetFileName(kwd, &start_loc, &loc_type); /* We're in trouble if we've encountered this file before */ if (ExpandIsRecursive(kwd, fname)) { sprintf(error_message, "Recursive %s statement found in file: %s", keyword_name, fname); OdlPrintMessage(message_fname,NULL,kwd->line_number,error_message); } else { /* Figure out exactly where the file is located */ fspec = (char *) OdlGetFileSpec(fname, orig_fspec); /* We're in trouble if we can't find the file */ if (fspec == NULL) { sprintf(error_message, "Unable to locate %s file: %s", keyword_name, fname); OdlPrintMessage(message_fname,NULL,kwd->line_number,error_message); } else { l_ptr = (FILE *) OdlLocateStart(fspec, start_loc, loc_type); /* Parse the file */ temp_root = (OBJDESC *) OdlParseFile(fspec,l_ptr, message_fname,NULL,suppress_messages,1,1,1); /* Was there anything in the file to parse? */ if (temp_root != NULL) { /* Append any keywords */ for (new_kwd=temp_root->first_keyword; new_kwd != NULL; new_kwd = save_kwd) { save_kwd = new_kwd->right_sibling; OdlPasteKwd((KEYWORD *) OdlCutKwd(new_kwd), kwd->parent); } /* Append any sub-objects */ for (new_obj=temp_root->first_child; new_obj != NULL; new_obj = save_obj) { save_obj = new_obj->right_sibling; OdlPasteObjDesc((OBJDESC *) OdlCutObjDesc(new_obj), kwd->parent); } /* Deallocate the temporary root */ temp_root->first_keyword = NULL; temp_root->first_child = NULL; temp_root = (OBJDESC *) OdlFreeTree(temp_root); } /* End: "if (temp_root != NULL) ..." */ /* Free the file spec storage */ LemmeGo(fspec) CloseMe(l_ptr) } /* End: "if (fspec == NULL) ... else ..." */ } /* End: "if (ExpandIsRecursive( ... else ..." */ OdlFreeKwd((KEYWORD *)OdlCutKwd(kwd)); /* Free the file name storage */ LemmeGo(fname) } /* End: "if (kwd == NULL) ... else ..." */ } /* End: "while (! done) ..." */ /* Free the keyword name storage */ LemmeGo(keyword_name) /* Check and see if there are any other keywords to expand */ if (expand != ODL_NOEXPAND) { object = (OBJDESC *) OdlExpandLabelFile(object, orig_fspec, message_fname, expand, suppress_messages); } /* Return the root of the expanded tree */ return(object); } /* End: "OdlExpandLabelFile" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static unsigned short ExpandIsRecursive (keyword, exp_fname) KEYWORD *keyword; char *exp_fname; #else static unsigned short ExpandIsRecursive (KEYWORD *keyword, char *exp_fname) #endif { OBJDESC *obj = {NULL}; char *temp_fname = {NULL}; unsigned short found = {FALSE}; if ((keyword != NULL) && (exp_fname != NULL)) { #if (defined( VAX) || defined( ALPHA_VMS)) UpperCase(exp_fname) #endif CopyString(temp_fname, keyword->file_name) #if (defined( VAX) || defined( ALPHA_VMS)) UpperCase(temp_fname) #endif found = (strcmp(temp_fname, exp_fname) == 0); LemmeGo(temp_fname) for (obj=keyword->parent; ((! found) && (obj != NULL)); obj=obj->parent) { CopyString(temp_fname, obj->file_name) #if (defined( VAX) || defined( ALPHA_VMS)) UpperCase(temp_fname) #endif found = (strcmp(temp_fname, exp_fname) == 0); LemmeGo(temp_fname) } } return(found); } /* End: "ExpandIsRecursive" */ /*========================================================================*/ /* */ /* Object description routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlFindObjDesc */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates an object within a parsed label by its */ /* class name (like TABLE), by its position (look for the seventh */ /* table object in the label), by a particular keyword present */ /* in the object (like NAME), or by a particular value that a */ /* particular keyword has (like START_BYTE = 76). */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlFindObjDesc(start_object, object_class, keyword_name, keyword_value, object_position, search_scope) OBJDESC *start_object; char *object_class; char *keyword_name; char *keyword_value; unsigned long object_position; unsigned short search_scope; #else OBJDESC *OdlFindObjDesc( OBJDESC *start_object, char *object_class, char *keyword_name, char *keyword_value, unsigned long object_position, unsigned short search_scope) #endif { OBJDESC *found_object = {NULL}; OBJDESC *obj = {NULL}; KEYWORD *kwd = {NULL}; unsigned short found = {FALSE}; unsigned short scope = search_scope; unsigned long current_position = {0}; for (obj=start_object; ((obj != NULL) && (! found)); obj = (OBJDESC *) OdlNextObjDesc(obj, start_object->level, &scope)) { if (object_class == NULL) found = TRUE; else found = OdlWildCardCompare(object_class, obj->class); if ((found) && (keyword_name != NULL)) { kwd = (KEYWORD *) OdlFindKwd(obj, keyword_name, NULL, 1, ODL_THIS_OBJECT); found = (kwd != NULL); } if ((found) && (keyword_value != NULL)) found = OdlWildCardCompare(keyword_value, (char *) OdlGetKwdValue(kwd)); if ((found) && (object_position > 0)) found = ((++current_position) == object_position); if (found) found_object = obj; } /* End: "for (obj=start_object; ..." */ return(found_object); } /* End: "OdlFindObjDesc" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlNextObjDesc */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the next object in the tree based on the */ /* search_scope passed in. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlNextObjDesc (object, root_level, search_scope) OBJDESC *object; unsigned long root_level; unsigned short *search_scope; #else OBJDESC *OdlNextObjDesc (OBJDESC *object, unsigned long root_level, unsigned short *search_scope) #endif { OBJDESC *next_object = {NULL}; if (object != NULL) { switch (*search_scope) { /* look only in the current object */ case ODL_THIS_OBJECT : next_object = NULL; break; /* look at the current object's first child now, and its */ /* child's right siblings in subsequent searches */ case ODL_CHILDREN_ONLY : next_object = object->first_child; *search_scope = ODL_SIBLINGS_ONLY; break; /* look at the current object's right sibling */ case ODL_SIBLINGS_ONLY : next_object = object->right_sibling; break; /* treat the current object as the root of a sub-tree */ case ODL_RECURSIVE_DOWN : next_object = (OBJDESC *) OdlTraverseTree(object, root_level); break; /* search children, then siblings, then move up to parent */ /* keep going until the end of the label is reached */ default : next_object = (OBJDESC *) OdlTraverseTree(object, (unsigned long) 0); break; } /* End: "switch (*search_scope) ..." */ } /* End: "if (object != NULL) ..." */ return(next_object); } /* End: "OdlNextObjDesc" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlCutObjDesc */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* 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. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlCutObjDesc (object) OBJDESC *object; #else OBJDESC *OdlCutObjDesc (OBJDESC *object) #endif { if (object != NULL) { if (object->right_sibling == NULL) object->parent->last_child = object->left_sibling; else object->right_sibling->left_sibling = object->left_sibling; if (object->left_sibling == NULL) object->parent->first_child = object->right_sibling; else object->left_sibling->right_sibling = object->right_sibling; object->parent = NULL; object->left_sibling = NULL; object->right_sibling = NULL; } /* End: "if (object != NULL) ..." */ return(object); } /* End routine: "OdlCutObjDesc" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPasteObjDesc */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine adds an object to a tree as the last child of the */ /* parent_object. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlPasteObjDesc (new_object, parent_object) OBJDESC *new_object; OBJDESC *parent_object; #else OBJDESC *OdlPasteObjDesc (OBJDESC *new_object, OBJDESC *parent_object) #endif { if ((new_object != NULL) && (parent_object != NULL)) { new_object->left_sibling = parent_object->last_child; new_object->right_sibling = NULL; new_object->parent = parent_object; if (parent_object->first_child == NULL) parent_object->first_child = new_object; if (parent_object->last_child != NULL) parent_object->last_child->right_sibling = new_object; parent_object->last_child = new_object; OdlAdjustObjDescLevel(new_object); } /* End: "if ((new_object != NULL) && ..." */ return(new_object); } /* End routine: "OdlPasteObjDesc" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPasteObjDescBefore */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine adds an object to a tree as the left sibling of */ /* the old_object. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlPasteObjDescBefore (new_object, old_object) OBJDESC *new_object; OBJDESC *old_object; #else OBJDESC *OdlPasteObjDescBefore (OBJDESC *new_object, OBJDESC *old_object) #endif { if ((new_object != NULL) && (old_object != NULL)) { new_object->left_sibling = old_object->left_sibling; new_object->right_sibling = old_object; new_object->parent = old_object->parent; if (old_object->left_sibling == NULL) old_object->parent->first_child = new_object; else old_object->left_sibling->right_sibling = new_object; old_object->left_sibling = new_object; OdlAdjustObjDescLevel(new_object); } /* End: "if ((new_object != NULL) && ..." */ return(new_object); } /* End routine: "OdlPasteObjDescBefore" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPasteObjDescAfter */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine adds an object to a tree as the right sibling of */ /* the old_object. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlPasteObjDescAfter (new_object, old_object) OBJDESC *new_object; OBJDESC *old_object; #else OBJDESC *OdlPasteObjDescAfter (OBJDESC *new_object, OBJDESC *old_object) #endif { if ((new_object != NULL) && (old_object != NULL)) { new_object->right_sibling = old_object->right_sibling; new_object->left_sibling = old_object; new_object->parent = old_object->parent; if (old_object->right_sibling == NULL) old_object->parent->last_child = new_object; else old_object->right_sibling->left_sibling = new_object; old_object->right_sibling = new_object; OdlAdjustObjDescLevel(new_object); } /* End: "if ((new_object != NULL) && ..." */ return(new_object); } /* End routine: "OdlPasteObjDescAfter" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlCopyObjDesc */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* 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. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlCopyObjDesc (object) OBJDESC *object; #else OBJDESC *OdlCopyObjDesc (OBJDESC *object) #endif { OBJDESC *new_object = {NULL}; if (object != NULL) { new_object = OdlNewObjDesc(object->class, object->pre_comment, object->line_comment, object->post_comment, object->end_comment, object->file_name, object->is_a_group, object->line_number); } return(new_object); } /* End routine: "OdlCopyObjDesc" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlNewObjDesc */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine creates a new object structure and initializes */ /* its fields with the values passed in. */ /* */ /************************************************************************/ #ifdef _NO_PROTO 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; #else OBJDESC *OdlNewObjDesc (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) #endif { OBJDESC *new_object = {NULL}; if ((new_object = (OBJDESC *)malloc(sizeof(OBJDESC))) == NULL) SayGoodbye() else { CopyString(new_object->class, object_class) CopyString(new_object->pre_comment, pre_comment) CopyString(new_object->line_comment, line_comment) CopyString(new_object->post_comment, post_comment) CopyString(new_object->end_comment, end_comment) CopyString(new_object->file_name, file_name) new_object->is_a_group = is_a_group; new_object->child_count = 0; new_object->line_number = line_number; new_object->level = 0; new_object->parent = NULL; new_object->left_sibling = NULL; new_object->right_sibling = NULL; new_object->first_child = NULL; new_object->last_child = NULL; new_object->first_keyword = NULL; new_object->last_keyword = NULL; new_object->appl1 = NULL; new_object->appl2 = NULL; } /* End: "if ((new_object = ... else ..." */ return(new_object); } /* End routine: "OdlNewObjDesc" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetLabelVersion */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a pointer to a character string containing */ /* the ODL version of the label. It looks for this information in */ /* the ODL_VERSION_NUMBER keyword. */ /* */ /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */ /* VALUE IS A POINTER TO THE ACTUAL VALUE OF THE */ /* ODL_VERSION_NUMBER KEYWORD AND MUST NOT BE FREED. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlGetLabelVersion (object) OBJDESC *object; #else char *OdlGetLabelVersion (OBJDESC *object) #endif { KEYWORD *kwd = {NULL}; char *version = {NULL}; if (object != NULL) { kwd = (KEYWORD *) OdlFindKwd(object, "PDS_VERSION_ID", NULL, 1, ODL_THIS_OBJECT); if (kwd == NULL) { kwd = (KEYWORD *) OdlFindKwd(object, "ODL_VERSION_NUMBER", NULL, 1, ODL_THIS_OBJECT); } if (kwd != NULL) version = (char *) OdlGetKwdValue(kwd); } return(version); } /* End: "OdlGetLabelVersion" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetObjDescClassName */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns the class name of an object. */ /* */ /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */ /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */ /* IN THE ODL OBJECT STRUCTURE AND MUST NOT BE FREED. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlGetObjDescClassName (object) OBJDESC *object; #else char *OdlGetObjDescClassName (OBJDESC *object) #endif { char *class_name = {NULL}; if (object != NULL) class_name = object->class; return(class_name); } /* End: "OdlGetObjDescClassName" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetObjDescChildCount */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a count of the immediate children of an */ /* object. It does not count children of children, etc. */ /* */ /************************************************************************/ #ifdef _NO_PROTO int OdlGetObjDescChildCount (object) OBJDESC *object; #else int OdlGetObjDescChildCount (OBJDESC *object) #endif { OBJDESC *obj = {NULL}; int child_count = {0}; if (object != NULL) { for (obj=object->first_child; obj != NULL; obj=obj->right_sibling) ++child_count; } return(child_count); } /* End: "OdlGetObjDescChildCount" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetObjDescLevel */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns the nesting level of an object. The ROOT */ /* object in a tree is always defined to be level 0. */ /* */ /************************************************************************/ #ifdef _NO_PROTO int OdlGetObjDescLevel (object) OBJDESC *object; #else int OdlGetObjDescLevel (OBJDESC *object) #endif { OBJDESC *obj = {NULL}; int level = {0}; if (object != NULL) { for (obj=object->parent; obj != NULL; obj=obj->parent) ++level; } return(level); } /* End: "OdlGetObjDescLevel" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlAdjustObjDescLevel */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* 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. */ /* */ /************************************************************************/ #ifdef _NO_PROTO void OdlAdjustObjDescLevel (object) OBJDESC *object; #else void OdlAdjustObjDescLevel (OBJDESC *object) #endif { OBJDESC *obj = {NULL}; unsigned short scope = {ODL_RECURSIVE_DOWN}; for (obj=object; obj != NULL; obj = (OBJDESC *) OdlNextObjDesc(obj, object->level, &scope)) { obj->level = (obj->parent == NULL) ? 0 : (1 + obj->parent->level); } return; } /* End routine: "OdlAdjustObjDescLevel" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetObjDescParent */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a pointer to an object's parent. */ /* */ /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */ /* VALUE IS A POINTER TO AN EXISTING ODL OBJECT AND */ /* AND MUST NOT BE FREED. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlGetObjDescParent (object) OBJDESC *object; #else OBJDESC *OdlGetObjDescParent (OBJDESC *object) #endif { OBJDESC *parent = {NULL}; if (object != NULL) parent = object->parent; return(parent); } /* End: "OdlGetObjDescParent" */ /*========================================================================*/ /* */ /* Keyword routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlFindKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the keyword in a label that satisfies the */ /* requirements passed in: The object where the search is to */ /* begin, the name of the keyword, a particular value that the */ /* keyword must have, which version of the keyword we want (if */ /* there are duplicates), and the search scope we want to use to */ /* limit the objects searched. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlFindKwd (start_object, keyword_name, keyword_value, keyword_position, search_scope) OBJDESC *start_object; char *keyword_name; char *keyword_value; unsigned long keyword_position; unsigned short search_scope; #else KEYWORD *OdlFindKwd (OBJDESC *start_object, char *keyword_name, char *keyword_value, unsigned long keyword_position, unsigned short search_scope) #endif { OBJDESC *obj = {NULL}; KEYWORD *kwd = {NULL}; KEYWORD *found_kwd = {NULL}; unsigned short found = {FALSE}; unsigned short scope = search_scope; unsigned long current_position = {0}; for (obj=start_object; ((obj != NULL) && (! found)); obj = (OBJDESC *) OdlNextObjDesc(obj, start_object->level, &scope)) { for (kwd=obj->first_keyword; ((kwd != NULL) && (! found)); kwd=kwd->right_sibling) { if (keyword_name == NULL) found = TRUE; else found = OdlWildCardCompare(keyword_name, kwd->name); if ((found) && (keyword_value != NULL)) found = OdlWildCardCompare(keyword_value, (char *) OdlGetKwdValue(kwd)); if ((found) && (keyword_position > 0)) found = ((++current_position) == keyword_position); if (found) found_kwd = kwd; } /* End: "for (kwd=obj-> ..." */ } /* End: "for (obj=start_object; ..." */ return(found_kwd); } /* End: "OdlFindKwd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlNextKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the keyword in a label that satisfies the */ /* requirements passed in: The object where the search is to */ /* begin, the name of the keyword, a particular value that the */ /* keyword must have, which version of the keyword we want (if */ /* there are duplicates), and the search scope we want to use to */ /* limit the objects searched. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlNextKwd (start_keyword, keyword_name, keyword_value, keyword_position, search_scope) KEYWORD *start_keyword; char *keyword_name; char *keyword_value; unsigned long keyword_position; unsigned short search_scope; #else KEYWORD *OdlNextKwd (KEYWORD *start_keyword, char *keyword_name, char *keyword_value, unsigned long keyword_position, unsigned short search_scope) #endif { OBJDESC *start_object = {NULL}; OBJDESC *obj = {NULL}; KEYWORD *kwd = {NULL}; KEYWORD *found_kwd = {NULL}; unsigned short found = {FALSE}; unsigned short scope = search_scope; unsigned long current_position = {0}; if (start_keyword != NULL) { start_object = start_keyword->parent; obj = start_object; kwd = start_keyword; do { for ( ; ((kwd != NULL) && (! found)); kwd=kwd->right_sibling) { if (keyword_name == NULL) found = TRUE; else found = OdlWildCardCompare(keyword_name, kwd->name); if ((found) && (keyword_value != NULL)) found = OdlWildCardCompare(keyword_value, (char *) OdlGetKwdValue(kwd)); if ((found) && (keyword_position > 0)) found = ((++current_position) == keyword_position); if (found) found_kwd = kwd; } /* End: "for (kwd=start_keyword; ..." */ if (! found) { obj = (OBJDESC *) OdlNextObjDesc(obj, start_object->level, &scope); kwd = (KEYWORD *) OdlGetFirstKwd(obj); } } while ((obj != NULL) && (! found)); } /* End: "if (start_keyword != NULL) ..." */ return(found_kwd); } /* End: "OdlNextKwd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlCutKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* 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. */ /* */ /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */ /* VALUE IS A POINTER TO AN EXISTING KEYWORD STRUCTURE */ /* AND MUST NOT BE FREED. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlCutKwd (keyword) KEYWORD *keyword; #else KEYWORD *OdlCutKwd (KEYWORD *keyword) #endif { if (keyword != NULL) { if (keyword->left_sibling != NULL) keyword->left_sibling->right_sibling = keyword->right_sibling; if (keyword->right_sibling != NULL) keyword->right_sibling->left_sibling = keyword->left_sibling; if (keyword->parent->first_keyword == keyword) keyword->parent->first_keyword = keyword->right_sibling; if (keyword->parent->last_keyword == keyword) keyword->parent->last_keyword = keyword->left_sibling; keyword->parent = NULL; keyword->left_sibling = NULL; keyword->right_sibling = NULL; } /* End: "if ((keyword != NULL) && ..." */ return(keyword); } /* End routine: "OdlCutKwd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPasteKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine adds a keyword to the end of an object's keyword */ /* list. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlPasteKwd (keyword, object) KEYWORD *keyword; OBJDESC *object; #else KEYWORD *OdlPasteKwd (KEYWORD *keyword, OBJDESC *object) #endif { if ((keyword != NULL) && (object != NULL)) { keyword->parent = object; keyword->left_sibling = object->last_keyword; keyword->right_sibling = NULL; if (object->first_keyword == NULL) object->first_keyword = keyword; if (object->last_keyword != NULL) object->last_keyword->right_sibling = keyword; object->last_keyword = keyword; } /* End: "if ((keyword != NULL) && ..." */ return(keyword); } /* End routine: "OdlPasteKwd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPasteKwdBefore */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine adds a keyword to an object as the left sibling of */ /* the old_keyword. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlPasteKwdBefore (new_keyword, old_keyword) KEYWORD *new_keyword; KEYWORD *old_keyword; #else KEYWORD *OdlPasteKwdBefore (KEYWORD *new_keyword, KEYWORD *old_keyword) #endif { if ((new_keyword != NULL) && (old_keyword != NULL)) { new_keyword->parent = old_keyword->parent; new_keyword->left_sibling = old_keyword->left_sibling; new_keyword->right_sibling = old_keyword; if (old_keyword->left_sibling == NULL) old_keyword->parent->first_keyword = new_keyword; else old_keyword->left_sibling->right_sibling = new_keyword; old_keyword->left_sibling = new_keyword; } /* End: "if ((new_keyword != NULL) && ..." */ return(new_keyword); } /* End routine: "OdlPasteKwdBefore" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPasteKwdAfter */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine adds a keyword to an object as the right sibling */ /* of the old_keyword. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlPasteKwdAfter (new_keyword, old_keyword) KEYWORD *new_keyword; KEYWORD *old_keyword; #else KEYWORD *OdlPasteKwdAfter (KEYWORD *new_keyword, KEYWORD *old_keyword) #endif { if ((new_keyword != NULL) && (old_keyword != NULL)) { new_keyword->parent = old_keyword->parent; new_keyword->right_sibling = old_keyword->right_sibling; new_keyword->left_sibling = old_keyword; if (old_keyword->right_sibling == NULL) old_keyword->parent->last_keyword = new_keyword; else old_keyword->right_sibling->left_sibling = new_keyword; old_keyword->right_sibling = new_keyword; } /* End: "if ((new_keyword != NULL) && ..." */ return(new_keyword); } /* End routine: "OdlPasteKwdAfter" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlCopyKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* 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. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlCopyKwd (keyword) KEYWORD *keyword; #else KEYWORD *OdlCopyKwd (KEYWORD *keyword) #endif { KEYWORD *new_keyword = {NULL}; if (keyword != NULL) { new_keyword = OdlNewKwd(keyword->name, keyword->value, keyword->pre_comment, keyword->line_comment, keyword->file_name, keyword->line_number); } return(new_keyword); } /* End routine: "OdlCopyKwd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlNewKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine creates a new keyword structure, initializes */ /* its fields with the values passed in, and returns a pointer */ /* to it. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlNewKwd (keyword_name, value_text, pre_comment, line_comment, file_name, line_number) char *keyword_name; char *value_text; char *pre_comment; char *line_comment; char *file_name; long line_number; #else KEYWORD *OdlNewKwd (char *keyword_name, char *value_text, char *pre_comment, char *line_comment, char *file_name, long line_number) #endif { KEYWORD *new_keyword = {NULL}; if ((new_keyword = (KEYWORD *)malloc(sizeof(KEYWORD))) == NULL) SayGoodbye() else { CopyString(new_keyword->name, keyword_name) CopyString(new_keyword->pre_comment, pre_comment) CopyString(new_keyword->line_comment, line_comment) CopyString(new_keyword->file_name, file_name) CopyString(new_keyword->value, value_text) new_keyword->is_a_pointer = (keyword_name == NULL) ? FALSE : (*keyword_name == '^'); if (value_text == NULL) { new_keyword->size = 0; new_keyword->is_a_list = FALSE; } else { new_keyword->size = strlen(new_keyword->value); new_keyword->is_a_list = ((*value_text == '{') || (*value_text == '(')); } new_keyword->line_number = line_number; new_keyword->parent = NULL; new_keyword->left_sibling = NULL; new_keyword->right_sibling = NULL; new_keyword->appl1 = NULL; new_keyword->appl2 = NULL; } /* End: "if ((new_keyword = ... else ..." */ return(new_keyword); } /* End routine: "OdlNewKwd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetFirstKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a pointer to the first keyword data */ /* structure in an object definition structure. */ /* */ /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */ /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */ /* IN THE OBJECT DATA STRUCTURE AND MUST NOT BE FREED. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlGetFirstKwd (object) OBJDESC *object; #else KEYWORD *OdlGetFirstKwd (OBJDESC *object) #endif { KEYWORD *kwd = {NULL}; if (object != NULL) kwd = object->first_keyword; return(kwd); } /* End: "OdlGetFirstKwd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetNextKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a pointer to the next keyword data */ /* structure in an object definition's list of keyword structures. */ /* */ /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */ /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */ /* IN THE OBJECT DATA STRUCTURE AND MUST NOT BE FREED. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlGetNextKwd (keyword) KEYWORD *keyword; #else KEYWORD *OdlGetNextKwd (KEYWORD *keyword) #endif { KEYWORD *kwd = {NULL}; if (keyword != NULL) kwd = keyword->right_sibling; return(kwd); } /* End: "OdlGetNextKwd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetKwdValue */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a pointer to a keyword's value. */ /* */ /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */ /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */ /* IN THE KEYWORD DATA STRUCTURE AND MUST NOT BE FREED. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlGetKwdValue (keyword) KEYWORD *keyword; #else char *OdlGetKwdValue (KEYWORD *keyword) #endif { char *value = {NULL}; if (keyword != NULL) value = keyword->value; return(value); } /* End: "OdlGetKwdValue" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetAllKwdValues */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine extracts each individual value from a set or */ /* sequence of values of a keyword, stores these values in a */ /* linked list, and returns a pointer to this list. */ /* */ /* For example, if a keyword has this combination of sets and */ /* sequences as its value: */ /* */ /* {red, (green, blue), {17, (("book.lbl", 345), orange)}} */ /* */ /* Then the TB_STRING_LIST returned would contain: */ /* */ /* red */ /* green */ /* blue */ /* 17 */ /* "book.lbl" */ /* 345 */ /* orange */ /* */ /* WARNING: The string list must be freed using the */ /* RemoveStringList macro (look in toolbox.h). */ /* */ /************************************************************************/ #ifdef _NO_PROTO TB_STRING_LIST *OdlGetAllKwdValues (keyword) KEYWORD *keyword; #else TB_STRING_LIST *OdlGetAllKwdValues(KEYWORD *keyword) #endif { TB_STRING_LIST *value_list = {NULL}; char *val_start = {NULL}; char *val_stop = {NULL}; char save_ch; if (keyword != NULL) { if (keyword->value != NULL) { for (val_start=(char *)OdlValueStart(keyword->value); *val_start != '\0'; val_start=(char *)OdlValueStart(val_stop+1)) { val_stop = (char *) OdlValueEnd(val_start); save_ch = *(val_stop + 1); *(val_stop + 1) = '\0'; AddStringToList(val_start, value_list) *(val_stop + 1) = save_ch; } } /* End: "if (keyword->value != NULL) ..." */ } /* End: "if (keyword != NULL) ..." */ return(value_list); } /* End: "OdlGetAllKwdValues" */ #ifdef _NO_PROTO int OdlGetAllKwdValuesArray (keyword, array) KEYWORD *keyword; char ***array; #else int OdlGetAllKwdValuesArray (KEYWORD *keyword, char ***array) #endif { TB_STRING_LIST *value_list = {NULL}; char *val_start = {NULL}; char *val_stop = {NULL}; char save_ch; *array = NULL; if (keyword != NULL) { if (keyword->value != NULL) { for (val_start=(char *)OdlValueStart(keyword->value); *val_start != '\0'; val_start=(char *)OdlValueStart(val_stop+1)) { val_stop = (char *) OdlValueEnd(val_start); save_ch = *(val_stop + 1); *(val_stop + 1) = '\0'; AddStringToList(val_start, value_list) *(val_stop + 1) = save_ch; } } /* End: "if (keyword->value != NULL) ..." */ } /* End: "if (keyword != NULL) ..." */ if (value_list) { return(ListToArray(value_list, array)); } else { return(0); } } /* End: "OdlGetAllKwdValues" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetKwdValueType */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine determines the data type of a keyword's value and */ /* returns a data type symbolic id. Possible symbolic ids are: */ /* */ /* ODL_UNKNOWN (can't tell what the heck it is) */ /* ODL_INTEGER (handles optional leading plus or minus) */ /* ODL_REAL (handles optional leading plus or minus, */ /* scientific notation, and real exponents) */ /* ODL_SYMBOL (unqouted or single quoted string of */ /* characters) */ /* ODL_TEXT (double quoted string of characters) */ /* ODL_DATE (yyyy-mm-dd or yyyy-ddd) */ /* ODL_DATE_TIME (yyyy-mm-ddThh:mm:ss.h) */ /* ODL_SEQUENCE (starts with a paren character "(") */ /* ODL_SET (starts with a brace character "{") */ /* */ /************************************************************************/ #ifdef _NO_PROTO unsigned short OdlGetKwdValueType (keyword) KEYWORD *keyword; #else unsigned short OdlGetKwdValueType (KEYWORD *keyword) #endif { unsigned short type = {ODL_UNKNOWN}; if (keyword != NULL) type = (unsigned short) OdlDataType(keyword->value); return(type); } /* End: "OdlGetKwdValueType" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetKwdUnit */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the units part of a keyword's value, */ /* extracts it, stores it in a new character string, and returns */ /* a pointer to this new character string. */ /* */ /* WARNING: This routine allocates memory for the return value */ /* that must be freed. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlGetKwdUnit (keyword) KEYWORD *keyword; #else char *OdlGetKwdUnit (KEYWORD *keyword) #endif { char *c = {NULL}; char *unit = {NULL}; /* If we were given a keyword to use */ if (keyword != NULL) { /* Attempt to locate the units string */ c = (char *) strchr(keyword->value, '<'); if (c != NULL) { /* We found it! Now copy it and make it upper case */ CopyString(unit, c) UpperCase(unit) /* Close off the units string */ c = (char *) strchr(unit, '>'); if (c != NULL) *(c + 1) = '\0'; } } /* End: "if (keyword != NULL) ..." */ return(unit); } /* End: "OdlGetKwdUnit" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetKwdName */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns the name of a keyword. */ /* */ /* WARNING: NO MEMORY IS ALLOCATED BY THIS ROUTINE. THE RETURN */ /* VALUE IS A POINTER TO THE ACTUAL INFORMATION STORED */ /* IN THE KEYWORD DATA STRUCTURE AND MUST NOT BE FREED. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlGetKwdName (keyword) KEYWORD *keyword; #else char *OdlGetKwdName (KEYWORD *keyword) #endif { char *name = {NULL}; if (keyword != NULL) name = keyword->name; return(name); } /* End: "OdlGetKwdName" */ /*========================================================================*/ /* */ /* Memory deallocation routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlFreeTree */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine frees all memory used by an ODL tree. The return */ /* value is always NULL. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlFreeTree (object) OBJDESC *object; #else OBJDESC *OdlFreeTree (OBJDESC *object) #endif { if (object != NULL) { OdlFreeTree(object->first_child); OdlFreeTree(object->right_sibling); OdlFreeAllKwds(object); LemmeGo(object->class) LemmeGo(object->pre_comment) LemmeGo(object->line_comment) LemmeGo(object->post_comment) LemmeGo(object->end_comment) LemmeGo(object->file_name) LemmeGo(object) } return(object); } /* End: "OdlFreeTree" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlFreeAllKwds */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* 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. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlFreeAllKwds (object) OBJDESC *object; #else KEYWORD *OdlFreeAllKwds (OBJDESC *object) #endif { KEYWORD *kwd = {NULL}; if (object != NULL) { for (kwd=object->first_keyword; kwd != NULL; kwd=(KEYWORD *) OdlFreeKwd(kwd)) ; object->first_keyword = NULL; object->last_keyword = NULL; } return(kwd); } /* End: "OdlFreeAllKwds" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlFreeKwd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine frees the memory used by a keyword. The return */ /* value is always a pointer to the right sibling of the keyword. */ /* */ /************************************************************************/ #ifdef _NO_PROTO KEYWORD *OdlFreeKwd (keyword) KEYWORD *keyword; #else KEYWORD *OdlFreeKwd (KEYWORD *keyword) #endif { KEYWORD *next_kwd = {NULL}; if (keyword != NULL) { next_kwd = keyword->right_sibling; LemmeGo(keyword->name) LemmeGo(keyword->file_name) LemmeGo(keyword->value) LemmeGo(keyword->pre_comment) LemmeGo(keyword->line_comment) LemmeGo(keyword) } return(next_kwd); } /* End: "OdlFreeKwd" */ /*========================================================================*/ /* */ /* File and File Name routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlOpenMessageFile */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a pointer to an opened file based on */ /* what is passed in. If message_fptr is not NULL, the we assume */ /* that the file is already open and return message_fptr. If */ /* message_fname is NULL, or we can't open message_fname, then */ /* we return stdout. If message_fname can be opened, then we */ /* return a pointer to the newly opened file. */ /* */ /************************************************************************/ #ifdef _NO_PROTO FILE *OdlOpenMessageFile (message_fname, message_fptr) char *message_fname; FILE *message_fptr; #else FILE *OdlOpenMessageFile (char *message_fname, FILE *message_fptr) #endif { FILE *fptr = {stdout}; char *c = message_fname; if (message_fptr != NULL) fptr = message_fptr; else if (message_fname != NULL && ! odl_suppress_messages) { if ((fptr = (FILE *) fopen(message_fname, "a")) == NULL) { fptr = stdout; OdlPrintMessage(NULL, NULL, 0, "Unable to open the output file. Messages will be written to the terminal"); } } return(fptr); } /* End routine: "OdlOpenMessageFile" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlGetFileName */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* 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 assocated */ /* 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 */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlGetFileName (keyword, start_location, start_location_type) KEYWORD *keyword; unsigned long *start_location; unsigned short *start_location_type; #else char *OdlGetFileName (KEYWORD *keyword, unsigned long *start_location, unsigned short *start_location_type) #endif { char *fname = {NULL}; char *text = {NULL}; char *unit = {NULL}; char *first_word = {NULL}; char *second_word = {NULL}; if (keyword != NULL) { /* Make a copy of the keyword's value */ CopyString(text, keyword->value) /* Get rid of parens, braces, and commas */ ReplaceChar(text, '(', ' ') ReplaceChar(text, ')', ' ') ReplaceChar(text, '{', ' ') ReplaceChar(text, '}', ' ') ReplaceChar(text, ',', ' ') /* Locate the units string */ unit = (char *) strchr(text, '<'); /* Remove the units string if it's there */ if (unit != NULL) *unit = '\0'; /* Find the first word */ first_word = (char *) OdlFirstWord(text); /* If the first word is quoted, then it's a file name */ if ((*first_word == '"') || (*first_word == '\'')) { /* Look for a second word */ second_word = (char *) OdlNextWord(first_word); /* If we can't find one, then the location is record 1 */ if (*second_word == '\0') *start_location = 1; else { /* Otherwise, the second word is the location */ *start_location = atoi(second_word); *(second_word - 1) = '\0'; } /* Copy and clean up the file name */ CopyString(fname, (first_word+1)) ReplaceChar(fname, '"', ' '); ReplaceChar(fname, '\'', ' '); StripTrailing(fname, ' ') } else { /* Since the first word isn't quoted, we assume that it's a */ /* location, and that the file name is the one associated with */ /* the keyword itself (e.g., we're looking at attached data) */ *start_location = atoi(first_word); CopyString(fname, keyword->file_name) } /* End: "if ((*first_word == '"') || ... else ..." */ /* No unit string means a record location */ if (unit == NULL) *start_location_type = ODL_RECORD_LOCATION; else { /* Otherwise, find out what kind of units string we have */ UpperCase(unit) *unit = '<'; /* Bug fix SM 10/24/94 */ if (strncmp(unit, " 1)) reached_the_end = (fseek(fptr,start_location,0) != 0); } else { fptr = (FILE *) fopen(filespec, "r"); if (fptr != NULL) { for (i=1; ((i < start_location) && (! reached_the_end)); ++i) { if (! fgets(buffer, TB_MAX_BUFFER, fptr)) reached_the_end = TRUE; } } } /* End: "if (start_location_type == ... else ..." */ if (reached_the_end) CloseMe(fptr) } /* End: "if (filespec != NULL) ..." */ return(fptr); } /* End: "OdlGetFileSpec" */ /*========================================================================*/ /* */ /* Print Routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPrintMessage */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine prints a formatted message either to stdout or to */ /* a message file, depending on what was passed in. Messages are */ /* formatted to look like this: */ /* */ /* -- */ /* */ /* If the line_number is zero, then just the message text is */ /* printed, with no formatting. */ /* */ /* If the odl_suppress_messages global flag is set to TRUE (1) */ /* then nothing is printed. */ /* */ /************************************************************************/ #ifdef _NO_PROTO short OdlPrintMessage (message_fname, message_fptr, line_number, text) char *message_fname; FILE *message_fptr; long line_number; char *text; #else short OdlPrintMessage (char *message_fname, FILE *message_fptr, long line_number, char *text) #endif { FILE *m_ptr = {NULL}; char line_prompt[20]; char *line_out = {NULL}; ++odl_message_count; if (! odl_suppress_messages) { m_ptr = (message_fptr != NULL) ? message_fptr : (FILE *) OdlOpenMessageFile(message_fname, message_fptr); if (line_number == 0) strcpy(line_prompt, ""); else sprintf(line_prompt, " Line %d -- ", line_number); if (text == NULL) { NewString(line_out, (20 + strlen(line_prompt))) sprintf(line_out, "%s Unknown error", line_prompt); } else { NewString(line_out, (20 + strlen(line_prompt) + strlen(text))) sprintf(line_out, "%s%s", line_prompt, text); } line_out = OdlFormatMessage(line_out); fprintf(m_ptr, "%s", line_out); LemmeGo(line_out) /* if we opened the message file in this routine then close it */ if ((m_ptr != stdout) && (message_fptr == NULL)) CloseMe(m_ptr) } /* End: "if (! odl_suppress_messages) ..." */ return(FALSE); } /* End routine: OdlPrintMessage */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPrintLine */ /* */ /* Author: */ /* */ /* J. S. Hughes (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 February 20, 1995 */ /* */ /* Change History: */ /* */ /* 02-20-95 jsh - a copy of OdlPrintMessage cleaned up for */ /* simple output of lines to message file */ /* NOTE: '\n' is not appended or assumed */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine prints a simple line either to stdout or to */ /* a message file, depending on what was passed in. */ /* */ /* If the odl_suppress_messages global flag is set to TRUE (1) */ /* then nothing is printed. */ /* */ /************************************************************************/ #ifdef _NO_PROTO short OdlPrintLine (message_fname, message_fptr, text) char *message_fname; FILE *message_fptr; char *text; #else short OdlPrintLine (char *message_fname, FILE *message_fptr, char *text) #endif { FILE *m_ptr = {NULL}; if (! odl_suppress_messages) { m_ptr = (message_fptr != NULL) ? message_fptr : (FILE *) OdlOpenMessageFile(message_fname, message_fptr); if (text == NULL) { fprintf(m_ptr, "%s", "Unknown error\n"); } else { fprintf(m_ptr, "%s", text); } /* if we opened the message file in this routine then close it */ if ((m_ptr != stdout) && (message_fptr == NULL)) CloseMe(m_ptr) } /* End: "if (! odl_suppress_messages) ..." */ return(FALSE); } /* End routine: OdlPrintLine */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static char *OdlFormatMessage (text) char *text; #else static char *OdlFormatMessage (char *text) #endif { char *new_text = {NULL}; char *first_char = {NULL}; char *last_char = {NULL}; char *dashes = {NULL}; char *blanks = {NULL}; char *c = {NULL}; char save_it = {'\0'}; long report_indent = {0}; long report_width = {75}; long line_size = {0}; long len = {0}; long i = {0}; /* IF a message was passed in THEN */ if (text != NULL) { NewString(new_text, 1) /* Find the double dash delimiter thingy in the message. */ /* Messages will look something like this: */ /* WARNING: Line 123 -- BANDS: Not in data dictionary. */ /* We are using the location of the " -- " characters to */ /* figure out how far the wrapped part of the line should */ /* be indented. */ if ((dashes = strstr(text, " -- ")) != NULL) report_indent = 4 + ((long) (dashes - text)); if (report_indent >= (report_width - 2)) report_indent = 0; /* Initialize the string of blanks used for indentation. */ NewString(blanks, report_indent + 1) for (i=0; i < report_indent; ++i) *(blanks+i) = ' '; *(blanks+i) = '\0'; /* Figure out the size of the wrapped parts of the line. */ line_size = report_width - report_indent; /* Now that we have all that out of the way, we can LOOP through */ /* the string until we have wrapped and written the */ /* whole thing. */ for (first_char=text; *first_char != '\0'; first_char = last_char) { /* Find the length of the remaining part of the string. */ len = strlen(first_char); /* IF we are at the beginning of the string THEN */ /* Use the total width of the report to figure out where */ /* the end of the line should be. */ /* ELSE */ /* Write the blanks to the report file and use the space */ /* left over after indentation to figure out where */ /* the end of the line should be. */ /* ENDIF */ if (first_char == text) { if (len > report_width) last_char = (char *) (first_char + report_width); else last_char = (char *) (first_char + len); } else { AppendString(new_text, blanks) if (len > line_size) last_char = (char *) (first_char + line_size); else last_char = (char *) (first_char + len); } /* End: "if (first_char == text) ... else ..." */ /* IF the current part of the message is still too large to */ /* fit without wrapping THEN */ /* Find the last blank in the line and wrap there. */ /* ENDIF */ if (*last_char != '\0') { for (c = last_char; ((c >= first_char) && (*c != ' ')); --c) ; if (c > first_char) last_char = c; } /* End: "if (*last_char != '\0') ..." */ /* Append the current part of the message onto the new string */ save_it = *last_char; *last_char = '\0'; AppendString(new_text, first_char) AppendString(new_text, "\n") *last_char = save_it; /* Bypass the last blank character. */ if (*last_char == ' ') ++last_char; } /* End: "for (first_char = text; ..." */ /* Deallocate local storage. */ LemmeGo(blanks) } /* End: "if ((text != NULL) && ..." */ LemmeGo(text) return(new_text); } /* End routine: "OdlFormatMessage" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPrintHierarchy */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine prints the object hierarchy to a message file. */ /* */ /************************************************************************/ #ifdef _NO_PROTO void OdlPrintHierarchy (object, message_fname, message_fptr) OBJDESC *object; char *message_fname; FILE *message_fptr; #else void OdlPrintHierarchy (OBJDESC *object, char *message_fname, FILE *message_fptr) #endif { OBJDESC *obj = {NULL}; KEYWORD *kwd = {NULL}; FILE *m_ptr = {NULL}; char *format = {NULL}; char *no_name = {""}; unsigned short scope = {ODL_TO_END}; char msgtext [TB_MAXLINE + 1]; m_ptr = (message_fptr != NULL) ? message_fptr : (FILE *) OdlOpenMessageFile(message_fname, message_fptr); for (obj=object; obj != NULL; obj=(OBJDESC *) OdlTraverseTree(obj, object->level)) { NewString(format, (TB_MAXLINE + 1)) kwd = (KEYWORD *)OdlFindKwd(obj, "NAME", NULL,1, ODL_THIS_OBJECT); if ((kwd == NULL) || (kwd->value == NULL)) { sprintf(format, " Line %-5d %%%dd %%%ds", obj->line_number, (obj->level + 1), (2*(obj->level) + strlen(no_name))); sprintf(msgtext, format, obj->level, no_name); OdlPrintLine(message_fname, m_ptr, msgtext); } else { sprintf(format, " Line %-5d %%%dd %%%ds", obj->line_number, (obj->level + 1), (2*(obj->level) + strlen(kwd->value))); sprintf(msgtext, format, obj->level, kwd->value); OdlPrintLine(message_fname, m_ptr, msgtext); } if (obj->class == NULL) OdlPrintLine(message_fname, m_ptr, " -- \n"); else { sprintf(msgtext, " -- %s\n", obj->class); OdlPrintLine(message_fname, m_ptr, msgtext); } LemmeGo(format) } /* End: "for (obj=object; ..." */ /* if we opened the message file in this routine then close it */ if ((m_ptr != stdout) && (message_fptr == NULL)) CloseMe(m_ptr) return; } /* End routine: "OdlPrintHierarchy" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlPrintLabel */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine prints the ODL tree to a message file, in ODL */ /* format, unless the global odl_suppress_messages flag is set. */ /* */ /************************************************************************/ #ifdef _NO_PROTO void OdlPrintLabel (object, message_fname, message_fptr, root_level) OBJDESC *object; char *message_fname; FILE *message_fptr; unsigned long root_level; #else void OdlPrintLabel (OBJDESC *object, char *message_fname, FILE *message_fptr, unsigned long root_level) #endif { FILE *m_ptr = {NULL}; char *blanks = {NULL}; int i; char msgtext [TB_MAXLINE + 1]; if (! odl_suppress_messages) { m_ptr = (message_fptr != NULL) ? message_fptr : (FILE *) OdlOpenMessageFile(message_fname, message_fptr); if (object != NULL) { NewString(blanks, (4*object->level)) for (i=1; i < object->level; ++i) strcat(blanks, " "); if (object->pre_comment != NULL) OdlPrintLine(message_fname, m_ptr, object->pre_comment); if (object->parent != NULL) { if (object->class == NULL) { sprintf(msgtext, "%sOBJECT", blanks); OdlPrintLine(message_fname, m_ptr, msgtext); } else { sprintf(msgtext, "%sOBJECT = %s", blanks, object->class); OdlPrintLine(message_fname, m_ptr, msgtext); } if (object->line_comment != NULL) { OdlPrintLine(message_fname, m_ptr, " "); OdlPrintLine(message_fname, m_ptr, object->line_comment); } OdlPrintLine(message_fname, m_ptr, "\n"); } /* End: "if (object->parent != NULL) ..." */ OdlPrintKeywords(object, NULL, m_ptr); OdlPrintLabel(object->first_child, NULL, m_ptr, root_level); if (object->post_comment != NULL) OdlPrintLine(message_fname, m_ptr, object->post_comment); if (object->parent != NULL) { if (object->class == NULL) { sprintf(msgtext, "%sEND_OBJECT", blanks); OdlPrintLine(message_fname, m_ptr, msgtext); } else { sprintf(msgtext, "%sEND_OBJECT = %s", blanks, object->class); OdlPrintLine(message_fname, m_ptr, msgtext); } if (object->end_comment != NULL) { OdlPrintLine(message_fname, m_ptr, " "); OdlPrintLine(message_fname, m_ptr, object->end_comment); } OdlPrintLine(message_fname, m_ptr, "\n"); } /* End: "if (object->parent != NULL) ..." */ if (object->level > root_level) OdlPrintLabel(object->right_sibling, 0, m_ptr, root_level); LemmeGo(blanks) if (object->parent == NULL) OdlPrintLine(message_fname, m_ptr, "END\n"); } /* End: "if (object != NULL) ..." */ /* if we opened the message file in this routine then close it */ if ((m_ptr != stdout) && (message_fptr == NULL)) CloseMe(m_ptr) } /* End: "if (! odl_suppress_messages) ..." */ return; } /* End routine: "OdlPrintLabel" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static void OdlPrintKeywords (object, message_fname, message_fptr) OBJDESC *object; char *message_fname; FILE *message_fptr; #else static void OdlPrintKeywords (OBJDESC *object, char *message_fname, FILE *message_fptr) #endif { KEYWORD *keyword = {NULL}; FILE *m_ptr = {NULL}; short sfdu_only = {FALSE}; char *blanks = {NULL}; int i; char msgtext [TB_MAXLINE + 1]; m_ptr = (message_fptr != NULL) ? message_fptr : (FILE *) OdlOpenMessageFile(message_fname, message_fptr); if (object != NULL) { NewString(blanks, (4*object->level)) if (object->level > 0) for (i=0; i < object->level; ++i) strcat(blanks, " "); for (keyword=object->first_keyword; keyword != NULL; keyword = keyword->right_sibling) { if (keyword->pre_comment != NULL) OdlPrintLine(message_fname, m_ptr, keyword->pre_comment); OdlPrintLine(message_fname, m_ptr, blanks); sfdu_only = FALSE; if (keyword->name == NULL) OdlPrintLine(message_fname, m_ptr, "unknown_keyword"); else { OdlPrintLine(message_fname, m_ptr, keyword->name); sfdu_only = ((strncmp(keyword->name, "NJPL", 4) == 0) || (strncmp(keyword->name, "CCSD", 4) == 0)); } if ((keyword->value != NULL) && (! sfdu_only)) { OdlPrintLine(message_fname, m_ptr, " = "); OdlPrintLine(message_fname, m_ptr, keyword->value); } if (keyword->line_comment != NULL) { OdlPrintLine(message_fname, m_ptr, " "); OdlPrintLine(message_fname, m_ptr, keyword->line_comment); } OdlPrintLine(message_fname, m_ptr, "\n"); } /* End: "for (keyword=object ..." */ LemmeGo(blanks) } /* End: "if (object != NULL) ..." */ /* if we opened the message file in this routine then close it */ if ((m_ptr != stdout) && (message_fptr == NULL)) CloseMe(m_ptr) return; } /* End routine: "OdlPrintKeywords" */ /*========================================================================*/ /* */ /* Parser-specific routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlParseFile */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine actually does the parsing of a label file and */ /* returns a pointer to the root object of the tree. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlParseFile(label_fname, label_fptr, message_fname, message_fptr, suppress_messages, suppress_metrics, suppress_hierarchy, ignore_missing_end) char *label_fname; FILE *label_fptr; char *message_fname; FILE *message_fptr; unsigned short suppress_messages; unsigned short suppress_metrics; unsigned short suppress_hierarchy; unsigned short ignore_missing_end; #else OBJDESC *OdlParseFile( char *label_fname, FILE *label_fptr, char *message_fname, FILE *message_fptr, unsigned short suppress_messages, unsigned short suppress_metrics, unsigned short suppress_hierarchy, unsigned short ignore_missing_end) #endif { OBJDESC *root = {NULL}; OBJDESC *curr_object = {NULL}; KEYWORD *curr_keyword = {NULL}; FILE *m_ptr = {NULL}; FILE *l_ptr = {NULL}; char *left_part = {NULL}; char *equals = {NULL}; char *right_part = {NULL}; char *comment = {NULL}; char *c = {NULL}; char *tc = {NULL}; char *tintext = {NULL}; char *text = {NULL}; char line_comment [TB_MAXLINE + 1]; char intext [TB_MAXLINE + 1]; char msgtext [TB_MAXLINE + 1]; long line_number = {0}; long value_list_line_number = {0}; long object_count = {0}; long end_object_count = {0}; long keyword_count = {0}; long comment_count = {0}; long brace_nesting = {0}; long paren_nesting = {0}; short end_found = {FALSE}; short quoted_value = {FALSE}; short value_list = {FALSE}; short equals_found = {FALSE}; short val_found = {FALSE}; short balanced = {FALSE}; short oddquotes = {FALSE}; odl_message_count = 0; odl_suppress_messages = suppress_messages; /* either use the file pointer passed in or open the message file */ m_ptr = (message_fptr != NULL) ? message_fptr : (FILE *) OdlOpenMessageFile(message_fname, message_fptr); /* opening remarks */ if (label_fname == NULL) sprintf(msgtext, "Parsing File: (no file name provided)"); else sprintf(msgtext, "Parsing File: %s", label_fname); OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n"); OdlPrintLine(message_fname, m_ptr, msgtext); OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n\n"); /* either use the file pointer passed in or open the label file */ l_ptr = (label_fptr != NULL) ? label_fptr : (label_fname == NULL) ? NULL : (FILE *) fopen(label_fname,"r"); if (l_ptr == NULL) { OdlPrintMessage(message_fname, m_ptr, 0, "Unable to open the label file. Parsing cannot continue"); } else { NewString(comment, 1) /* Initialize a ROOT object to start the tree */ curr_object = root = OdlNewObjDesc("ROOT",0,0,0,0,label_fname,0,0); /* read the label file */ while (! end_found && fgets(intext, TB_MAXLINE, l_ptr)) { if (strchr(intext, '\n') == NULL) { /** ** Line is too long. Probably not an ODL file (nsg) **/ OdlPrintMessage(NULL,stderr,(line_number+1), "Line too long...skipping rest of file\n"); break; } ++line_number; StripUnprintables(intext) /* removes linefeeds and such */ ReplaceChar(intext, '\t', ' ') /* turns TABs into blanks */ StripTrailing(intext, ' ') /* removes trailing blanks */ /* locate and skip SFDU */ if (line_number == 1L) { if (! strncmp(intext, "CCSD", 4)) continue; } /* locate, save, and remove comment text from the line */ *line_comment = '\0'; tintext = intext; oddquotes = FALSE; while ((c = strstr(tintext, "/*")) != NULL) { for (tc = tintext; tc < c; tc++) if (*tc == '"') if (oddquotes) oddquotes = FALSE; else oddquotes = TRUE; if (! oddquotes) { oddquotes = FALSE; ++comment_count; strcpy(line_comment, c); *c = '\0'; StripTrailing(tintext, ' '); break; } else tintext = c+1; } c = OdlFirstWord(intext); if (text != NULL || *c != '\0') { AppendString(text, intext) c = OdlFirstWord(text); if (strcmp(c, "END") == 0) { balanced = TRUE; end_found = TRUE; break; } else if (strcmp(c, "END_OBJECT") == 0) { balanced = TRUE; } else { if (! equals_found) equals_found = (strchr(text, '=') != NULL); if (! val_found && equals_found) { c = (char *) LastChar(text); val_found = (*c != '='); } if (val_found && equals_found) balanced = CheckBalance(text); if (! balanced) AppendString(text, "\n") } } if (balanced) { /* locate the keyword, the equals sign, and the value */ left_part = OdlFirstWord(text); if ((equals = (char *)strchr(left_part, '=')) != NULL) right_part = OdlFirstWord(equals+1); else { equals = text + strlen(text); right_part = equals; } /*------------------------------------------------------------------*/ /* Here's where the parsing begins. First, we take care of three */ /* special cases: multi-line quoted values, multi-line value */ /* lists, and blank lines. If the current line isn`t one */ /* of these than it's either an OBJECT statement, an END_OBJECT */ /* statement, the END of the label, or a new KEYWORD. */ /*------------------------------------------------------------------*/ /* we've discovered the beginning of a new object */ if ((strncmp(left_part, "OBJECT ", 7) == 0) || (strcmp(left_part, "OBJECT") == 0)) { ++object_count; ++(curr_object->child_count); /* validate the new object's class identifier */ OdlValidObjDesc(curr_object, equals, right_part, message_fname, m_ptr, line_number); /* make the new object a child of the current object */ curr_object = OdlPasteObjDesc(OdlNewObjDesc(right_part, comment,line_comment,0,0, label_fname,0,line_number), curr_object); /* reset the comment text string */ LemmeGo(comment) NewString(comment, 1) } else /*------------------------------------------------------------------*/ /* we've discovered the end of the current object */ if ((strncmp(left_part, "END_OBJECT ", 11) == 0) || (strcmp(left_part, "END_OBJECT") == 0)) { ++end_object_count; /* validate the end_object's class identifier */ OdlValidEndObjDesc(curr_object, equals, right_part, message_fname, m_ptr, line_number); /* set the current object's remaining comment fields */ CopyString(curr_object->post_comment, comment) CopyString(curr_object->end_comment, line_comment) /* make curr object's parent the new current object */ if (curr_object->parent != NULL) curr_object = curr_object->parent; /* reset the comment text string */ LemmeGo(comment) NewString(comment, 1) } else /*------------------------------------------------------------------*/ /* we've reached the end of the label */ if ((strncmp(left_part, "END ", 4) == 0) || (strcmp(left_part, "END") == 0)) { end_found = TRUE; CopyString(curr_object->post_comment, comment) } else /*------------------------------------------------------------------*/ /* We've discovered a keyword and its value */ { ++keyword_count; /* validate the keyword and its values */ OdlValidKwd(curr_object, left_part, equals, right_part, message_fname, m_ptr, line_number); /* Add the keyword to the current object */ curr_keyword = OdlPasteKwd(OdlNewKwd(left_part, right_part, comment, line_comment, label_fname, line_number), curr_object); /* we've got a potential multi-line value list if the first character of the value is either an open brace, '{', or an open paren, '(' */ if ((value_list = curr_keyword->is_a_list) == TRUE) { /* validate that the braces and parens are correct */ OdlValidBraces(curr_keyword->value, brace_nesting, paren_nesting, message_fname, m_ptr, value_list_line_number); /* reset the comment text string */ LemmeGo(comment) NewString(comment, 1) } /* End: "if ((strncmp(left_part, ... else ... else ..." */ /*------------------------------------------------------------------*/ } /* End: "if (quoted_value) ... else ... else ..." */ equals_found = FALSE; val_found = FALSE; balanced = FALSE; LemmeGo(text) } /*------------------------------------------------------------------*/ } /* End: "while (fgets(text, ..." */ /* if we're not sitting at the root then not enough END_OBJECTs found */ if (curr_object->parent != NULL) { OdlPrintMessage(message_fname, m_ptr, line_number, "Not enough END_OBJECT statements. Some objects may be incomplete"); } /* hey, we didn't find an end statement! */ if ((! end_found) && (! ignore_missing_end)) { OdlPrintMessage(message_fname, m_ptr, line_number, "END statement is missing"); } /* oops, there was nothing in the label file to parse */ if (line_number == 0) root = OdlFreeTree(root); LemmeGo(comment) } /* End: "if (l_ptr == NULL) ... else ..." */ /* how'd we do? */ if (! suppress_metrics && ! suppress_messages) { OdlPrintLine(message_fname, m_ptr, "\n"); OdlPrintLine(message_fname, m_ptr, " |-------------------------------|\n"); OdlPrintLine(message_fname, m_ptr, " | Parsing Metrics: |\n"); OdlPrintLine(message_fname, m_ptr, " | |\n"); sprintf(msgtext, " | %7d Syntax Messages |\n", odl_message_count); OdlPrintLine(message_fname, m_ptr, msgtext); OdlPrintLine(message_fname, m_ptr, " | |\n"); sprintf(msgtext, " | %7d OBJECT Statements |\n", object_count); OdlPrintLine(message_fname, m_ptr, msgtext); sprintf(msgtext, " | %7d END_OBJECT Statements |\n", end_object_count); OdlPrintLine(message_fname, m_ptr, msgtext); sprintf(msgtext, " | %7d Keywords |\n", keyword_count); OdlPrintLine(message_fname, m_ptr, msgtext); sprintf(msgtext, " | %7d Comments |\n", comment_count); OdlPrintLine(message_fname, m_ptr, msgtext); OdlPrintLine(message_fname, m_ptr, " |-------------------------------|\n\n"); } /* End: "if (! suppress_metrics) ..." */ /* display the object hierarchy */ if (! suppress_hierarchy && ! suppress_messages) { if (label_fname == NULL) sprintf(msgtext, "Object Hierarchy in File: (no file name provided)"); else sprintf(msgtext, "Object Hierarchy in File: %s", label_fname); OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n"); OdlPrintLine(message_fname, m_ptr, msgtext); OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n\n"); OdlPrintHierarchy(root, message_fname, m_ptr); } /* End: "if (suppress_hierarchy) ..." */ /* closing remarks */ if (label_fname == NULL) sprintf(msgtext, "End of Parsing File: (no file name provided)"); else sprintf(msgtext, "End of Parsing File: %s", label_fname); OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n"); OdlPrintLine(message_fname, m_ptr, msgtext); OdlPrintLine(message_fname, m_ptr, "\n--------------------------------------------------------------------------\n\n"); /* if we opened the label file in this routine then close it */ if (label_fptr == NULL) CloseMe(l_ptr) /* if we opened the message file in this routine then close it */ if ((m_ptr != stdout) && (message_fptr == NULL)) CloseMe(m_ptr) LemmeGo(text) return (root); } /* End routine: OdlParseFile */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static short OdlNestingLevel (text, brace_nesting, paren_nesting) char *text; long *brace_nesting; long *paren_nesting; #else static short OdlNestingLevel (char *text, long *brace_nesting, long *paren_nesting) #endif { char *c = {NULL}; for (c=text; *c != '\0'; ++c) { if (*c == '{') ++(*brace_nesting); else if (*c == '}') --(*brace_nesting); else if (*c == '(') ++(*paren_nesting); else if (*c == ')') --(*paren_nesting); } return((*brace_nesting == 0) && (*paren_nesting == 0)); } /* End routine: "OdlNestingLevel" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static short OdlValidBraces (text, brace_nesting, paren_nesting, message_fname, message_fptr, line_number) char *text; long brace_nesting; long paren_nesting; char *message_fname; FILE *message_fptr; long line_number; #else static short OdlValidBraces (char *text, long brace_nesting, long paren_nesting, char *message_fname, FILE *message_fptr, long line_number) #endif { char *c = {NULL}; char *sp = {NULL}; char *nesting_stack = {NULL}; short status = {TRUE}; /* allocate storage for the nesting stack */ NewString(nesting_stack, strlen(text)) /* validate that all braces and parens are correctly nested */ for (c=text,sp=(nesting_stack-1); ((*c != '\0') && (status == TRUE)); ++c) { /* push brace or paren onto the nesting stack */ if ((*c == '{') || (*c == '(')) *(++sp) = *c; else /* nesting is ok so far, pop the nesting stack */ if (((*c == '}') && (*sp == '{')) || ((*c == ')') && (*sp == '('))) --sp; else /* found a right brace that doesn't have a matching left one */ if ((*c == '}') && (*sp != '{')) { status = OdlPrintMessage(message_fname,message_fptr,line_number, "Bad nesting in VALUE LIST. Expected a right parenthesis and found a brace instead."); } else /* found a right paren that doesn't have a matching left one */ if ((*c == ')') && (*sp != '(')) { status = OdlPrintMessage(message_fname,message_fptr,line_number, "Bad nesting in VALUE LIST. Expected a right brace and found a parenthesis instead."); } /* we've reached nesting level zero before reaching the end */ if ((sp < nesting_stack) && (*(c+1) != '\0')) { status = OdlPrintMessage(message_fname,message_fptr,line_number, "VALUE LIST not properly enclosed in braces or parentheses"); } } /* End: "for (c=text,sp=(nesting_stack-1); ..." */ LemmeGo(nesting_stack) if (brace_nesting < 0) { status = OdlPrintMessage(message_fname, message_fptr, line_number, "Too many right braces in VALUE LIST"); } else if (brace_nesting > 0) { status = OdlPrintMessage(message_fname, message_fptr, line_number, "Too many left braces in VALUE LIST"); } if (paren_nesting < 0) { status = OdlPrintMessage(message_fname, message_fptr, line_number, "Too many right parentheses in VALUE LIST"); } else if (paren_nesting > 0) { status = OdlPrintMessage(message_fname, message_fptr, line_number, "Too many left parentheses in VALUE LIST"); } return(status); } /* End routine: "OdlValidBraces" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static short OdlValidElement (text, message_fname, message_fptr, line_number, element_number) char *text; char *message_fname; FILE *message_fptr; long line_number; long element_number; #else static short OdlValidElement (char *text, char *message_fname, FILE *message_fptr, long line_number, long element_number) #endif { char *message = NULL; char element_prompt[TB_MAXLINE + 1]; char *save_units = 0; char *first_blank = {NULL}; char *first_char = {NULL}; char *last_char = {NULL}; char *units_start = {NULL}; char *units_end = {NULL}; char *single_quote = {NULL}; char *double_quote = {NULL}; char *c = {NULL}; int i; short status = {TRUE}; if (element_number <= 0) strcpy(element_prompt, ""); else sprintf(element_prompt, " LIST element %d", element_number); single_quote = (char *) strchr(text+1, (int) '\''); double_quote = (char *) strchr(text+1, (int) '"'); first_blank = (char *) strchr(text+1, (int) ' '); first_char = text; last_char = (char *) LastChar(text); NewString(message, TB_MAXLINE+strlen(text)) /* double quote found in the middle of the value */ if ((double_quote > first_char) && (double_quote < last_char)) { sprintf(message, "Embedded double quote in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } else /* value is double quoted - everything is okay */ if (*first_char == '"') { status = TRUE; } else /* single quote found in the middle of the value */ if ((single_quote > first_char) && (single_quote < last_char)) { sprintf(message, "Embedded single quote in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } else /* value is single quoted - fine if not just a quote */ if ((*first_char == '\'') && (*last_char == '\'')) { if (first_char == last_char) { sprintf(message, "Unpaired single quote in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } } else /* value is missing a closing single quote */ if ((*first_char == '\'') && (*last_char != '\'')) { sprintf(message, "Unpaired single quote in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } else /* value is missing an opening single quote */ if ((*first_char != '\'') && (*last_char == '\'')) { sprintf(message, "Unpaired single quote in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } else /* value is missing an opening double quote */ if ((*first_char != '"') && (*last_char == '"')) { sprintf(message, "Unpaired double quote in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } else /* current value list element is just a double quote */ if ((element_number > 0) && (first_char == (last_char-1)) && (*first_char == '"')) { sprintf(message, "Unpaired double quote in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } else /* current value list element is missing a closing double quote */ if ((element_number > 0) && (*first_char == '"') && (*(last_char-1) != '"')) { sprintf(message, "Unpaired double quote in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } else /* value is unquoted */ if ((*first_char != '\'') && (*last_char != '\'')) { /* check the value only if it isn't N/A */ if ((strcmp(first_char, "n/a") != 0) && (strcmp(first_char, "N/A") != 0)) { /* we can't have multiple underscores in an unquoted value */ if (strstr(first_char, "__") != NULL) { sprintf(message, "Multiple underscores in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } /* an unquoted value cannot begin with an underscore */ if (*first_char == '_') { sprintf(message, "First character is an underscore in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } /* an unquoted value cannot end with an underscore */ if (*last_char == '_') { sprintf(message, "Last character is an underscore in VALUE%s", element_prompt); status = OdlPrintMessage(message_fname,message_fptr, line_number, message); } /* the value may have a units expression */ if ((units_start = (char *) strchr(text, (int) '<')) != NULL) { CopyString(save_units, units_start) *units_start = '\0'; StripTrailing(text, ' ') } if (OdlDataType(text) == ODL_UNKNOWN) { sprintf(message, "Unable to determine the data type of VALUE%s: \"%s\"", element_prompt, first_char); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } /* validate the units expression, if any */ if (units_start != NULL) { /* only one '<' char allowed in a units expression */ if (strchr(units_start+1, (int) '<') != NULL) { sprintf(message, "Embedded '<' character found in the UNITS expression: \"<%s\", for VALUE%s: \"%s\"", units_start+1, element_prompt, first_char); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } /* find the closing char for the units expression */ units_end = (char *) strchr(units_start+1, (int) '>'); /* missing the closing '>' char in the units expression */ if (units_end == NULL) { sprintf(message, "Missing the closing '>' character in the UNITS expression: \"<%s\", for VALUE%s: \"%s\"", units_start+1, element_prompt, first_char); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } else /* characters found after the closing '>' in the units exp */ if (units_end != last_char) { sprintf(message, "Extraneous characters found after the closing '>' character in the UNITS expression: \"<%s\", for VALUE%s: \"%s\"", units_start+1, element_prompt, first_char); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } /* restore the value */ strcat(text, " "); strcat(text, save_units); LemmeGo(save_units) } /* End: "if (units_start != NULL) ..." */ } /* End: "if ((strcmp(first_char, "n/a") != 0) && ..." */ } /* End: "if ((double_quote > ... else ... else ..." */ LemmeGo(message) return(status); } /* End routine: "OdlValidElement" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static short OdlValidEndObjDesc (curr_object, equals, right_part, message_fname, message_fptr, line_number) OBJDESC *curr_object; char *equals; char *right_part; char *message_fname; FILE *message_fptr; long line_number; #else static short OdlValidEndObjDesc (OBJDESC *curr_object, char *equals, char *right_part, char *message_fname, FILE *message_fptr, long line_number) #endif { short status = {TRUE}; if (curr_object->parent == NULL) { status = OdlPrintMessage(message_fname, message_fptr, line_number, "Extra END_OBJECT encountered"); } if (*equals != '\0') { if (*right_part != '\0') { if (strcmp(curr_object->class, right_part) != 0) { status = OdlPrintMessage(message_fname, message_fptr, line_number, "OBJECT and END_OBJECT class identifiers do not match"); } } status = OdlValidIdentifier(right_part, "END_OBJECT class", message_fname, message_fptr,line_number) && status; } /* End: "if (*equals != '\0') ..." */ return(status); } /* End routine: "OdlValidEndObjDesc" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static short OdlValidIdentifier (id_name, id_type, message_fname, message_fptr, line_number) char *id_name; char *id_type; char *message_fname; FILE *message_fptr; long line_number; #else static short OdlValidIdentifier (char *id_name, char *id_type, char *message_fname, FILE *message_fptr, long line_number) #endif { char *message = NULL; char *c = {NULL}; int i; short status = {TRUE}; NewString(message, TB_MAXLINE+strlen(id_name)+strlen(id_type)) if (id_name == NULL) { sprintf(message, "%s identifier is missing", id_type); status = OdlPrintMessage(message_fname, message_fptr, line_number,message); } else { StripUnprintables(id_name) if (*id_name == '\0') { sprintf(message, "%s identifier is missing", id_type); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } else { if (! isalpha(*id_name)) { sprintf(message, "%s identifier: \"%s\" does not begin with a letter", id_type, id_name); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } for (c=id_name,i=0; *c != '\0'; ++c) { if ((*c != '_') && (! isalnum(*c))) ++i; } if (i > 0) { sprintf(message, "%s identifier: \"%s\" contains %d embedded non-alphanumeric or \"_\" character", id_type, id_name, i); if (i > 1) strcat(message, "s"); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } } /* End: "if (*id_name == '\0') ... else ..." */ } /* End: "if (id_name == NULL) ... else ..." */ LemmeGo(message) return(status); } /* End routine: "OdlValidIdentifier" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static short OdlValidKwd (curr_object, left_part, equals, right_part, message_fname, message_fptr, line_number) OBJDESC *curr_object; char *left_part; char *equals; char *right_part; char *message_fname; FILE *message_fptr; long line_number; #else static short OdlValidKwd (OBJDESC *curr_object, char *left_part, char *equals, char *right_part, char *message_fname, FILE *message_fptr, long line_number) #endif { KEYWORD *keyword = {NULL}; char *key = {NULL}; char *message = NULL; char c; short status = {TRUE}; short sfdu_only = {FALSE}; short found_keyword = {FALSE}; NewString(message, TB_MAXLINE+strlen(left_part)+strlen(right_part)) if (*left_part == '=') { *left_part = '\0'; status = OdlPrintMessage(message_fname, message_fptr, line_number, "KEYWORD identifier is missing"); } else { if (*equals == '\0') { sfdu_only = ((strncmp(left_part, "NJPL", 4) == 0) || (strncmp(left_part, "CCSD", 4) == 0)); if (! sfdu_only) { sprintf(message, "Missing equals sign after KEYWORD identifier: \"%s\"", left_part); status = OdlPrintMessage(message_fname, message_fptr, line_number, message); } } else { *equals = '\0'; StripTrailing(left_part, ' ') } /* ignore the first character if the keyword is a pointer */ key = (*left_part != '^') ? left_part : left_part + 1; status = OdlValidIdentifier(key, "KEYWORD", message_fname, message_fptr, line_number) && status; for (keyword=curr_object->first_keyword; ((keyword != NULL) && (! found_keyword)); keyword=keyword->right_sibling) { if (keyword->name != NULL) found_keyword = (strcmp(keyword->name, left_part) == 0); } if (found_keyword) { sprintf(message, "Duplicate KEYWORD identifier: \"%s\"", left_part); status = OdlPrintMessage(message_fname, message_fptr, line_number,message); } } /* End: "if (*left_part == '=') ... else ..." */ if (*right_part != '\0') { /* what sort of value do we have? */ if ((*right_part != '{') && (*right_part != '(')) { /* we have a single element */ status = OdlValidElement(right_part, message_fname, message_fptr, line_number, 0) && status; } else { /* we have a value list */ status = OdlValidValueList(right_part, message_fname, message_fptr, line_number) && status; } } else if (! sfdu_only) { sprintf(message, "KEYWORD identifier: \"%s\" is missing a VALUE", left_part); status = OdlPrintMessage(message_fname, message_fptr, line_number,message); } LemmeGo(message) return(status); } /* End routine: "OdlValidKwd" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static short OdlValidObjDesc (curr_object, equals, right_part, message_fname, message_fptr, line_number) OBJDESC *curr_object; char *equals; char *right_part; char *message_fname; FILE *message_fptr; long line_number; #else static short OdlValidObjDesc (OBJDESC *curr_object, char *equals, char *right_part, char *message_fname, FILE *message_fptr, long line_number) #endif { short status = {TRUE}; if (*equals == '\0') { status = OdlPrintMessage(message_fname, message_fptr, line_number, "Missing equals sign after OBJECT statement"); } StripTrailing(right_part, ' ') status = OdlValidIdentifier(right_part, "OBJECT class", message_fname, message_fptr,line_number) && status; return(status); } /* End routine: "OdlValidObjDesc" */ /*******************/ /* Local Routine */ /*******************/ #ifdef _NO_PROTO static short OdlValidValueList (text, message_fname, message_fptr, line_number) char *text; char *message_fname; FILE *message_fptr; long line_number; #else static short OdlValidValueList (char *text, char *message_fname, FILE *message_fptr, long line_number) #endif { char *first_char = {NULL}; char *last_char = {NULL}; char save_c; int i; short status = {TRUE}; for (i=1,first_char=OdlValueStart(text); *first_char != '\0'; ++i) { /* find the end of the current element */ last_char = OdlValueEnd(first_char); /* save the next character and terminate the string */ save_c = *(++last_char); *last_char = '\0'; /* validate the current element */ OdlValidElement(first_char,message_fname,message_fptr,line_number,i); /* restore the character that was overwritten by the terminator */ *last_char = save_c; /* find the start of the next element */ first_char = OdlValueStart(last_char); } /* End: "for (i=1, ..." */ return(status); } /* End routine: "OdlValidValueList" */ /*========================================================================*/ /* */ /* Miscellaneous routines */ /* */ /*========================================================================*/ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlWildCardCompare */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine compares two text strings, one of which may have */ /* wildcard characters in it ('*'). */ /* */ /************************************************************************/ #ifdef _NO_PROTO unsigned short OdlWildCardCompare (wildcard_text, plain_text) char *wildcard_text; char *plain_text; #else unsigned short OdlWildCardCompare (char *wildcard_text, char *plain_text) #endif { char *c = {NULL}; char *substr = {NULL}; char *tmp_str = {NULL}; char *tmp_str2 = {NULL}; char *text_start = {NULL}; char save_it; unsigned long len; unsigned short allrightythen = {FALSE}; /* see if we have anything to compare */ if ((wildcard_text != NULL) && (plain_text != NULL)) { /* all righty then, let's initialize some local variables */ allrightythen = TRUE; /* copy the wildcard text */ CopyString(tmp_str, wildcard_text) /* strip off leading and trailing quotes */ save_it = *tmp_str; if ((save_it == '\'') || (save_it == '"')) { StripLeading(tmp_str, save_it) StripTrailing(tmp_str, save_it) StripLeading(tmp_str, ' ') StripTrailing(tmp_str, ' ') } /* copy the plain text */ CopyString(tmp_str2, plain_text) /* strip off leading and trailing quotes */ save_it = *tmp_str2; if ((save_it == '\'') || (save_it == '"')) { StripLeading(tmp_str2, save_it) StripTrailing(tmp_str2, save_it) StripLeading(tmp_str2, ' ') StripTrailing(tmp_str2, ' ') } substr = tmp_str; text_start = tmp_str2; if (strchr(substr, '*') == NULL) allrightythen = (strcmp(text_start, substr) == 0); else { /* we're going to break out the chunks of text between the */ /* wildcard caracters and try to find them one-by-one in */ /* the plain text string. */ do { /* locate the start of next substring */ for ( ; *substr == '*'; ++substr) ; if (*substr == '\0') break; /* locate the end of the substring and save that address */ for (c=substr; ((*c != '*') && (*c != '\0')); ++c) ; save_it = *c; *c = '\0'; /* look for the substring in the un-wildcarded text */ if ((c = (char *)strstr(text_start, substr)) == NULL) { allrightythen = FALSE; break; } /* prepare for the next search */ len = strlen(substr); substr += len; *substr = save_it; text_start = c + len; if ((*substr == '\0') && (*text_start != '\0')) { allrightythen = FALSE; break; } } while(TRUE); } /* End: "if (strchr(substr, '*') == NULL) ... else ..." */ LemmeGo(tmp_str) LemmeGo(tmp_str2) } /* End: "if ((wildcard_text != NULL) && ..." */ return(allrightythen); } /* End: "OdlWildCardCompare" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlTraverseTree */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the next object in an ODL tree, stopping */ /* when it has traversed the entire tree as defined by the */ /* root_level parameter. */ /* */ /************************************************************************/ #ifdef _NO_PROTO OBJDESC *OdlTraverseTree (curr_object, root_level) OBJDESC *curr_object; unsigned long root_level; #else OBJDESC *OdlTraverseTree (OBJDESC *curr_object, unsigned long root_level) #endif { OBJDESC *obj = {NULL}; OBJDESC *next_object = {NULL}; if (curr_object != NULL) { /* start search with current object's children */ if (curr_object->first_child != NULL) next_object = curr_object->first_child; else /* start search with current object's right sibling */ if (curr_object->right_sibling != NULL) next_object = curr_object->right_sibling; else /* move up parent list until we find one with a right sibling */ { for (next_object=NULL,obj=curr_object->parent; (obj != NULL); obj=obj->parent) { if (obj->level <= root_level) break; else if (obj->right_sibling != NULL) { next_object = obj->right_sibling; break; } } } /* End: "if (curr_object->first_child ... else ..." */ } /* End: "if (curr_object != NULL) ..." */ return(next_object); } /* End routine: "OdlTraverseTree" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlFirstWord */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a pointer to the first word in a string */ /* of text. A word is anything that begins with a printable */ /* ASCII character. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlFirstWord(text) char *text; #else char *OdlFirstWord(char *text) #endif { char *c = {NULL}; for (c=text; ((c != NULL) && ((*c <= ' ') || (*c > '~')) && (*c != '\0')); ++c) ; return(c); } /* End routine: "OdlFirstWord" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlNextWord */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the next word in a string of text. It */ /* locates the end of the current word and skips over whitespace */ /* to find the start of the next. A word is anything that begins */ /* with a printable ASCII character. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlNextWord(text) char *text; #else char *OdlNextWord( char *text) #endif { char *c = {NULL}; for (c=text; ((c != NULL) && (*c > ' ') && (*c <= '~') && (*c != '\0')); ++c) ; return(OdlFirstWord(c)); } /* End routine: "OdlNextWord" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlValueStart */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the start of a value within a set or */ /* sequence. A value is anything that doesn't begin with a brace, */ /* comma, paren, or blank. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlValueStart(text) char *text; #else char *OdlValueStart(char *text) #endif { /* find a character that is not a brace, paren, comma, or blank */ return(text + strspn(text, "{}(), \n")); } /* End routine: "OdlValueStart" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlValueEnd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine finds the end of a value within a set or sequence. */ /* A value is anything that doesn't begin with a brace, comma, */ /* paren, or blank. It finds the end by locating a comma, paren, */ /* or brace, and backing up over trailing whitespace. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlValueEnd(text) char *text; #else char *OdlValueEnd( char *text) #endif { char *c = {NULL}; /* find a character that is a brace, paren, or comma */ c = strpbrk(text, "{}(),"); /* backup over any trailing blanks */ for (--c; ((c > text) && ((*c == ' ') || (*c == '\0'))); --c) ; return(c); } /* End routine: "OdlValueEnd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlValueRowStart */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the start of a set or sequence within a */ /* set or sequence. A set begins with a brace and a sequence */ /* begins with a paren. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlValueRowStart(text) char *text; #else char *OdlValueRowStart( char *text) #endif { /* find a character that is not a brace or paren */ return(text + strspn(text, "{}()\n")); } /* End routine: "OdlValueRowStart" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlValueRowEnd */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine locates the end of a set or sequence within a */ /* set or sequence. A set begins with a brace and a sequence */ /* begins with a paren. It finds a closing brace or paren and */ /* backs up over any whitespace. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlValueRowEnd(text) char *text; #else char *OdlValueRowEnd( char *text) #endif { char *c = {NULL}; /* find a character that is a brace or paren */ c = strpbrk(text, "{}()\n"); /* backup over any trailing blanks or commas */ for (--c; ((c > text) && ((*c == ' ') || (*c == ',') || (*c == '\0'))); --c) ; return(c); } /* End routine: "OdlValueRowEnd" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlDataType */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine determines the ODL data type of a text string. */ /* */ /************************************************************************/ #ifdef _NO_PROTO unsigned short OdlDataType (text) char *text; #else unsigned short OdlDataType (char *text) #endif { char *c = {NULL}; char *u = {NULL}; char *tempstr = {NULL}; char *last_pound = {NULL}; int base; unsigned long decimal_count = {0}; unsigned long hyphen_count = {0}; unsigned long colon_count = {0}; unsigned long t_count = {0}; unsigned short has_sign = {FALSE}; unsigned short type = {ODL_UNKNOWN}; unsigned short exponent_type = {ODL_UNKNOWN}; static char *valid_chars[17] = { "", /* base 0 */ "0", /* base 1 */ "01", /* base 2 */ "012", /* base 3 */ "0123", /* base 4 */ "01234", /* base 5 */ "012345", /* base 6 */ "0123456", /* base 7 */ "01234567", /* base 8 */ "012345678", /* base 9 */ "0123456789", /* base 10 */ "0123456789A", /* base 11 */ "0123456789AB", /* base 12 */ "0123456789ABC", /* base 13 */ "0123456789ABCD", /* base 14 */ "0123456789ABCDE", /* base 15 */ "0123456789ABCDEF"}; /* base 16 */ if (text != NULL) { /* make a copy of the string */ CopyString(tempstr, text) /* remove any units */ if ((u = (char *)strchr(tempstr, '<')) != NULL) *u = '\0'; /* clean up blanks and convert to upper case */ StripLeading(tempstr, ' ') StripTrailing(tempstr, ' ') UpperCase(tempstr) c = tempstr; type = ODL_SYMBOL; /* See if we have a double quoted text value */ if (*c == '"') type = ODL_TEXT; else /* See if we have a single quoted text value */ if (*c == '\'') type = ODL_SYMBOL; else /* See if we have a sequence of values */ if (*c == '{') type = ODL_SEQUENCE; else /* See if we have a set of values */ if (*c == '(') type = ODL_SET; else /* See if we have any embedded blanks */ if (strchr(c, ' ') != NULL) type = ODL_UNKNOWN; else /* See if we have an integer, real, date, or date-time value */ { /* we're going to check each character */ for ( ; *c != '\0'; ++c) { /* may have a number */ if (isdigit(*c)) { if (c == tempstr) type = ODL_INTEGER; else if (has_sign && (c == (tempstr + 1))) type = ODL_INTEGER; } else /* we may have a real number or a date-time */ if (*c == '.') { /* we may have a real number */ if (type == ODL_INTEGER) type = ODL_REAL; else /* date-times can only have one decimal point */ if (type == ODL_DATE_TIME) { if ((++decimal_count) > 1) type = ODL_UNKNOWN; } else /* we may have a real number */ if (c == tempstr) type = ODL_REAL; else /* we may have a signed real number */ if (has_sign && (c == (tempstr + 1))) type = ODL_REAL; else type = ODL_UNKNOWN; } else /* we may have a real number in scientific notation */ if (*c == 'E') { /* only valid if we thought we had an int or real */ if ((type == ODL_INTEGER) || (type == ODL_REAL)) { /* check out the exponent */ exponent_type = (unsigned short) OdlDataType((c+1)); /* we have a real number only if the exponent */ /* is real or int */ if ((exponent_type == ODL_REAL) || (exponent_type == ODL_INTEGER)) type = ODL_REAL; else type = ODL_UNKNOWN; break; } else if (type != ODL_SYMBOL) type = ODL_UNKNOWN; } else /* we may have a signed number */ if (*c == '+') { /* this had better be the first character */ if (c != tempstr) type = ODL_UNKNOWN; else has_sign = TRUE; } else /* we may have a date or a signed number */ if (*c == '-') { /* this had better be the first character */ if (c == tempstr) has_sign = TRUE; else /* a date can have at most two hyphens */ if ((++hyphen_count) > 2) type = ODL_UNKNOWN; else /* we thought we had an integer */ if (type == ODL_INTEGER) type = ODL_DATE; else /* if it wasn't an int and it wasn't a date ... */ if (type != ODL_DATE) type = ODL_UNKNOWN; } else /* we may have a date-time */ if (*c == 'T') { /* we thought we had a date */ if (type == ODL_DATE) type = ODL_DATE_TIME; else /* a date-time may only have one 'T' */ if (type == ODL_DATE_TIME) { if ((++t_count) > 1) type = ODL_UNKNOWN; } else /* must be a symbol */ if (type != ODL_SYMBOL) type = ODL_UNKNOWN; } else /* we may have a date-time */ if (*c == 'Z') { /* only a date time may contain a 'Z' */ if (type == ODL_DATE_TIME) { /* it had better be the last char in the string */ if (*(c + 1) != '\0') type = ODL_UNKNOWN; } else if (type != ODL_SYMBOL) type = ODL_UNKNOWN; } else /* we may have a date-time */ if (*c == ':') { /* only a date-time may contain colons */ if (type != ODL_DATE_TIME) type = ODL_UNKNOWN; else /* there can't be more than two of them */ if ((++colon_count) > 2) type = ODL_UNKNOWN; else /* characters on either side must be digits */ if ((! isdigit(*(c-1))) || (! isdigit(*(c+1)))) type = ODL_UNKNOWN; else /* decimal points can't occur before the last colon */ if (decimal_count > 0) type = ODL_UNKNOWN; } else /* we may have a non-decimal integer */ if (*c == '#') { /* we didn't think it WAS an integer */ if (type != ODL_INTEGER) type = ODL_UNKNOWN; else /* the base can't be signed */ if (has_sign) type = ODL_UNKNOWN; else /* missing the closing '#' character */ if ((last_pound = (char *)strchr(c+1, '#')) == NULL) type = ODL_UNKNOWN; else /* closing '#' char is not at the end */ if (*(last_pound + 1) != '\0') type = ODL_UNKNOWN; else { /* looks good so far, but we have to make sure */ /* stuff between the '#' characters is valid */ /* with the specified base */ /* isolate the base */ *c = '\0'; base = atoi(tempstr); /* ignore the integer's sign */ ++c; if ((*c == '+') || (*c == '-')) ++c; /* isolate the number part */ *last_pound = '\0'; /* valid bases are 2 through 16, inclusive */ if ((base < 2) || (base > 16)) type = ODL_UNKNOWN; else /* look for invalid digits for the specified base */ if (c[strspn(c, valid_chars[base])] != '\0') type = ODL_UNKNOWN; } if (type != ODL_UNKNOWN) { type = ODL_INTEGER; break; } } else /* we may have an unquoted symbol */ if (isalpha(*c) || (*c == '_')) { if (type != ODL_SYMBOL) type = ODL_UNKNOWN; } else /* we havn't got a clue */ type = ODL_UNKNOWN; if (type == ODL_UNKNOWN) break; } /* End: "for ( ; ..." */ if (has_sign && (type != ODL_INTEGER) && (type != ODL_REAL)) type = ODL_UNKNOWN; } /* End: "if (*c == '(') ... else ..." */ LemmeGo(tempstr) } /* End: "if (text != NULL) ..." */ return(type); } /* End: "OdlDataType" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlTypeString */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine determines the ODL data type of a text string. */ /* */ /************************************************************************/ #ifdef _NO_PROTO char *OdlTypeString (type, type_string) unsigned short type; char *type_string; #else char *OdlTypeString (unsigned short type, char *type_string) #endif { static char local_type_string [TB_MAXLINE]; switch (type) { case ODL_INTEGER : strcpy(local_type_string, "INTEGER"); break; case ODL_REAL : strcpy(local_type_string, "REAL"); break; case ODL_SYMBOL : strcpy(local_type_string, "SYMBOL"); break; case ODL_TEXT : strcpy(local_type_string, "TEXT"); break; case ODL_DATE : strcpy(local_type_string, "DATE"); break; case ODL_DATE_TIME : strcpy(local_type_string, "DATE-TIME"); break; case ODL_SEQUENCE : strcpy(local_type_string, "SEQUENCE"); break; case ODL_SET : strcpy(local_type_string, "SET"); break; default : strcpy(local_type_string, "UNKNOWN"); break; } /* End: "switch (type) ..." */ if (type_string != NULL) strcpy(type_string, local_type_string); return(local_type_string); } /* End: "OdlTypeString" */ /************************************************************************/ /* */ /* Component: */ /* */ /* OdlTempFname */ /* */ /* Author: */ /* */ /* David P. Bernath (Jet Propulsion Laboratory) */ /* */ /* Version: */ /* */ /* 1.0 March 31, 1994 */ /* */ /* Change History: */ /* */ /* 03-31-94 Original code */ /* */ /*----------------------------------------------------------------------*/ /* */ /* Description: */ /* */ /* This routine returns a unique file name, depending on the */ /* system on which the code was compiled. */ /* */ /************************************************************************/ char *OdlTempFname() { FILE *fptr = {NULL}; char *fname = {NULL}; char temp_str [TB_MAXPATH + TB_MAXFNAME]; char base_name [TB_MAXPATH + TB_MAXFNAME]; strcpy(base_name, "tmp.tmp"); #ifdef SUN_UNIX tmpnam(temp_str); strcpy( base_name, temp_str); /* Bug fix 11/2/94 SM */ /* Was: sprintf(base_name, "~/%s.tmp", */ /* temp_str); */ #endif #if (defined( VAX) || defined( ALPHA_VMS)) tmpnam(temp_str); sprintf(base_name, "sys$login:%s.tmp", temp_str); #endif #ifdef MAC_THINK tmpnam(temp_str); sprintf(base_name, "%s.tmp", temp_str); #endif #ifdef MSDOS { time_t t; t = (time_t) time(NULL); sprintf(base_name, "C:\\%ld", t); base_name[8] = '\0'; /* EOS; */ strcat(base_name, ".tmp"); } #endif CopyString(fname, base_name) if ((fptr = (FILE *) fopen(fname, "w")) == NULL) LemmeGo(fname) else CloseMe(fptr) return(fname); } /* End: "OdlTempFname" */ short CheckBalance(text) char *text; { long quote_nesting = 0; long brace_nesting = 0; long paren_nesting = 0; char *c = {NULL}; char *c1 = {NULL}; c1 = (char *) strchr(text, '='); c = OdlFirstWord(c1 + 1); if ((*c == '(') || (*c == '{')) OdlNestingLevel(c,&brace_nesting,&paren_nesting); else if (*c == '"') { for (; *c != '\0'; ++c) { if (*c == '"') { if (quote_nesting == 0) quote_nesting = 1; else quote_nesting = 0; } } } return((brace_nesting + paren_nesting + quote_nesting) == 0); } /*========================================================================*/ /* */ /* End of lablib 3.0 stuff */ /* */ /*========================================================================*/ int ListToArray(TB_STRING_LIST *list, char ***array) { TB_STRING_LIST *t, *t2; int count=0; int i = 0; for (t = list ; t != NULL ; t=t->next) { count++; } *array = calloc(count, sizeof(char *)); t = list; while(t != NULL) { (*array)[i++] = t->text; t2 = t->next; LemmeGo(t); t = t2; } return(i); } #if 0 /* * helper functions * */ char * basename(const char *name) { const char *base = name; while (*name) { if (*name++ == '/') { base = name; } } return (char *) base; } #endif #if 0 char * dirname(char *path) { char *newpath; char *slash; int length; /* Length of result, not including NUL. */ slash = strrchr(path, '/'); if (slash == 0) { /* File is in the current directory. */ path = "."; length = 1; } else { /* Remove any trailing slashes from the result. */ while (slash > path && *slash == '/') --slash; length = slash - path + 1; } newpath = (char *) malloc(length + 1); if (newpath == 0) return 0; strncpy(newpath, path, length); newpath[length] = 0; return newpath; } #endif char *uppercase(char *s) { char *p; for (p = s ; p && *p ; p++) { if (islower(*p)) *p = *p - 'a' + 'A'; } return(s); } char *lowercase(char *s) { char *p; for (p = s ; p && *p ; p++) { if (isupper(*p)) *p = *p - 'A' + 'a'; } return(s); } char * find_file(char *fname) { if (!access(fname, R_OK)) return(fname); /** ** try some permutations **/ { char buf[256], buf2[256], buf3[256], *p; /** ** original path, trailing component lowercased **/ strcpy(buf, fname); lowercase(basename(buf)); if (!access(buf, R_OK)) return(strdup(buf)); /** ** original path, trailing component uppercased **/ uppercase(basename(buf)); if (!access(buf, R_OK)) return(strdup(buf)); /** ** whole path lowercased **/ strcpy(buf, fname); lowercase(buf); if (!access(buf, R_OK)) return(strdup(buf)); /** ** whole path uppercased **/ uppercase(buf); if (!access(buf, R_OK)) return(strdup(buf)); /** ** One last ditch attempt: twiddle case on each piece **/ strcpy(buf, fname); buf2[0] = 0; for (p = strtok(buf, "/") ; p != NULL ; p = strtok(NULL, "/")) { if (buf2[0] != 0) { sprintf(buf3, "%s/%s", buf2, p); } else { sprintf(buf3, "%s", p); } if (!access(buf3, F_OK)) { strcpy(buf2, buf3); continue; } sprintf(buf3, "%s/%s", buf2, uppercase(p)); if (!access(buf3, F_OK)) { strcpy(buf2, buf3); continue; } sprintf(buf3, "%s/%s", buf2, lowercase(p)); if (!access(buf3, F_OK)) { strcpy(buf2, buf3); continue; } fname = strdup(buf3); break; } } return(fname); }